int vs float:数字是怎么存的
int(整数)和 float(浮点数)是编程语言表示一个数字的两种方式。这个选择在你的代码碰到真实数据时立刻会感觉到后果。
int 是精确可数的:42 就是 42,没有舍入、没有意外。float 是近似的、连续的:IEEE 754 双精度下 0.1 + 0.2 等于 0.30000000000000004,谁第一次遇到都会惊讶。
精确范围
int 是有限的。大多数现代系统中,int32 能存 2^32 个不同的值(−2,147,483,648 到 2,147,483,647)。int64 能存 2^64。超过这些,类型本身就无法表示这个数了。
float 几乎是连续的。IEEE 754 float64(C 系语言里的 “double”)能表示大约 10^−308 到 10^308 的数,约 15-17 位有效十进制数字。代价:该范围内的很多值无法精确表示,很多值(比如 0.1)会被舍入。
为什么 0.1 + 0.2 ≠ 0.3
在二进制浮点中,0.1 不是干净的分数。正如十进制的 1/3 是 0.3333…,二进制的 1/10 是 0.000110011001100… 循环。float 必须舍入到有限的位数,实际存进去的值略偏。
两个舍入后的数相加,舍入误差会累积。0.1 + 0.2 比 0.3 略大一点,float 就打印出 0.30000000000000004。
这不是 bug,是 IEEE 754 在正常工作。bug 是把 float 用在了本该精确的事情上。
怎么选
int 用于:
- 计数(行数、索引、长度)
- 以最小单位存钱(分、聪、wei——永远用整数最小单位)
- 处理 ID、按秒/毫秒存的时间戳、字节数
- 需要精确相等语义(
a == b就是你想的那个意思)
float 用于:
- 物理量计算(距离、重量、角度)
- 聚合求和(精确性比范围重要度低)
- 受益于大范围数值的数学(科学计算、图形)
- 接受带容差的比较(
abs(a - b) < epsilon)
混用的陷阱
最隐蔽的 bug 都来自 int 和 float 混用。在动态类型语言中:
5 / 2— 很多语言里是整数除法得 2;JavaScript 里得 2.55.0 / 2— 任何语言都得 2.5int(2.5)与Math.floor(2.5)— 大多数语言都得 2;JavaScript 因为没有 int 类型会让你意外
超过 int64 的整数(超大的 ID、高精度时间戳、区块链金额)需要特殊类型:Python 的 int 是任意精度;C++ 有 __int128 和 boost::multiprecision;JavaScript 数字始终是 float64(超过 2^53 的整数用 BigInt)。
货币与经典教训
五十年计算史中的绝大多数金融 bug 都来自用 float 存钱。修法是通用的:以最小整数单位存钱(分、便士、聪)。1999 分就是 19.99 元,永远不会近似。转成人类可读的数字只在显示时发生,使用做十进制算术的库(或配合显式舍入规则的整数除法)。
工具
处理嵌在 JSON 或 CSV 数据里的数字——你可能遇到看起来像 float 的 int 或反过来——JSON to CSV 和 JSON to YAML 在转换中忠实地保留值的类型不改变。
SQL 中,int vs float 列的选择会决定下游所有查询的行为,SQL Formatter 帮你看清局面。
另见
- JSON Schema Generator — 当你想要显式的
integer与number类型 - Regex Tester — 用于从可能是两种形式的字符串里抠出数字