參考:https://blog.csdn.net/oximing1/article/details/50456969
既金融類app中有關數值精確計算的問題。
1.簡單粗暴的方法—doubleValue解決
剛開始接手的項目中關于數值的計算就是按照字符串直接轉doubleValue的方式轉化為后進行加減乘除運算。這樣做在大多數情況下是不會有問題的,但如果經過全面測試的話,有些字符串轉double會出現精度損失問題,計算結果也會出現不準確的問題,一個最近踩過的坑就是用戶再輸入投資金額的時候會對自己賬戶中的可用余額進行判斷,以確定余額是否充足,測試的時候輸入很多數據都沒問題,但線上用戶大量數據就會出現偶爾數據錯誤,用戶輸入金額明明和可用余額一樣,但判斷的時候就會提示可用余額不足,老板使用過程中也遇到過,還找了我好幾次,汗,都是之前開發人員的坑。所以記住這簡單粗暴的方法針對金融類的對數據精度及其敏感的項目不可取。
2.明智之舉—NSDecimalNumber
NSDecimalNumber是蘋果提供的專門金融貨幣精確數值計算的API。
+ (instancetype)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode
scale:(short)scale
raiseOnExactness:(BOOL)raiseOnExactness
raiseOnOverflow:(BOOL)raiseOnOverflow
raiseOnUnderflow:(BOOL)raiseOnUnderflow
raiseOnDivideByZero:(BOOL)raiseOnDivideByZero
參數和說明:
- roundingMode:要使用的舍入模式,有四種值: NSRoundUp, NSRoundDown, NSRoundPlain, and NSRoundBankers
- scale:結果保留幾位小數
- raiseOnExactness:發生精確錯誤時是否拋出異常,一般為NO
raiseOnOverflow:發生溢出錯誤時是否拋出異常,一般為NO
raiseOnUnderflow:發生不足錯誤時是否拋出異常,一般為NO
raiseOnDivideByZero:被0除時是否拋出異常,一般為YES
2.1 NSDecimalNumber 的使用。
NSDecimalNumber是進行數值計算的對象,即所有的加減乘除,冪運算操作對象。
NSDecimalNumberHandler *handler = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundBankers
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
NSDecimalNumber *num1 = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%@",@"2.37"]];
NSDecimalNumber *num2 = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%@",@"15.89"]];
//加
NSDecimalNumber *addResult = [num1 decimalNumberByAdding:num2
withBehavior:handler];
//減
NSDecimalNumber *subtractResult = [num1 decimalNumberBySubtracting:num2
withBehavior:handler];
//乘
NSDecimalNumber *multiplyResult = [num1 decimalNumberByMultiplyingBy:num2
withBehavior:handler];
//除
NSDecimalNumber *divideResult = [num1 decimalNumberByDividingBy:num2
withBehavior:handler];
//平方
NSDecimalNumber *powerResult = [num1 decimalNumberByRaisingToPower:2
withBehavior:handler];
NSLog(@"\n%f\n%f\n%f\n%f\n%f",[addResult doubleValue],[subtractResult doubleValue],[multiplyResult doubleValue],[divideResult doubleValue],[powerResult doubleValue]);
這樣就能夠很好地解決金融類app貨幣單位精確計算的問題。但有一點需要注意的是如果計算公式比較長,那么withBehavior應該在最后一步使用,切不可在計算過程中進行舍入操作,相信有點數學常識的同學都能明白這個問題。
2.2比較大小
NSDecimalNumber*discount1 = [NSDecimalNumber decimalNumberWithString:@".85"];
NSDecimalNumber*discount2 = [NSDecimalNumber decimalNumberWithString:@".9"];
NSComparisonResult result = [discount1 compare:discount2];
if (result ==NSOrderedAscending) {
NSLog(@"85%% < 90%%小于");
} else if (result == NSOrderedSame) {
NSLog(@"85%% == 90%%等于");
} else if (result ==NSOrderedDescending) {
NSLog(@"85%% > 90%%大于");
}
2.3 使用過程中注意點
- 模型接受的時候的用NSString 類型;
- 字符串轉成NSDecimalNumber的時候要判斷是否為nil;
- iOS NSDecimalNumber用法 加減乘除 解決字符串轉float類型不準確 結尾無法去0處理 用于貨幣處理