我有一些简单的代码,如下所示
a = 0.8889
print repr(a)
print str(a)
我在几种不同的系统(包括Python 2.7.12〜2.7.14,作为提示输入或脚本)上进行了尝试,总是得到结果
0.8889
0.8889
这里是one example。
但是,在App Engine(运行时Python 2.7.12)上,我得到了
0.88890000000000002
0.8889
我了解repr() trends to be more precise。问题是为什么App Engine的行为会有所不同。是否依赖底层硬件?
背景:
这个事实使我很烦,因为在将浮点数转换为json时,我不必要地获得了多余的数字。
更新:
事实证明这是GAE运行时的错误。正如Mark所言,根本原因是sys.float_repr_style
的配置丢失。 GAE支持团队创建了一个错误报告here。
Update2: 自2018/08/19起已修复。即使尚未宣布。
答案 0 :(得分:1)
很明显,正如@abarnert在评论中提到的那样,GAE env在后台做了一些工作,其中之一是提高了所用浮点数的精度。
首先要注意的事情之一是:
>>> a = 0.88890000000000002
>>> print a
0.8889
这意味着多余的数字是没有用的。
您可以使用Decimal模块来重现这种情况:
>>> from decimal import *
>>> Context(prec=17).create_decimal_from_float(0.899).__str__()
'0.89900000000000002'
有趣的是,GAE似乎试图模拟〜17的浮点精度(float
没有特定的十进制精度,因为它们表示为浮点数)。如果> 17,则会得到更多的小数,如果少于,则数字将不够精确。
使用Decimal
的优点是浮点错误更少,尽管看起来repr()
与此相关。
查看以下更多扩展示例以提供更多上下文:
>>> from decimal import *
>>> Context(prec=16).create_decimal_from_float(0.899).__str__()
'0.8990000000000000'
>>> Context(prec=17).create_decimal_from_float(0.899).__str__()
'0.89900000000000002'
>>> Context(prec=18).create_decimal_from_float(0.899).__str__()
'0.899000000000000021'
>>> repr(float(1.0000000000000003)).__str__()
'1.0000000000000002'
>>> Context(prec=17).create_decimal_from_float(1.0000000000000003).__str__()
'1.0000000000000002'
>>> repr(float(1.0000000000000002)).__str__()
'1.0000000000000002'
>>> Context(prec=17).create_decimal_from_float(1.0000000000000002).__str__()
'1.0000000000000002'
>>> repr(float(1.0000000000000001)).__str__()
'1.0'
>>> Context(prec=17).create_decimal_from_float(1.0000000000000001).__str__()
'1'
最后,由python float 0.899表示的实际数字是:
>>> from decimal import *
>>> Decimal(float(0.899))
Decimal('0.89900000000000002131628207280300557613372802734375')
因此,最后,repr
在GAE中提供的表示非常精确。
答案 1 :(得分:1)
sys.float_repr_style
的值为'legacy',这是GAE在构建时设置的选项,无法更改。
此版本的repr
算法曾经是Python 2.7之前使用的格式,该算法先计算17个有效数字,然后将输出基于这17个数字(适当时将尾随零除掉