最后一位上的单位值
在计算机科学与数值分析中,最后一位上的单位值或称最小精度单位,缩写为ULP,是毗邻的浮点数值之间的距离,也即浮点数在保持指数部分的时候最低有效数字为1所对应的值。ULP用于度量数值计算的精度。[1]
例如:圆周率位于毗邻的双精度浮点数3.1415926535897927与3.1415926535897936之间。
定义
设底数为b,如果x的指数为E,那么ULP(x) = 机器精度·bE。[2]但在计算机与数值计算的文献中,对ULP,指数与机器精度也可用其它方式定义。如John Harrison给出的定义: ULP(x)是两个最近的跨(straddling)x的浮点数a与b的距离,即a ≤ x ≤ b且a ≠ b,并且在指数无上限的情形。[3][4]这两个定义基本等价。
被所有现代浮点硬件遵从IEEE 754标准要求基本算术运算(1985年起的加法、减法、乘法、除法、求平方根,以及2008年起的“积和熔加运算(FMA)”)的结果近似到最近的浮点数且与数学确切结果的距离在0.5 ULP范围内。这性质意味着近似结果与数学确切结果的距离是最小的(但对于居中情形,有两个毗邻的浮点数都满足上述要求)。有美誉的数值库(numeric library)计算基本超越函数的误差在0.5至大约1 ULP间。仅有少数库在计算超越函数时的误差小于0.5 ULP,这一问题相当复杂,归因于Table-Maker's Dilemma。[5]
例子
找到最接近圆周率的双精度浮点数:
#include <cmath>
#include <cstdio>
#define PI 3.14159265358979323846264338327950288419716939937510582097494459230
int main()
{
printf("%.17g (%a)\n", PI, PI);
printf("%.17g (%a)\n", std::nextafter(PI, 0.0), std::nextafter(PI, 0.0));
printf("%.17g (%a)\n", std::nextafter(PI, 4.0), std::nextafter(PI, 4.0));
}
/* Output:
3.1415926535897931 (0x1.921fb54442d18p+1)
3.1415926535897927 (0x1.921fb54442d17p+1)
3.1415926535897936 (0x1.921fb54442d19p+1)
*/
设x用IEEE 754表示时四舍五入且舍入到偶数的操作记为RN。如果ULP(x)的值小于等于1,那么RN(x + 1) > x;否则,RN(x + 1) = x或RN(x + 1) = x + ULP(x),取决于最低有效位(least significant digit)与x的指数部分。下面的Python程序展示了这个例子:
>>> x = 1.0
>>> p = 0
>>> while x != x + 1:
... x = x * 2
... p = p + 1
...
>>> x
9007199254740992.0
>>> p
53
>>> x + 2 + 1
9007199254740996.0
这个例子中,从x = 1开始,反复地翻倍直至x = x + 1。结果是253,因为双精度浮点数格式使用了53位有效数字,从而ulp(253)=253*2-52=2 > 1 。即,在这里双精度浮点数可表示的最小精度间隔已经是2了。
语言支持
从Java 1.5, Java语言的标准库包含了函数:
Math.ulp(double)
与
Math.ulp(float)
。
C语言标准库从C99开始提供了计算给定方向的下一个浮点数的函数:
nextafterf
与nexttowardf
用于float
, nextafter
与nexttoward
用于double
, nextafterl
与nexttowardl
用于long double
, 都在<math.h>
中声明。[6]
Boost C++ Libraries提供了boost::math::float_next, boost::math::float_prior, boost::math::nextafter与boost::math::float_advance等函数获取邻近的浮点数。 [7]。boost::math::float_distance(a, b)计算两个double值之间的浮点距离。 [8]
参见
- IEEE 754
- 最低有效位 (LSB)
- 机器精度
参考文献
- ^ David Goldberg: What Every Computer Scientist Should Know About Floating-Point Arithmetic, section 1.2 Relative Error and Ulps, ACM Computing Surveys, Vol 23, No 1, pp.8, March 1991.
- ^ Higham, Nicholas. Accuracy and Stability of Numerical Algorithms (2 ed). SIAM. 2002.
- ^ Harrison, John. A Machine-Checked Theory of Floating Point Arithmetic. [2013-07-17]. (原始内容存档于2021-02-24).
- ^ Muller, Jean-Michel (2005-11). "On the definition of ulp(x)". INRIA Technical Report 5504. ACM Transactions on Mathematical Software, Vol. V, No. N, November 2005. Retrieved in 2012-03 from http://ljk.imag.fr/membres/Carine.Lucas/TPScilab/JMMuller/ulp-toms.pdf (页面存档备份,存于互联网档案馆).
- ^ Kahan, William. A Logarithm Too Clever by Half. [2008-11-14]. (原始内容存档于2015-07-27).
- ^ ISO/IEC 9899:1999 specification (PDF). . p. 237, §7.12.11.3 The nextafter functions and §7.12.11.4 The nexttoward functions [2016-04-08]. (原始内容存档 (PDF)于2018-01-11).
- ^ Boost float_advance.
- ^ Boost float_distance.
- Goldberg, David (1991-03). "Rounding Error" in "What Every Computer Scientist Should Know About Floating-Point Arithmetic". Computing Surveys, ACM, March 1991. Retrieved from https://web.archive.org/web/20160406101256/http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html#689.