我依赖于一些使用decimal类的代码,因为它需要精确到一定数量的小数位。有些函数允许输入是浮动的,因为它与代码基的其他部分的接口方式。要将它们转换为十进制对象,它使用
1mydec = decimal.Decimal(str(x))
其中x是作为输入的浮点。我的问题是,是否有人知道"str"方法应用于float的标准是什么?
例如,取数字2.1234512。它在内部存储为2.1234511999999999,因为浮点数是如何表示的。
1
2
3
4
5>>> x = 2.12345119999999999
>>> x
2.1234511999999999
>>> str(x)
'2.1234512'
好的,在这种情况下,str(x)执行的操作类似于"%.6f""%x"。这是我的代码转换为小数的方式的问题。采取以下措施:
1
2
3
4>>> d = decimal.Decimal('2.12345119999999999')
>>> ds = decimal.Decimal(str(2.12345119999999999))
>>> d - ds
Decimal('-1E-17')
所以,如果我有float,2.1234511999999999,我想把它传递给decimal,用str()把它转换成一个字符串,会得到错误的答案。我需要知道str(x)的规则是什么,这些规则决定了格式是什么,因为我需要确定是否需要重新编写此代码以避免此错误(请注意,这可能是正常的,因为例如,一旦我们有了十进制对象,代码可能会四舍五入到小数点后10位)。
在python的文档中一定有一些规则,希望这里的某个人能指向我。谢谢!
如果没有x.__str__()或x.__repr__(),那么str(x)返回x.__str__()或x.__repr__(),这些完全取决于手头的对象。
str通常返回更为人类可读的表示。如果您想要完全准确,可以使用repr,它将返回'2.12345119999999999'。
请看浮点数和字符串转换的奇怪行为
再说一次,如果您的原始编号是2.1234512,而2.12345119999999999只是内部存储的方式,那么str的"缩短"表示是否更精确?
@托比亚斯·库克:是的,我曾经看到过这个功能,它的编号是2.1234512,但我可能看到的是2.123451199999999。
在python源中,查找"include/floatobject.h"。字符串转换的精度是在注释后从顶部开始设置几行,并对选择进行一些解释:
1
2
3
4
5/* The str() precision PyFloat_STR_PRECISION is chosen so that in most cases,
the rounding noise created by various operations is suppressed, while
giving plenty of precision for practical use. */
#define PyFloat_STR_PRECISION 12
如果你需要不同的东西,你可以选择重建。任何更改都将更改浮点数和复数的格式。请参见./objects/complexobject.c和./objects/floatobject.c。此外,您还可以比较这两个文件中repr和str转换双精度的不同。
是的,就是这样!谢谢!
注意这个数字在python 2.6和python2.7之间发生了变化。如果你想要最大的精度,你应该使用repr()而不是str(),它总是给你一个表示,在双精度的范围内尽可能精确地表示数字。
重建python当然不是解决这个问题的正确方法。
@Svenmarnach:据我所知,在python 2的生命周期中,PyFloat_STR_PRECISION并没有改变:2.6和2.7都是12。当大值的串化转换为科学记数法时,会有一些小的变化,但是浮点的str仍然基于小数展开的12个最重要的数字。在python 3.2和更高版本中,这一点发生了变化,其中repr和str现在对于float是相同的。
@马克迪金森:谢谢你的纠正。我似乎记得这个变化是在3.1和2.7中应用的,但我的记忆显然是错误的。:)也许这是最基本的表示方式……
@Svenmarnach:是的:float->string和string->float转换的新算法进入了python 3.1,然后(稍后)进入了python 2.7,repr输出的差异是变化中最用户可见的部分。从理论上讲,可能也会出现影响str的角点情况(例如,在操作系统未完全正确进行舍入的情况下,接近一半的情况);实际上,我不知道任何此类角点情况。
这里有几个问题值得讨论,但总结是:您不能提取尚未存储在系统中的信息。
如果您取了一个十进制数并将其存储为一个浮点,那么您将丢失信息,因为大多数具有有限位数的十进制(以10为基数)数不能使用以2为基数(二进制)的有限位数存储。
如前所述,str(a_float)实际上称为a_float.__str__()。如文件所述,该方法的目的是
return a string containing a nicely printable representation of an object
对于float案件没有特别的定义。我的意见是,为了您的目的,您应该考虑__str__的行为是未定义的,因为没有关于它的正式文档-当前的实现可以随时更改。
如果没有原始字符串,则无法从float对象中提取十进制表示的缺失数字。您所能做的就是使用字符串格式(您提到的)按可预见的方式进行四舍五入:
Decimal( "{0:.5f}".format(a_float) )
您还可以使用resulting_string.rstrip("0")删除右侧的0。同样,此方法不会恢复已丢失的信息。