浮點(diǎn)數(shù)的存儲(chǔ)
首先要搞清楚javascript如何存儲(chǔ)小數(shù)的壁袄,它和其他語言存儲(chǔ),javascript中的整數(shù)和小數(shù)都只有一種類型--number
,它的實(shí)現(xiàn)遵循 IEEE 754 標(biāo)準(zhǔn)轩褐,使用 64 位固定長度來表示,也就是標(biāo)準(zhǔn)的 double 雙精度浮點(diǎn)數(shù)狞洋。
格式
(1)sign bit(符號): 第1位用來表示正負(fù)號纲辽,0代表數(shù)值為正,1代表數(shù)值為負(fù)您觉。
(2)exponent(指數(shù)): 中間的11位用來表示次方數(shù)拙寡。
(3)mantissa(尾數(shù)):最后的52位用來表示精確度,在二進(jìn)制的“科學(xué)記號”琳水,數(shù)字被表示為:Mantissa*2^exponent肆糕,超出的部分自動(dòng)進(jìn)一舍零。
實(shí)際數(shù)字就可以用以下公式來計(jì)算:
注意以上的公式遵循科學(xué)計(jì)數(shù)法的規(guī)范在孝,在十進(jìn)制是為0<M<10诚啃,到二進(jìn)行就是0<M<2。也就是說整數(shù)部分只能是1私沮,所以可以被舍去始赎,只保留后面的小數(shù)部分。如 4.5 轉(zhuǎn)換成二進(jìn)制就是 100.1仔燕,科學(xué)計(jì)數(shù)法表示是 1.001*2^2造垛,舍去1后 M = 001。E是一個(gè)無符號整數(shù)晰搀,因?yàn)殚L度是11位五辽,取值范圍是 0~2047。但是科學(xué)計(jì)數(shù)法中的指數(shù)是可以為負(fù)數(shù)的外恕,所以再減去一個(gè)中間數(shù) 1023杆逗,[0,1022]表示為負(fù)乡翅,[1024,2047] 表示為正。如4.5 的指數(shù)E = 1025罪郊,尾數(shù)M為 001蠕蚜。
最終的公式變成:
所以 4.5 最終表示為(M=001、E=1025):
下面再以 0.1 例解釋浮點(diǎn)誤差的原因排龄, 0.1 轉(zhuǎn)成二進(jìn)制表示為 0.0001100110011001100(1100循環(huán))波势,1.100110011001100x2^-4,所以 E=-4+1023=1019橄维;M 舍去首位的1尺铣,得到 100110011...。最終就是:
轉(zhuǎn)化成十進(jìn)制后為 0.100000000000000005551115123126争舞,因此就出現(xiàn)了浮點(diǎn)誤差凛忿。
為什么 0.1+0.2=0.30000000000000004?
計(jì)算步驟為:
// 0.1 和 0.2 都轉(zhuǎn)化成二進(jìn)制后再進(jìn)行運(yùn)算
0.00011001100110011001100110011001100110011001100110011010 +
0.0011001100110011001100110011001100110011001100110011010 =
0.0100110011001100110011001100110011001100110011001100111
// 轉(zhuǎn)成十進(jìn)制正好是 0.30000000000000004