更新的準確性和完整性
您遇到是精度在浮點數(相當常見的)問題。上許多編譯器,浮點數只有32位長,並且它們使用一定數量的那些位(23)的對他們的「有效位數」(有時稱爲「尾數」),1個符號位,並且8位用於「指數」(在很多象1.23E45,在‘1.23’是有效數字,而‘45’是指數在二,你實際上有相對較少的(24)那些和可用零,所以你在奔波了精度十進制表示法中的數字6或7)。
爲了說明的精度這方面的損失,我寫的幾行代碼:
#include <stdio.h>
int main(){
float fpennies;
long lpennies, ii;
lpennies = 805306360;
for(ii = 0; ii< 100; ii++) {
fpennies = lpennies + ii;
printf("%ld pennies converted to float: %.0f fpennies\n",ii+ lpennies, fpennies);
}
}
這種生產類型
805306360 pennies converted to float: 805306368 fpennies
805306361 pennies converted to float: 805306368 fpennies
805306362 pennies converted to float: 805306368 fpennies
...
805306400 pennies converted to float: 805306368 fpennies
805306401 pennies converted to float: 805306432 fpennies
正如你所看到的許多行,對周圍805306400
,遞增該long
只需一按64
遞增數量的float
表示!最好通過稍微靠近浮點數的二進制表示來解釋。
首先,這裏是一個32位浮點數字的組織(從http://upload.wikimedia.org/wikipedia/commons/d/d2/Float_example.svg):
我們可以有明確的鑄造得到一個數字的十六進制表示:
printf("%.0f %08x", fpennies, *(unsigned int*)(&fpennies));
對於前面我們看到的跨越跳躍的兩個值,這導致
805306368 4e400000
805306432 4e400001
正如你所看到的,有效數的「最低顯著位」增加了1
,但指數意味着64.爲什麼64事半功倍?好吧,讓我們展開前幾名位:
0x4e40 = 0100 1110 0100 0000 in binary
由於最高位爲符號位(0 =正),接下來的八位是指數,這使得指數
1001 1100 = 0x9c = 156
現在用於從浮點到其值的位得到規則(見http://en.wikipedia.org/wiki/Single-precision_floating-point_format)是
value = (-1)^(sign bit) * (1 + sum(i=1 to 23, bit(23-i)*2^(-i))) * 2^(exponent - 127)
在這種情況下,1
在至少顯著位的變化(0位)增加2^(-23) * 2^(156 - 127) = 2^6 = 64
因此,對於這個量級的數字,可以表示的最小步數是64
,正如您在輸出中看到的那樣。
如果你想解決這個問題,你可以在Vaughn的答案中提出建議 - 使用代表便士的長整數,並使用整數數學(除法,模)來獲得「全部美元,全部美分」數量。
long int dollars, cents, pennies;
...
dollars = pennies/100;
cents = pennies % 100;
以這種方式,您可以代表一些非常大的金錢而不會損失精度。
在實踐中,當你寫
float pennies = 805306365;
printf("you have %f pennies\n", pennies);
你得到
You have 805306368 pennies
如果使用double
類型,你將有更好的運氣(在這種情況下)。
如果您在使用'float',它不會有足夠的精度保持'805306365'。並且不要使用浮點類型來賺錢。 – Mysticial 2013-04-08 02:44:33
[請仔細閱讀本文](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)。這將需要一段時間,但它會永遠改變你對漂浮指針數字的任何想法。 – WhozCraig 2013-04-08 02:59:00
當整數足夠時,不要對浮點數進行數學運算。 – 2013-04-08 03:00:14