为什么Python的浮点数会在一些非常长的输入中引发ValueError?

时间:2016-06-21 02:52:05

标签: python

在x64上的Python 2.7.9上,我看到以下行为:

>>> float("10"*(2**28))
inf
>>> float("10"*(2**29))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: 10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
>>> float("0"*(2**33))
0.0
>>> float("0." + "0"*(2**32))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

除非有更深层次的理由,否则我会错过最少的惊喜。当我在"10"*(2**29)上得到ValueError时,我认为它只是对很长字符串的限制,但后来"0"*(2**33)起作用了。发生了什么事?任何人都可以证明为什么这种行为不是一个POLA错误(如果可能是一个相对无关的错误)?

2 个答案:

答案 0 :(得分:4)

因为在推断基础时会跳过零

I like to look to my favourite reference implementation这样的问题。

证明

Casevh在评论中有很大的直觉。 Here's the relevant code

 
for (bits_per_char = -1; n; ++bits_per_char)
    n >>= 1;

/* n <- total # of bits needed, while setting p to end-of-string */
while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base)
    ++p;
*str = p;

/* n <- # of Python digits needed, = ceiling(n/PyLong_SHIFT). */
n = (p - start) * bits_per_char + PyLong_SHIFT - 1;
if (n / bits_per_char < p - start) {
    PyErr_SetString(PyExc_ValueError,"long string too large to convert");
    return NULL;

最初p设置为指向字符串的指针。如果我们查看PyLongDigitValue表,我们会看到0显式映射到0.

Python做了很多额外的工作来优化特定基础的转换(there's a fun 200 line comment about converting binary!),这就是为什么它首先要推断出正确的基础做了很多工作。在这种情况下;我们可以在推断基数时跳过零,因此他们不会计算溢出计算。

实际上,我们正在检查存储此浮点数需要多少位,但python足够聪明,可以从此计算中删除前导零。我没有在浮动函数的文档中看到任何内容,从而保证了跨实现的这种行为。他们不祥地说明了

  

如果可能,将字符串或数字转换为浮点数。

何时不起作用

写作时

   float("0." + "0"*(2**32))

它会在早期停止解析基数 - 所有其余的零都会在位长计算中考虑,并有助于提升ValueError

类似的解析技巧

在float类中的

Here's a similar case,我们发现忽略了空格(以及作者对这个设计选择的意图的有趣评论)

while (Py_ISSPACE(*s))    
    s++;

/* We don't care about overflow or underflow.  If the platform
 * supports them, infinities and signed zeroes (on underflow) are    
 * fine. */

答案 1 :(得分:2)

对于float(&#34; 10&#34; *(2 ** 29))的情况,您将字符串转换为浮点值,该值很可能超过float在Python中可以具有的最大值。

然而,对于float(&#34; 0&#34; *(2 ** 33))的情况,您将字符串转换为浮点值0.0,无论您将其乘以多少次。 / p>

由于对非常长的字符串的限制但由于浮点数的最大值的限制而未发生错误。

随意检查一下 What is the maximum float in Python?