2014-03-14 30 views
3

我正在阅读一个JSON数据文件,可能会给我一个浮动值,比如1.1。当我制作Decimal这个值时,由于浮点数的二进制表示的不精确性,我得到了一个疯狂的长数。十进制(str(my_float))似乎比十进制(my_float)更好,发生了什么事?

我明白二进制表示法,我很满意这个想法,即在base-ten浮点数中可写的数字不能总是以base-two表示。

但似乎如果我串 - 如果首先浮动,并使用该字符串作为值的十进制,我得到一个十进制没有微小的二元 - 不精确三角洲。

这里就是我的意思是:

Python 2.7.6 (default, Jan 16 2014, 10:55:32) 
>>> from decimal import Decimal 
>>> f = 1.1 
>>> d = Decimal(f) 
>>> f 
1.1 
>>> d 
Decimal('1.100000000000000088817841970012523233890533447265625') 
>>> d = Decimal(str(f)) 
>>> d 
Decimal('1.1') 

串ifying使它成为一个小数点前的浮动似乎给我一个结果更接近原始基地十号输入号码(或从一个读JSON文件)。

所以,这里是我的问题:当把字符串化为浮点数时,为什么我看不到数字的长尾? python是否自动跟踪从JSON中解析出来的原始字符串,或者什么?为什么Decimal构造函数不使用该技巧呢?

+1

“为什么Decimal构造函数不使用这个技巧呢?很明显,“十进制”模块的设计者认为严格的准确性是一个更好的结果。我不知道他们为什么会这么想,因为模块的全部内容是使用不能用二进制表示的十进制数。你所看到的数字是确切的 - 一个二进制数总是可以用十进制表示,即使反过来也是如此。 –

回答

4

浮点的确切值是1.100000000000000088817841970012523233890533447265625。 Python不会以某种方式跟踪原始字符串。当Python使用str将其串化时,它会截断为12位数字。

>>> x = 1.0/9 
>>> print decimal.Decimal(x) # prints exact value 
0.111111111111111104943205418749130330979824066162109375 
>>> print x # truncated 
0.111111111111 

即使repr,Python使用时float解析,将舍入到原来的浮动最短的字符串。

>>> print repr(x) 
0.1111111111111111 

如果你想解析JSON并获得十进制实例,而不是浮动,你可以传递一个parse_float参数传递给load(s)功能:

>>> json.loads('{"foo": 1.23456789}', parse_float=decimal.Decimal) 
{u'foo': Decimal('1.23456789')} 

以上调用导致decimal.Decimal被调用来解析数字在JSON字符串中,绕过将发生在中间floatstr调用中的四舍五入。您将得到完全在JSON中指定的数字。

请注意,API区分用于解析看起来像浮动的东西,看起来像整数的东西的函数以及看起来像Infinity-InfinityNaN的东西。如果你想以同样的方式处理所有3个类别,这可能有点不方便:

>>> json.loads('{"foo": 1.23456789}', 
...   parse_float=decimal.Decimal, 
...   parse_int=decimal.Decimal, 
...   parse_constant=decimal.Decimal) 
{u'foo': Decimal('1.23456789')} 
+0

我希望我可以为'parse_float'引用提供另一个+1,这看起来非常有用。 –

+0

(OP在这里..)是的,看起来像parse_float是我应该如何处理这个。这是科学数据,所以我必须严格处理数字。我的工具可以接受数据结构或JSON字符串,所以我也必须处理浮动...如果我确实得到浮点值,我想我会用'Decimal(repr(the_float))'来转换它们,这似乎与我能得到的原始人类意图接近。 –

相关问题