iOS惡心的Double精度

最近發(fā)現(xiàn)在iOS中將String類型轉(zhuǎn)化為Double類型的時候會有莫名奇妙的精度丟失問題累魔,甚至在Double與Double之間的乘除運(yùn)算結(jié)果也會出現(xiàn)很奇葩的精度問題屎飘。試過Objective-C和Swift,都有同樣的問題个粱,看來是iOS系統(tǒng)底層對這些情況有特殊處理吧古毛。

下面以一個很常見的場景來說明問題:

假如在你的項(xiàng)目中需要提供給用戶“提現(xiàn)”的功能,并收取一定比例的手續(xù)費(fèi)(相信玩過各大比特幣交易所的同學(xué)深有感觸)。要求金額保留兩位小數(shù)稻薇,并以手續(xù)費(fèi)四舍五入為準(zhǔn)嫂冻,計(jì)算實(shí)際提取金額。

創(chuàng)建很簡單的視圖:

提現(xiàn)

我們輸入提現(xiàn)金額塞椎,并實(shí)時計(jì)算手續(xù)費(fèi)桨仿,那么我們可能會這樣寫:

屏幕快照 2018-06-04 下午8.32.54.png

得到的結(jié)果是:

結(jié)果1

發(fā)現(xiàn)問題了嗎?

按道理案狠,我們輸入1234.1的時候服傍,手續(xù)費(fèi)四舍五入保留兩位小數(shù)應(yīng)該是61.71,但這里結(jié)果是61.70骂铁,而且實(shí)際提取的金額和手續(xù)費(fèi)的金額加起來也不等于1234.1吹零。

看圖中的斷點(diǎn),是不是很驚訝拉庵!為什么inputValue的值是1234.0999999灿椅?這就是題目中說的惡心的精度。48行直接將String類型轉(zhuǎn)Double類型就會出現(xiàn)這樣奇怪的問題钞支,然后計(jì)算的feeValue就相應(yīng)的變小了一點(diǎn)點(diǎn)茫蛹,再四舍五入就少了0.01了,同樣地烁挟,第55行的結(jié)果是1172.39499婴洼,四舍五入之后變成了1172.39。所以撼嗓,總的來說窃蹋,手續(xù)費(fèi)不對,實(shí)際提取的也不對了静稻。

怎么辦呢? 有兩種方法: 一是手動修正手續(xù)費(fèi)的值匈辱;二是使用NSDecimalNumber振湾,也是最推薦的方式。

首先第一種方法亡脸,既然我們知道系統(tǒng)會丟失一點(diǎn)精度押搪,那我們在轉(zhuǎn)化之后手動修復(fù)一點(diǎn)點(diǎn),比如給inputValue加上一個很小的小數(shù)浅碾,然后再對feeValue手動四舍五入大州,這樣就保證了feeValue的值是正確的,也能保證realValue四舍五入的結(jié)果是對的:

手動修正精度

第二種方法是推薦使用的垂谢,在處理金錢相關(guān)的精度問題首先應(yīng)該考慮使用它

使用NSDecimalNumber

其中我們所有的操作都是基于String和NSDecimalNumber的厦画,中間不涉及Double的轉(zhuǎn)換。其中NSDecimalNumberHandler 是可以定義一些行為參數(shù)的:

scale : 需要保留的精度。
raiseOnExactness : 為YES時在處理精確時如果有錯誤根暑,就會拋出異常力试。
raiseOnOverflow  : YES時在計(jì)算精度向上溢出時會拋出異常,否則返回排嫌。
raiseOnUnderflow : YES時在計(jì)算精度向下溢出時會拋出異常畸裳,否則返回.
raiseOnDivideByZero : YES時。當(dāng)除以0時會拋出異常淳地,否則返回怖糊。

這樣得到的結(jié)果是精確的NSDecimalNumber類型的,我么可以像第56行那樣取出他的string格式結(jié)果颇象。

使用這兩種方式的結(jié)果如下:

正確結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伍伤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子夯到,更是在濱河造成了極大的恐慌嚷缭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耍贾,死亡現(xiàn)場離奇詭異阅爽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)荐开,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門付翁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晃听,你說我怎么就攤上這事百侧。” “怎么了能扒?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵佣渴,是天一觀的道長。 經(jīng)常有香客問我初斑,道長辛润,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任见秤,我火速辦了婚禮砂竖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹃答。我一直安慰自己乎澄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布测摔。 她就那樣靜靜地躺著置济,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舟肉,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天修噪,我揣著相機(jī)與錄音,去河邊找鬼路媚。 笑死黄琼,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的整慎。 我是一名探鬼主播脏款,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裤园!你這毒婦竟也來了撤师?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤拧揽,失蹤者是張志新(化名)和其女友劉穎剃盾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淤袜,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痒谴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铡羡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片积蔚。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖烦周,靈堂內(nèi)的尸體忽然破棺而出尽爆,到底是詐尸還是另有隱情,我是刑警寧澤读慎,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布漱贱,位于F島的核電站,受9級特大地震影響夭委,放射性物質(zhì)發(fā)生泄漏幅狮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一闰靴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钻注,春花似錦蚂且、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春淑翼,著一層夾襖步出監(jiān)牢的瞬間腐巢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工玄括, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冯丙,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓遭京,卻偏偏與公主長得像胃惜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哪雕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容