Python:大型浮动如何自动变成* inf *?

时间:2017-09-26 17:07:40

标签: python

Python 3.6.2,Win10-x64

上的

我遇到过一些奇怪的事情并且无法解释。

在:

x = 10.0
for i in range(10):
    print(str(i) + " | " + str(x))
    x *= x

输出:

0 | 10.0
1 | 100.0
2 | 10000.0
3 | 100000000.0
4 | 1e+16
5 | 1e+32
6 | 1.0000000000000002e+64
7 | 1.0000000000000003e+128
8 | 1.0000000000000005e+256
9 | inf

为什么它会变成inf为什么不抛出异常?

例如,如果我用*=替换最后一行中的**=,那么在第二次迭代中它会引发OverflowError: (34, 'Result too large'),这是有道理的(因为它只有10.000.000.000 ^ 10.000.000.000)。

这是否意味着浮动上存在一种“软”限制 - 当超过时 - 将它们变成inf?如果是这样,那么限制是什么,无论算术运算如何都是一样的?这不会意味着像inf == this_limit + anything吗?

添加

我知道有sys.float_info.max。这是限制吗?

我刚才有了一个想法并测试了一些东西:

print(sys.float_info.max)
print(sys.float_info.max + 1)
print(sys.float_info.max * 2)
print(sys.float_info.max * 1.000000000000001)
print(sys.float_info.max * 1.0000000000000001)

这给了我:

1.7976931348623157e+308
1.7976931348623157e+308
inf
inf
1.7976931348623157e+308

这对我来说很奇怪......

2 个答案:

答案 0 :(得分:6)

  

为什么它会变成inf?

因为即使是最大的有限浮点数,结果也太大了,所以它会溢出。

  

为什么不抛出异常?

因为Python在将inf / nan变成异常的时候不是很一致。一些操作提供例外。有些人给inf / nan。

  

这是否意味着浮子有一种“软”限制 - 当超过时 - 将它们变成inf?如果是这样,那么限制是什么,无论算术运算如何都是一样的?这不会暗示像inf == this_limit +任何东西吗?

在舍入后,任何大于1.7976931348623157e + 308的结果都会成为inf(或者如果Python感觉像是异常)。确切的限制不能表示为浮动;你实际上无法执行this_limit + anything,因为尝试将this_limit放入浮点数会将其舍入为1.7976931348623157e + 308。

答案 1 :(得分:3)

转到来源

如果你在CPython(floatobject.c)中检查浮点运算实现,你可以看到大多数操作只是推迟到C double操作,例如在float_add,{{3 }},或float_sub

static PyObject *
float_mul(PyObject *v, PyObject *w)
{
    double a,b;
    CONVERT_TO_DOUBLE(v, a);
    CONVERT_TO_DOUBLE(w, b);
    PyFPE_START_PROTECT("multiply", return 0)
    a = a * b;
    PyFPE_END_PROTECT(a)
    return PyFloat_FromDouble(a);
}

结果a = a * b是根据IEEE 754标准在CPU上计算的 - 在溢出的情况下禁止-inf / +inf的默认结果(即结果不能存储在有限的32位float或64位double中。)

另外需要注意的是,IEEE 754中定义的五个浮点异常(如溢出)中的任何一个都可以(1)产生默认值并将异常信息存储在状态字,或者(2)如果启用FP异常陷阱,则发出SIGFPE信号(参见float_mul)。

在Python中,陷阱是GNU lib C docs on FP exceptions,因此程序以不间断模式运行。

乘法溢出

这意味着,反过来, float_mul例程上的溢出结果将默认为float inf(如IEEE 754中所定义)和Python只会返回PyFloat_FromDouble(a)ainf

指数溢出

另一方面,如果我们检查never enabled(下面的缩短版本):

static PyObject *
float_pow(PyObject *v, PyObject *w, PyObject *z)
{
    ...
    errno = 0;
    PyFPE_START_PROTECT("pow", return NULL)
    ix = pow(iv, iw);
    PyFPE_END_PROTECT(ix)
    Py_ADJUST_ERANGE1(ix);

    if (errno != 0) {
        PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
                             PyExc_ValueError);
        ...
    }
    ...
}

我们可以看到x **= x 的结果为inf ,如果不是附加的状态字(〜{{ 1}})检查 - 并在基础errno溢出的情况下引发Python OverflowError异常。

总之(如此处已经提到的),Python在处理浮点异常时并不一致 - 有时会返回默认值(来自C / pow / CPU),有时会引发Python异常。 / p>