【问题标题】:Python format default rounding when formatting float number格式化浮点数时的Python格式默认舍入
【发布时间】:2017-04-03 11:48:29
【问题描述】:

我正在尝试在 Python 2.7.10 中解决我的代码中的一些浮点问题。在测试时,我遇到了 format 方法的奇怪行为:

print "{}".format(0.3000000000004) # 13 decimals

打印:0.3

但是:

print "{}".format(0.300000000004) # 12 decimals

打印:0.300000000004

既然我没有指定格式,为什么它会四舍五入第一个数字?是否有默认允许的小数位数?

【问题讨论】:

标签: python floating-point numbers format


【解决方案1】:

由于您没有指定格式,因此使用默认类型强制转换为字符串。所以这不是format 的真正问题。 Python 2 将float.__str__ 截断到 12 个字符的精度(不包括前导零,如果有的话),并且在这种情况下截断后,所有尾随零都被清除:

>>> str(0.3000000000004) # unlike str(0.3000000000014) -> '0.300000000001'
'0.3'

添加 format_spec :f 会得到默认精度 6:

>>> '{:f}'.format(0.3000000000004)
'0.300000' 

指定宽度和精度或使用repr 以获得良好的表示:

>>> '{!r}'.format(0.3000000000004)
'0.3000000000004'

但在 Python 3 中的行为有所不同:

>>> str(0.3000000000004)
'0.3000000000004'

浮点数的格式化仅由 Python 3 中的一个函数 float_repr 处理(它没有特殊的 float_str 函数):

(reprfunc)float_repr,                       /* tp_repr */
...
(reprfunc)float_repr,                        /* tp_str */

而 Python2.7 分别为 __str__ 和 __repr__ 定义了一个单独的处理程序 float_str 和 float_repr:

(reprfunc)float_repr,                       /* tp_repr */
...
(reprfunc)float_str,                        /* tp_str */

我认为这里的决定性变量是超过 12d.p 的精度损失的原因。是PyFloat_STR_PRECISION(在 Python 2 中定义):

#define PyFloat_STR_PRECISION 12

对于在默认转换中超过 12 个字符的浮点数,它会反转为截断。

【讨论】:

  • 但是在 Py3.6 中 str(0.3000000000004) returns '0.3000000000004'
  • @Chris_Rands 在 2.7 和 3.6 之间,字符串发生了很大变化,所以我认为这并不令人惊讶
  • 没有说这令人惊讶,但它并不直观(至少对我而言),所以也许值得在你的回答中解释:)
  • 好吧,这是有道理的,我只是想知道这是否是预期的行为。那么我可以确定这种舍入解决了数字到字符串转换的浮点问题吗?
  • @Chris_Rands 花了一些时间浏览了 c 代码,但是你已经有了它
【解决方案2】:

这正是 python(和许多其他语言)处理浮点不准确性的方式。所以在内部这个数字实际上等于 0.3。有一个专门针对这个问题的多语言网站:http://0.30000000000000004.com/

对于这个特定的打印,您可以简单地引用数字(使其成为字符串),编译器不会尝试对数字进行四舍五入:

print "{}".format("0.3000000000004")

但是你也不需要使用格式:

print "0.3000000000004"

【讨论】:

  • 不,这是关于格式的准确性,而不是一般的 FP 准确性。
  • IEEE 754 二进制浮点数不可能具有值 0.3。最接近的 64 位二进制浮点数是 0.299999999999999988897769753748434595763683319091796875
猜你喜欢
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多