在Python 3.6.2,Win10-x64上
我遇到过一些奇怪的事情并且无法解释.
在:
x = 10.0
for i in range(10):
print(str(i) + " | " + str(x))
x *= x
Run Code Online (Sandbox Code Playgroud)
日期:
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
Run Code Online (Sandbox Code Playgroud)
它怎么变成了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)
Run Code Online (Sandbox Code Playgroud)
这给了我:
1.7976931348623157e+308
1.7976931348623157e+308
inf
inf
1.7976931348623157e+308
Run Code Online (Sandbox Code Playgroud)
这对我来说很奇怪......
怎么变成inf呢?
因为即使是最大的有限浮点数,结果也太大了,所以它溢出了.
为什么不抛出异常?
因为Python在将inf/nan变成异常的时候并不是很一致.一些操作提供例外.有些给inf/nan.
这是否意味着浮子有一种"软"限制 - 当超过时 - 将它们变成inf?如果是这样,那么限制是什么,无论算术运算如何都是一样的?并不意味着inf == this_limit +任何东西?
舍入后任何大于1.7976931348623157e + 308的结果都会成为inf(或者如果Python感觉像是异常).确切的限制不能表示为浮动; 你无法实际执行this_limit + anything,因为试图放入this_limit浮动将其舍入为1.7976931348623157e + 308.
如果您检查 CPython () 中的浮点运算实现floatobject.c,您会发现大多数操作都简单地推迟到 Cdouble操作,例如在float_add、float_sub或 中float_mul:
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);
}
Run Code Online (Sandbox Code Playgroud)
结果a = a * b是根据 IEEE 754 标准在 CPU 上计算的,该标准规定了在溢出情况下(即当结果无法存储在有限的 32 位或 64 位中时)的默认结果-inf/ 。+inffloatdouble
另一件需要注意的事情是,IEEE 754 中定义的五个浮点异常(如溢出)中的任何一个都可以 (1) 生成默认值并将异常信息存储在状态字中,或 (2)SIGFPE如果 FP 则引发信号异常陷阱已启用(请参阅有关 FP 异常的 GNU lib C 文档)。
在Python中,陷阱永远不会启用,因此程序以不间断的模式运行。
这意味着,float_mul上述例程中的溢出结果将默认为 float inf(如 IEEE 754 中定义),并且 Python 将简单地返回PyFloat_FromDouble(a),其中a是inf。
另一方面,如果我们检查float_pow(下面的缩短版本):
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);
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
我们可以看到你的结果x **= x 是inf,如果没有额外的状态字(~ )检查——并且在底层溢出时errno引发Python异常。OverflowErrorpow
总之(正如这里已经指出的),Python 在处理浮点异常方面并不一致——有时会返回默认值(来自 C// libcCPU),有时会引发 Python 异常。
| 归档时间: |
|
| 查看次数: |
901 次 |
| 最近记录: |