python - 函数 math.ulp 是否比 Python 中的显式公式更精确?
问题描述
在浮点运算中,浮点数的最后一位(ULP) 的单位是该数与连续一个数之间的间距,即如果它是 1,则它的最低有效位(最右位)的值。它由以下公式给出:
ULP( x ) = b -( p -1) • | x |
其中b是基数(二进制数字为 2),p(双精度有效数为 53)是精度。
Python 3.9 引入了一个新函数math.ulp
来计算浮点数的 ULP。
使用这个函数,前面的公式被验证为 ULP 为 1 的预期:
>>> math.ulp(1)
2.220446049250313e-16
>>> 2**(-(53 - 1)) * abs(1)
2.220446049250313e-16
但对于 10 -10的 ULP 未验证,例如:
>>> math.ulp(1e-10)
1.2924697071141057e-26
>>> 2**(-(53 - 1)) * abs(1e-10)
2.2204460492503132e-26
math.ulp(x)
比 更精确吗2**(-(53 - 1)) * abs(x)
?为什么?
CPython 实现在Modules/mathmodule.c#L3408-L3427但我找不到被调用函数的实现nextafter
来理解:
static double
math_ulp_impl(PyObject *module, double x)
/*[clinic end generated code: output=f5207867a9384dd4 input=31f9bfbbe373fcaa]*/
{
if (Py_IS_NAN(x)) {
return x;
}
x = fabs(x);
if (Py_IS_INFINITY(x)) {
return x;
}
double inf = m_inf();
double x2 = nextafter(x, inf);
if (Py_IS_INFINITY(x2)) {
/* special case: x is the largest positive representable float */
x2 = nextafter(x, -inf);
return x - x2;
}
return x2 - x;
}
解决方案
2 −(53−1) • | x | (or 2**(-(53 - 1)) * abs(x)
) 不是 ULP( x ) (or math.ulp(x)
) 的公式,因为它没有在 x 的最低位的位置给出 1 的值,而是x (1.something) 的有效数字的值缩放到x的最低位的位置。当x不是 2 的幂时,其有效数超过 1,公式太高。
正确的公式是 2 −(53−1) • 2 max( e , −1022)其中e是x的 IEEE 754归一化指数,即 2 e ≤ | x | < 2 e +1(或)。2**(-(53 - 1)) * 2**max(math.floor(math.log2(x)), -1022)
推荐阅读
- javascript - Google Apps 脚本:读取持续时间值已关闭 X 分钟
- java - 忽略 @Controller 内 ResponseEntity<> 中的 JSON 字段
- c++ - SDL2 ios如何获取UIViewController指针
- sql - 连接 2 个查询的 SQL 操作
- python - exec'ing python sqlite3执行命令的问题
- reactjs - 如何在查询参数url中传递数组反应
- deployment - uSync 下拉数据类型问题
- git - 给定本地和远程分支名称的 Git 推送
- android - 在后台线程中膨胀视图?
- postgresql - “‘密码’的空值”——DataGrip 中的 PostgreSQL