最後一位上的單位值
在計算機科學與數值分析中,最後一位上的單位值或稱最小精度單位,縮寫為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]
參見
[編輯]參考文獻
[編輯]- ^ 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.