金融类app各种数值的精确计算问题

参考: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

参数和说明:

  1. roundingMode:要使用的舍入模式,有四种值: NSRoundUp, NSRoundDown, NSRoundPlain, and NSRoundBankers
  2. scale:结果保留几位小数
  3. 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 使用过程中注意点
  1. 模型接受的时候的用NSString 类型;
  2. 字符串转成NSDecimalNumber的时候要判断是否为nil;
  3. iOS NSDecimalNumber用法 加减乘除 解决字符串转float类型不准确 结尾无法去0处理 用于货币处理

你可能感兴趣的:(金融类app各种数值的精确计算问题)