[英]C++ `digits10` is 6 for IEEE float, but the first non-representable integer already has 8 digits?
C ++的std::numeric_limits<float>::digits10
在cppref中描述如下:
std::numeric_limits<T>::digits10
的值是可以由類型T表示而沒有更改的基數為10的數字,也就是說,具有此多個十進制數字的任何數字都可以轉換為類型的值T並返回小數形式,不會因舍入或溢出而改變。
C表兄弟FLT_DIG存在類似的描述。
給出的值是:
float FLT_DIG /* 6 for IEEE float */
但是 , 這里顯示的是,在32位IEEE浮點類型中,高達16,777,216
(2 24 )的所有整數都可以精確表示。 如果我能算,這個數字有8位,所以對於價值digits10
實際上應該是7,現在不應該嗎?
而是很明顯,我誤解了一些關於digits10
這里,那么,這實際上告訴我嗎?
實用性:
有人問我,如果我們能夠從存儲所有號碼0.00
- 86,400.00
正是在IEEE 32位浮點。
現在,我非常有信心我們可以在IEEE 32位浮點數中存儲0
到8,640,000
所有數字,但這是否適用於向左移動2位數的相同“整數”范圍?
(限制IEEE754 float
答案)。
8.589973e9
和8.589974e9
都映射到8589973504
。 這是第7個有效數字被保留的斷言的反例。
由於第6個有效數字上不存在這樣的反例,因此std::numeric_limits<float>::digits10
和FLT_DIG
為6。
實際上,整數可以精確地表示為2的24 次冪。( 16,777,216
和16,777,217
都映射到16,777,216
)。 這是因為float
具有24位有效數 。
正如另一個答案和評論所確定的digits10
涵蓋了所有“指數范圍”,即它必須保持1234567
以及1.234567
和12345670000
- 這僅適用於6位數!
7位數的反例:
8.589,973 e9
vs. 8.589,974 e9
(來自cppref示例) 有時候很容易找到反例。
#include <stdio.h>
#include <string.h>
int main(void) {
int p6 = 1e6;
int p7 = 1e7;
for (int expo = 0; expo < 29; expo++) {
for (int frac = p6; frac < p7; frac++) {
char s[30];
sprintf(s, "%d.%06de%+03d", frac / p6, frac % p6, expo);
float f = atof(s);
char t[30];
sprintf(t, "%.6e", f);
if (strcmp(s, t)) {
printf("<%s> %.10e <%s>\n", s, f, t);
break;
}
}
}
puts("Done");
}
產量
<8.589973e+09> 8.5899735040e+09 <8.589974e+09>
<8.796103e+12> 8.7961035080e+12 <8.796104e+12>
<9.007203e+15> 9.0072024760e+15 <9.007202e+15>
<9.223377e+18> 9.2233775344e+18 <9.223378e+18>
<9.444738e+21> 9.4447374693e+21 <9.444737e+21>
<9.671414e+24> 9.6714134744e+24 <9.671413e+24>
<9.903522e+27> 9.9035214949e+27 <9.903521e+27>
<1.000000e+28> 9.9999994421e+27 <9.999999e+27> This is an interesting one
另一個角度來看:
考慮在每對2的冪之間,像IEEE二進制的float
編碼線性分布的2 23個值。
示例:介於2 0和2 1或1.0和2.0之間,
float
值之間的差異是1.0 / 2 23或10.192e-06。
以文本形式“1.dddddd”(7位數字)編寫,數字相差1.000e-06。
因此,對於十進制文本編號的每一步,大約有10.2 float
。
編碼這7位數字沒有問題。
在此范圍內,編碼8位數也沒有問題。
示例:介於2 23和2 24或8,388,608.0和16,777,216.0之間。
float
值之間的差異是2 23/2 23或1.0。
以文本形式“8or9.ddddd * 10 6 ”(7位有效數字)寫的低端附近的數字相差1.0。
編碼這7位數字沒有問題。
示例:介於2 33和2 34或8,589,934,592.0和17,179,869,184.0之間,
之間的差float
值是2 33/2 23或1,024.0。
以文本形式“8or9.ddddd * 10 9 ”(7位有效數字)寫的低端附近的數字相差1,000.0。
現在我們遇到了問題。 從8,589,934,592.0開始,接下來文本形式的1024個數字只有1000個不同的float
編碼。
d.dddddd * 10 expo形式的7位數字太多,無法使用float
進行唯一編碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.