問題描述:
在iOS開發(fā)中:涉及價(jià)格金額處理,后臺(tái)有時(shí)會(huì)返回Number類型的數(shù)據(jù)状知,打印或者經(jīng)過Json轉(zhuǎn)Model后的NSString有時(shí)會(huì)出現(xiàn)精度丟失的問題,如果涉及到金額的加減乘除運(yùn)算問題將暴露得更為明顯有咨。
代碼示例:
NSArray *numbers = @[
@9,
@9.00,
@9.09,
@9.19,
@9.29,
@9.39,
@9.49,
@9.59,
@9.69,
@9.79,
@9.89,
@9.99,
@10.00,
@10,
];
for (int i = 0; i < numbers.count; i++) {
NSNumber *number = numbers[I];
NSString *newValue = [number stringValue];
NSLog(@"newValue:%@,number:%@",newValue,number);
}
我們看輸出的結(jié)果可以看出來將NSNumber轉(zhuǎn)換成NSSting的過程中和存儲(chǔ)的時(shí)間可能都會(huì)出現(xiàn)精度丟失携龟。
問題分析
因?yàn)楦↑c(diǎn)數(shù)在計(jì)算機(jī)中是采用IEEE規(guī)定的標(biāo)準(zhǔn)浮點(diǎn)格式,即二進(jìn)制科學(xué)表示法衡创。 在這種表示法中帝嗡,一個(gè)數(shù) S = M * 2 ^ N。
其中N表示階碼璃氢,M表示位數(shù)(有效數(shù)字位)哟玷。 例如一個(gè)float類型的浮點(diǎn),在32bit位上一也,占4個(gè)字節(jié)巢寡,字節(jié)表示為
【31】N:【30 ~ 23】 M:【22~0】
a)31位表示符號(hào)位: 0正,1負(fù)
b)中間8位是階碼位: 表示范圍【-128 ~ 127】,對(duì)于float類型數(shù)據(jù)規(guī)定其偏移量為127
c)后面23位是有效數(shù)字位: 因?yàn)榭茖W(xué)計(jì)數(shù)法椰苟,整數(shù)位定死了是1抑月,所以這里記錄的是小數(shù)點(diǎn)后面的二進(jìn)制為
指數(shù)N決定它的范圍,因?yàn)镸總是一個(gè)以1開頭的小數(shù)舆蝴,以float來說即是:-2 ^ 128 ~ 2 ^ 128,即float能表示的數(shù)的大小的范圍谦絮。
而它的精度是由位數(shù)(也就是有效的數(shù)據(jù)位)來決定的, 2 ^ 23 = 8388608洁仗,總共7位挨稿,表示最多能用7位有效數(shù)字,最多能表示到.8388708即小數(shù)點(diǎn)后7位京痢,由于不能完全表示全部的7位數(shù),所以它的精度范圍是6位~7位篷店。
同理可得double的精度是2 ^ 52 = 4503599627370496祭椰, 共16位,所以精度為15 ~ 16位疲陕。
總結(jié):
float/double類型的范圍和精度的計(jì)算方式方淤,對(duì)于高精度的計(jì)算是不合適的,存在著精度的丟失蹄殃。相對(duì)于float 携茂;double的精度更高一些在用的時(shí)間要做好取舍