【编程基础】浮点数是如何表示数据的?为何存在精度丢失问题?为何无法比较问题?

发布时间:2026/7/7 5:32:48
【编程基础】浮点数是如何表示数据的?为何存在精度丢失问题?为何无法比较问题? 来看看计算机是怎么在底层把3.0和3.146544这两个数字“造”出来的。在计算机底层IEEE 754 标准32位浮点数被切成了三块符号位 (1 bit)正数还是负数。指数位 (8 bits)决定小数点要往哪边“浮”放大还是缩小。尾数位 (23 bits)决定具体的数字细节精度。我们分别来看这两个数字是怎么被“造”出来的案例一表示3.0极其完美的整数3.0在浮点数世界里是个“乖孩子”它可以被极其精确地表示没有任何误差。第一步把它变成二进制计算机只认 0 和 1。十进制的 3.0 转换成二进制是11.0。第二步套用“科学计数法”调整橡皮筋我们要把它写成1.xxxxx × 2^指数的形式。11.0小数点向左移动 1 位就变成了1.1 × 2^1。这里的1.1就是尾数。这里的1就是指数。第三步塞进 32 个格子里符号位正数填0。指数位实际指数是 1。为了防止负数计算机规定要加上 127 的偏移量1 127 128。128 的二进制是10000000。尾数位前面说过二进制科学计数法小数点左边永远是 1计算机为了省空间默认省略这个 1。所以尾数只需要存小数点后面的1剩下的 22 个格子全补0。最终在内存里的样子01000000010000000000000000000000(完美契合没有任何浪费)案例二表示3.146544带小数的麻烦精带小数的数字在浮点数世界里往往会遇到“除不尽”的尴尬。第一步把它变成二进制整数部分3是11。小数部分0.146544怎么转计算机用的是**“乘 2 取整法”**不断乘以 2把整数部分抠出来0.146544 × 2 0.293088 (取 0)0.293088 × 2 0.586176 (取 0)0.586176 × 2 1.172352 (取 1)0.172352 × 2 0.344704 (取 0)0.344704 × 2 0.689408 (取 0)… 这个过程极其漫长甚至可能是个无限循环小数第二步套用“科学计数法”假设我们算出了足够多的二进制位大概是11.00100101...小数点左移 1 位变成1.100100101... × 2^1。第三步塞进 32 个格子里见证奇迹的时刻符号位0。指数位同样是10000000。尾数位问题来了尾数只有23 个格子。但是0.146544的二进制小数部分可能长达几十位。计算机怎么办直接砍掉四舍五入只保留前 23 位后面的全部扔掉。最终在内存里的样子01000000010010010100011110101110(最后几位是被迫截断的)总结一下浮点数是如何产生的先翻译成二进制十进制小数在二进制下往往变成长长的无限小数。移动小数点调整橡皮筋的倍数把它变成1.xxxx × 2^n。暴力截断因为尾数格子有限超出的部分直接被砍掉或四舍五入。这就解释了为什么浮点数会有误差3.0刚好是个完美的二进制数所以它被原封不动地存了下来。而3.146544在变成二进制时被强行砍掉了尾巴。当你把这个被砍过尾巴的二进制数再翻译回十进制显示在屏幕上时它可能就变成了3.1465439796...。这就是为什么在编程时永远不要用去判断两个浮点数是否相等因为你永远不知道它们底层是不是被悄悄砍过一刀ps为什么指数部分要加上127的偏移量进行计算核心痛点计算机“讨厌”负数在数学里我们很习惯写负数比如-3、-5。但在计算机底层的硬件电路里处理带负号的数字有符号整数是非常麻烦、非常耗时的。计算机最喜欢的是纯粹的、没有负号的正整数无符号整数。但是浮点数里的“指数”偏偏经常是负数呀比如表示极小的数时指数可能是-10。绝妙的解决办法整体平移加偏移量既然计算机讨厌负数那我们就把整个刻度盘往上平移让所有的指数都变成正数想象一下你要记录一个地方的海拔高度范围在-120米到120米之间。如果不加偏移量你要在尺子上刻一个“0米海平面”往上刻正数往下刻负数。计算机每次看这个尺子都要先判断“这是在 0 上面还是 0 下面”很麻烦。如果加上 127 的偏移量我们直接把整个尺子往上抬 127 米原来的-120米现在变成了7米-120 127。原来的0米现在变成了127米0 127。原来的120米现在变成了247米120 127。看到了吗经过这么一抬所有的数字都变成了正数计算机现在只需要像看普通正整数一样去看这个尺子再也不用去管什么负号了简直不要太爽例如7.132131321它的实际指数是2。为了让计算机开心我们给它加上 127 的“海拔偏移量”2 127 129。计算机在内存里存的就是这个129的二进制10000001。那计算机读出来的时候怎么办它只要把这个数减去 127就行了129 - 127 2。它瞬间就知道“哦原来小数点要向右移动 2 位”为什么偏偏是 127因为 32位浮点数分配给指数的格子刚好是8 个比特。8 个比特最多能表示 256 个状态0 到 255。为了公平起见把 256 劈成两半一半给负数一半给正数256 ÷ 2 128。所以127 刚好就是这把尺子最中间的刻度用它来做“海平面基准线”是最完美的。