例如,使用 IEEE-754 32 位二進制浮點數,讓我們表示1 / 3. 它不能精確地完成,但0x3eaaaaab會產生最接近的值1 / 3。您可能希望以十進制寫入值,并讓編譯器將十進制文字轉換為二進制浮點數。
0.333333f -> 0x3eaaaa9f (0.333332986)
0.3333333f -> 0x3eaaaaaa (0.333333313)
0.33333333f -> 0x3eaaaaab (0.333333343)
0.333333333f -> 0x3eaaaaab (0.333333343)
您可以看到 8 個(有效)十進制數字足以表示盡可能正確的值(最接近實際值)。
我用 π 和 e(自然對數的底)進行了測驗,兩者都需要 8 個十進制數字才能最正確。
3.14159f -> 0x40490fd0 (3.14159012)
3.141593f -> 0x40490fdc (3.14159298)
3.1415927f -> 0x40490fdb (3.14159274)
3.14159265f -> 0x40490fdb (3.14159274)
2.71828f -> 0x402df84d (2.71828008)
2.718282f -> 0x402df855 (2.71828198)
2.7182818f -> 0x402df854 (2.71828175)
2.71828183f -> 0x402df854 (2.71828175)
但是,√2似乎需要 9 位數字。
1.41421f -> 0x3fb504d5 (1.41420996)
1.414214f -> 0x3fb504f7 (1.41421402)
1.4142136f -> 0x3fb504f4 (1.41421366)
1.41421356f -> 0x3fb504f3 (1.41421354)
1.414213562f -> 0x3fb504f3 (1.41421354)
https://godbolt.org/z/W5vEcs695
查看這些結果,具有 9 位有效數字的十進制浮點文字足以產生最正確的 32 位二進制浮點值可能是正確的,并且在實踐中,如果空間為存盤額外的數字并不重要。
但我對它背后的數學很感興趣。在這種情況下,如何確定 9 位數字就足夠了?甚至是double任意精度,是否有一個簡單的公式可以得出所需的位數?
當前的答案和評論中的鏈接確認9數字對于大多數情況來說就足夠了,但我發現了一個反例,其中9數字是不夠的。事實上,十進制格式的無限精度需要始終正確轉換(四舍五入到最接近的值)為某些二進制浮點格式(討論 IEEE-754 binary32 浮點數)。
8388609.499用9有效十進制數字表示的是8388609.50。該數字轉換為float的值為8388610。另一方面,用10或更多位表示的數字將始終保留原始值,并且轉換為float的數字具有 value 8388609。
您可以看到8388609.499需要比9數字更準確地轉換為float. 有無數這樣的數字,非常接近二進制浮點格式中兩個可表示值的半點。
uj5u.com熱心網友回復:
我認為您正在尋找*_DECIMAL_DIG常量。C 標準提供了關于如何計算它們的小解釋和公式(N2176 C17 草案):
5.2.4.2.2 浮動型別的特點<float.h>
以下串列中給出的值應替換為具有實作定義的值的常量運算式,這些值的大小(絕對值)大于或等于所示值,符號相同:
...
小數位數n,這樣任何具有p基數b位的浮點數都可以四舍五入為具有n 個十進制數字的浮點數,然后再回傳而不會更改值,
p log10 b if b is a power of 10 ?1 p log10 b? otherwise FLT_DECIMAL_DIG 6 DBL_DECIMAL_DIG 10 LDBL_DECIMAL_DIG 10
使用 IEEE-754 32 位浮點數b = FLT_RADIX = 2和p = FLT_MANT_DIG = 24,結果為FLT_DECIMAL_DIG = ?1 24 log10 2? = 9。( ?x?=ceil(x)) 是天花板函式:向上取整)
uj5u.com熱心網友回復:
那么雙精度甚至任意精度呢,有沒有一個簡單的公式可以推匯出所需的位數?>
從 C17 § 5.2.4.2.2 11FLT_DECIMAL_DIG, DBL_DECIMAL_DIG, LDBL_DECIMAL_DIG
小數位數n,這樣任何具有p基數b位的浮點數都可以四舍五入為具有n 個十進制數字的浮點數,然后再回傳而不會更改值,
p max log 10 b:如果b是 10 的冪
1 p max log 10 b:否則
但我對它背后的數學很感興趣。在這種情況下,如何確定 9 位數字就足夠了?
每個二進制浮點范圍,如 [1.0 ... 2.0)、[128.0 ... 256.0)、[0.125 ... 0.5) 包含 2 p - 1 個均勻分布的值。例如float, p = 24。
十進制文本的每個范圍都n包含 10 n - 1 個值均勻分布。
例子: common float:
當p是 24 和 2 24組合時,n必須至少有8 來形成 16,777,216 個組合才能清楚地將十進制文本往返float傳輸到float. 由于上述兩個十進制范圍的端點可能很好地存在于該組 2 24中,因此較大的十進制值間隔得更遠。這需要 1 十進制數字。
例子:
考慮 2 個相鄰的float值
10.000009_5367431640625
10.000010_49041748046875
兩者都轉換為 8 位有效數字十進制文本"10.000010"。8個還不夠。
9 總是足夠的,因為我們不需要超過 167,772,160 來區分 16,777,216 個float 值。
OP 還詢問8388609.499. (我們只考慮float簡單。)
該值幾乎介于 2 個float值之間。
8388609.0f // Nearest lower float value
8388609.499 // OP's constant as code
8388610.0f // Nearest upper float value
OP 報告:“您可以看到 8388609.499 需要超過 9 位才能最準確地轉換為浮點數。”
讓我們回顧一下標題“浮點文字*1中有效小數位數的最小數量是多少,以盡可能正確地表示該值?”
這個新的問題部分強調所討論的值是源代碼的值,8388609.499而不是它在發出的代碼中變成的浮點常量:8388608.0f.
如果我們認為該值是浮點常數的值,那么定義浮點常數只 需要最多 9 位有效十進制數字8388608.0f。8388608.49,作為源代碼就足夠了。
但是要根據某個數字作為代碼獲得最接近的浮點常數,確實可能需要很多位數。
考慮典型的最小的float,FLT_TRUE_MIN具有精確的十進制值:
0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
0.0 和 0.0 之間的一半是 0.000..(約 39 個零)..0007006..(約 100 個數字)..15625。
如果最后一位數字是 6 或 4,則最接近的數字分別float是FLT_TRUE_MIN或0.0f。所以現在我們有一個案例,其中“需要”109 個有效數字來在 2 個可能的 之間進行選擇float。
為了避免我們越過精神錯亂的懸崖,IEEE-758 已經解決了這個問題。
翻譯(編譯器)必須檢查以符合該規范(不一定是 C 規范)的有效十進制數字的數量要有限得多,即使額外的數字可以轉換為另一個 FP 值。
IIRC,它已經生效FLT_DECIMAL_DIG 3。因此,對于一個常見的float,可以檢查低至 9 3 個有效十進制數字。
(稍后我會查一些章節和詩句)
*1 C 沒有定義:浮點文字,但確實定義了浮點常量,因此使用了該術語。
uj5u.com熱心網友回復:
浮點文字中有效十進制數字的最小數量是多少,以盡可能正確地表示該值?
C 標準不保證浮點文字中的任意數量的十進制數字將產生以浮點格式實際可表示的最接近的值。在討論浮點文字時,C 2018 6.4.4.2 3 說:
…對于十進制浮點常量,…結果要么是最接近的可表示值,要么是緊鄰最接近的可表示值的較大或較小的可表示值,以實作定義的方式選擇...
為了質量,C 實作應該正確地將浮點文字四舍五入到最接近的可表示值,并與偶數低位的選擇聯系起來。在這種情況下,FLT_DECIMAL_DIG、DBL_DECIMAL_DIG和LDBL_DECIMAL_DIG中定義的值<float.h>提供的位數始終足以唯一標識可表示的值。
在這種情況下,如何確定 9 位數字就足夠了?
您需要在編譯器檔案中宣告這種效果,例如它為浮點文字提供正確舍入并且它使用 IEEE-754 binary32(又名“單精度”)for float(或僅需要九個的其他格式)的宣告唯一標識所有可表示值的有效數字)。
雙精度甚至任意精度怎么樣,是否有一個簡單的公式可以得出所需的位數?
C 標準表明,如果b是十的冪,則上述常數計算為p log 10 b ,否則計算為 ceil(1 p log 10 b ),其中p是浮點格式的位數,b是格式中使用的基礎。這些總是足夠的,但后者并不總是必要的。后者提供指數范圍無界時所需的位數;從某種意義上說,它的“1 ”涵蓋了b的冪如何與 10 的冪相互作用的所有可能的余量。但是任何浮點格式都有一個有限的指數范圍,并且對于某些指數范圍的選擇,ceil( p log 10 b ) 代替 ceil(1 p log 10 b ) 就足夠了。這沒有簡單的公式。它不會出現在標準 IEEE-754 格式中,在實踐中可以忽略。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/464185.html
上一篇:將陣列回傳到C中的函式的問題
