Rust浮点类型

368 阅读4分钟

浮点类型的场景

表示范围和精度的需求: 在科学、工程、金融等领域,常常需要处理非常大或非常小的数值,以及需要精确到小数点后多位的计算。例如,在处理物理常数、货币汇率或统计数据时。浮点数能够提供广泛的数值范围和可接受的精度。

模拟实数运算: 实际世界中的许多量都是连续的,如时间、速度、温度等,需要通过浮点数在计算机中得以模拟和处理。

资源优化: 相较于更精确但更复杂的数值表示方法(如任意精度算术),浮点数提供了一种在精度和存储/计算资源之间取得平衡的方法。它允许在有限的存储空间内表示极广范围的数值。

标准化: 浮点数的处理在 IEEE (电气和电子工程师协会) 754标准下进行了标准化,这提供了一种跨不同计算机硬件和编程语言共通的数据表示和算术处理方式。

Rust 提供了 IEEE 单精度浮点类型和 IEEE 双精度浮点类型。这些类 型包括正无穷大和负无穷大、不同的正零值和负零值,以及非数值。

类型精度范围
f32IEEE 单精度(至少 6 位小数)大约 -3.4 × 10的38次方 至 +3.4 × 10的38次方
f64IEEE 双精度(至少 15 位小数)大约 -1.8 × 10的308次方 至 +1.8 ×10的308次方

Rust 的 f32 和 f64 分别对应于 C 和 C++(在支持 IEEE 浮点的 实现中)以及 Java(始终使用 IEEE 浮点)中的 float 类型和 double 类型。

图片

浮点字面量的一般化形式

浮点字面量

浮点数中整数部分之后的每个部分都是可选的,但必须至少存在小数部分、指数或类型后缀这三者中的一个,以将其与整型字面量区分开来。小数部分可以仅由一个单独的小数点组成,因此 5. 也是有效的浮点常量。

如果浮点字面量缺少类型后缀,那么 Rust 就会检查上下文以查看值的使用方式,这与整型字面量非常相似。如果它最终发现这两种浮点 类型都适合,就会默认选择 f64。

为了便于类型推断,Rust 会将整型字面量和浮点字面量视为不同的大类:它永远不会把整型字面量推断为浮点类型,反之亦然。

浮点字面量的例子

图片

f32 类型和 f64 类型具有 IEEE 要求的一些特殊值的关联常量,比如 INFINITY(无穷大)、NEG_INFINITY(负无穷大)、NAN(非 数值)以及 MIN(最小有限值)和 MAX(最大有限值):

assert!((-1. / f32::INFINITY).is_sign_negative());
assert_eq!(-f32::MIN, f32::MAX);

f32 类型和 f64 类型提供了完备的数学计算方法,比如 2f64.sqrt() 就是 2 的双精度平方根。下面是一些例子:

assert_eq!(5f32.sqrt() * 5f32.sqrt(), 5.); // 按IEEE的规定,它精确等5.0
assert_eq!((-1.01f64).floor(), -2.0);

再次提醒,方法调用的优先级高于前缀运算符,因此在对负值进行方 法调用时,请务必正确地加上圆括号。 std::f32::consts 模块和 std::f64::consts 模块提供了各种常用的数学常量,比如 E、PI 和 2 的平方根。 在搜索文档时,请记住这两种类型本身都有名为“f32(原始类型)”和“f64(原始类型)”的页面,以及每种类型的单独模块 std::f32 和 std::f64。 与整数一样,通常不必在实际代码中写出浮点字面量的类型后缀,但如果你想这么做,那么将类型放在字面量或函数上就可以:

println!("{}", (2.0_f64).sqrt());
println!("{}", f64::sqrt(2.0));

与 C 和 C++ 不同,Rust 几乎不会执行任何隐式的数值转换。如果函数需要 f64 参数,则传入 i32 型参数是错误的。事实上,Rust 甚 至不会隐式地将 i16 值转换为 i32 值,虽然每个 i16 值都必然在i32 范围内。不过,你随时可以用 as 运算符写出显式转换:i as f64 或 x as i32。 缺少隐式转换有时会让 Rust 表达式比类似的 C 或 C++ 代码更冗长。然而,隐式整数转换有着导致错误和安全漏洞的大量“前科”, 特别是在用这种整数表示内存中某些内容的大小时,很可能发生意外溢出。根据以往的经验,Rust 这种要求明确写出数值类型转换的行为,会提醒我们注意到一些可能错过的问题。