天天看點

iOS開發:Objective-C精确的貨币計算

在iOS開發中,和貨币價格計算相關的,需要注意計算精度的問題。即使隻是兩位小數,也會出現誤差。使用float類型運算,是完全不夠的。經過一番測試,最後選擇使用系統提供的API的NSDecimalNumber來進行更好的解決。

作為一個對外的庫,鑒于版本延續,我們保留對外的flaot的類型,不改變接口,選擇進行内部适配。

以下是一些基本的測試,

原始資料

float a = 0.01;

int b = 99999999;

double c = 0.0;

1:使用浮點運算,

c = a*b;

NSLog(@"%f",c);

NSLog(@"%.2f",c);

使用double類型存儲沒有觸及問題的實質,完全不能解決。

<b>2011-12-30 11:04:00.121 Untitled[2912:207] 1000000.000000</b>

<b></b>

<b>2011-12-30 11:04:00.123 Untitled[2912:207] 1000000.00</b>

2:使用類型轉換,提高精度

c = a*(double)b;

Double運算的精度是提高了,可是浮點數的數值早已經出現了精度的不準确,即使存儲空間足夠,同樣還是不準确的數值。

<b>2011-12-30 11:04:00.123 Untitled[2912:207] 999999.967648</b>

<b>2011-12-30 11:04:00.124 Untitled[2912:207] 999999.97</b>

3:通過和NSString的轉換,将計算的原始資料轉換為純粹的double類型的資料,這樣的計算精度就可以達到要求了。

NSString *objA = [NSString stringWithFormat:@"%.2f", a];

NSString *objB = [NSString stringWithFormat:@"%.2f", (double)b];

c = [objA doubleValue] * [objB doubleValue];

計算的結果還是比較準确的,不過需要做格式化輸入和格式化輸出的處理。同時使用NSString來轉換,這樣的寫法看起來比較奇怪。

<b>2011-12-30 11:04:00.190 Untitled[2912:207] 999999.99</b>

4:個人還是比較喜歡使用系統提供的類型來進行計算。通過NSDecimalNumber提供的計算方式,可以很好的計算出準确的精度的資料,同時不需要使用格式化輸出等。

其計算的精度是比較高,這是官方建議的貨币計算的API,對乘除等計算都有單獨的API接口來提供。

NSString *decimalNumberMutiplyWithString(NSString *multiplierValue,NSString *multiplicandValue)

{

     NSDecimalNumber *multiplierNumber = [NSDecimalNumber decimalNumberWithString:multiplierValue];

     NSDecimalNumber *multiplicandNumber = [NSDecimalNumber decimalNumberWithString:multiplicandValue];

     NSDecimalNumber *product = [multiplicandNumber decimalNumberByMultiplyingBy:multiplierNumber];

     return [product stringValue];

}

NSLog(@"%@",decimalNumberMutiplyWithString([NSString stringWithFormat:@"%f",a], [NSString stringWithFormat:@"%d",b]));

隻是測試,是以接口名大緻寫寫,名字取得比較不那麼講究,希望可以表達清楚。

總的來說,對于貨币計算,應該需要注意精度的問題。同時在運算的時候,應該優先選用架構提供的API,否則,就應該使用足夠精度的類型運算,同時對自己寫的接口進行足夠的說明,要求開發者按照規範來使用。

在自己不能保證足夠準确的情況下,用适當的說明的要求來規避責任還是可以接受的。至少被人抱怨兩句總比出錯強。

本文轉自 arthurchen 51CTO部落格,原文連結:http://blog.51cto.com/arthurchen/761426,如需轉載請自行聯系原作者