>> float("10"*(2**29)) Traceback (most-6ren">
gpt4 book ai didi

python - 为什么 Python 的 float 会为一些非常长的输入引发 ValueError?

转载 作者:太空狗 更新时间:2023-10-29 20:25:13 25 4
gpt4 key购买 nike

在 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 错误(如果可能是一个相对不相关的错误)?

最佳答案

因为在推断基数时跳过了零

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!),这就是为什么它首先要做很多工作来推断正确的碱基。在这种情况下;我们可以在推断基数时跳过零,因此它们不计入溢出计算。

的确,我们正在检查存储这个 float 需要多少位,但是 python 足够聪明,可以从这个计算中删除前导零。我在 float 函数的文档中看不到任何保证跨实现的行为的内容。他们不祥地说

Convert a string or number to a floating point number, if possible.


什么时候这不起作用

当你写作时

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

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


类似的解析技巧

Here's a similar case在 float 类中,我们发现空白被忽略了(以及作者对他们选择这种设计的意图的有趣评论)

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. */

关于python - 为什么 Python 的 float 会为一些非常长的输入引发 ValueError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37934813/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com