Ziglings 笔记 60: 浮点数的奥秘

浩瀚的数字宇宙

在 Ziglings 的第 60 个练习中,我们离开了精确的整数岛屿,驶向了浩瀚的浮点数海洋。

如果你需要表示原子的大小 ($10^{-10}$) 或者宇宙的直径 ($10^{26}$),整数就无能为力了。这时候我们需要使用 Floating Point (浮点数)

挑战:航天飞机的重量

我们需要计算航天飞机起飞时的公吨数。 已知:

  • 重量:4,480,000 磅。
  • 换算:1 磅 = 0.453592 千克。
  • 目标:输出整数公吨 (1 公吨 = 1000 千克)。

解决方案

这是使用科学计数法和格式化输出的代码:

const print = @import("std").debug.print;

pub fn main() void {
    // 1. 使用科学计数法
    // 4480e3 等同于 4480000.0
    // Zig 编译器会自动处理 float 字面量之间的乘法
    const shuttle_weight: f32 = 0.453592 * 4480e3;

    // 2. 格式化输出
    // 这里的计算:shuttle_weight (kg) / 1e3 (1000.0) = metric tons
    // 格式化 {d:.0}:
    //    d: 十进制显示
    //   .0: 精度为 0 (不显示小数部分)
    print("Shuttle liftoff weight: {d:.0} metric tons\n", .{shuttle_weight / 1e3});
}

核心知识点总结

1. 浮点字面量

在 Zig 中,任何包含小数点 . 或指数 e 的数字都会被推导为 comptime_float

  • 4480000comptime_int
  • 4480e3comptime_float。 虽然 Zig 允许我们将整数字面量赋值给浮点变量(例如 const f: f32 = 100;),但在混合运算时,显式使用浮点格式通常更清晰。

2. 精度控制

格式化字符串 {d:.0} 是处理输出显示的好帮手。

  • {d:.2} -> 保留两位小数 (3.14)
  • {d:.5} -> 保留五位小数 (3.14159) 这只是显示上的舍入,内存中的实际值并没有改变。

3. IEEE-754 细节

练习中的注释展示了 f16 在内存中的二进制结构(符号位、指数位、尾数位)。虽然日常编程不需要手动拼凑这些位,但了解“浮点数是对实数的近似”这一事实至关重要。这意味着 0.1 + 0.2 在计算机中可能并不严格等于 0.3


后续预告:我们已经学习了基本的数值类型。现在,我们要从单个循环跳出来,进入多重循环的世界。下一篇,我们将学习 Labelled Loops(带标签的循环),看看如何优雅地从嵌套循环中跳出。