news 2026/10/16 1:57:31

python中的浮点数运算、round()

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python中的浮点数运算、round()

0.1 ,计算机会想“没前缀,是十进制,我要转成二进制存”;你写 0b0.00011 ,它才会想“有 0b ,是二进制,我直接按二进制存”。 计算机是以二进制来存储数据的,而像 0.1 、 0.2 这样的十进制小数,在转换为二进制时是无限循环小数。由于计算机的存储位数有限,只能对其进行近似存储,这就导致了计算时的精度误差。

当浮点数的近似值与十进制小数的差异非常小时,会自动以更简洁的十进制形式显示,而不是输出其底层存储的完整(带误差的)二进制近似值。例子a = 0.1 :底层存储的是 0.1 的二进制近似值(0.000110011001100110011

实际是 0.10000000000000000555... )。

二进制近似值(0.0001100110011...) → 这个二进制值转成十进制后是 0.10000000000000000555... → 它和目标十进制 0.1 差异极小 → Python 直接显示 0.1。

0.1 + 0.2 之所以会显示长串的误差( 0.30000000000000004 ),是因为这两个浮点数的近似值相加后,误差的表现形式无法被 Python 的显示优化“掩盖”,所以只能输出其真实的存储结果。

round() 用的其实是“银行家舍入”(四舍六入五成双),不是严格意义的四舍五入

银行家舍入‌(也叫“四舍六入五成双”),不是我们数学课上学的那种“四舍五入”。

四舍五入‌:逢五就进位,2.5 → 3,3.5 → 4

‌银行家舍入‌:当数字‌正好卡在中间‌(比如 2.5 正好在 2 和 3 正中间)时,‌向偶数那边靠

round(2.5) # 2 → 2和3中间,2是偶数,所以取2
round(3.5) # 4 → 3和4中间,4是偶数,所以取4
round(4.5) # 4 → 4和5中间,4

2.5 在计算机中是可以被精确存储的‌。一个十进制小数能否被二进制‌精确‌表示,取决于它能否写成 1/2^n的和。

‌2.5 的二进制转换‌:

整数部分 2 → 二进制 10

小数部分 0.5 → 二进制 0.1 (因为 0.5 = 1/2 = 2^(-1)

所以,2.5 的二进制表示是 10.1。这是一个‌有限‌的二进制小数。

在 IEEE 754 双精度浮点数标准中,2.5 可以被毫无误差地存储为:

1.01 ×2 ^1 尾数部分正好存得下,没有截断,没有舍入误差。因此,内存里的 2.5 就是数学意义上的四舍五入。

为什么round(2.675, 2) 返回2.67而不是 2.68

2.675 的二进制转换‌:

整数部分 2 → 10

小数部分 0.675 → 尝试用 1/2, 1/4, 1/8...1/2,1/4,1/8... 拼凑:

0.675×2=1.35 → 取 1

0.35×2=0.7 → 取 0

0.7×2=1.4 → 取 1

0.4×2=0.8 → 取 0

0.8×2=1.6 → 取 1

0.6×2=1.2 → 取 1

0.2×2=0.4 → 取 0

0.4×2=0.8 → 取 0 ... ‌开始循环了!‌

0.675 的二进制是 0.1010110011001100...(1100 无限循环)。

2.675 在二进制里无法精确表示,实际存的是一个‌比它略小‌的数,大约是这个:2.6749999999999998 ,round() 拿到的是这个“略小”的数去舍入,自然就往下走了。你可以自己验证:

repr(2.675)

#'2.67499999999999982236431605997495353221893310546875'

总结
round(2.5) 返回2:是因为2.5 存得准,且符合银行家舍入规则(五成双,2是偶数)。
round(2.675,2)返回2.67:主要是因
为 2.675 存不准,实际值略小于
2.675,导致它甚至没资格参与“五成
双”的判断,直接被当作“小于5”处理了。
哪些小数能精确存储?
只要小数部分的分母是2的幂次(如0.5,
0.25,0.125,0.75等),就能精确存储。像
0.1, 0.2, 0.3, 0.675 这种分母含有5或其他质因数的,通常都无法精确存储。

想要真正的“四舍五入”怎么办

‌1. 格式化输出(适合展示)

f'{2.675:.2f}' # '2.68'(返回字符串,一般符合直觉)

2. 用 decimal 模块(适合金额计算)‌

from decimal import Decimal, ROUND_HALF_UP

Decimal('2.675').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
# Decimal('2.68')
注意:Decimal 后面要传‌字符串‌,传 2.675 这个浮点数本身又会把误差带进去。

简单记:普通场景用 round() 没问题;涉及金额、分数这类‌不能有偏差‌的计算,用 decimal 模块才稳。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 1:54:38

TwinCAT 2.0从入门到精通:PDF手册实战指南与避坑技巧

简介:《TwinCAT 2.0从入门到精通》是面向Beckhoff自动化系统工程师的实践型教程,由拥有近15年倍福技术工作经验的Lizzy Chen编写,非官方发行。内容聚焦TwinCAT 2这一PC-based控制平台,覆盖系统配置、PLC编程、EtherCAT与K-Bus I/O…

作者头像 李华