В арифметике с плавающей запятой - единица, стоящая на последнем месте (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
но это не проверено для ULP 10−10, например:
>>> 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;
}
math.ulp(x) == 2**(-(53 - 1)) * 2**math.floor(math.log2(x))
. Не могли бы вы написать ответ, чтобы я мог его принять? - person Maggyero   schedule 04.02.2021