iOS开发知识点收集

iOS 价格浮点型计算类NSDecimalNumber详解

2020-05-12  本文已影响0人  不会写代码的尬先生

电商类应用涉及金额计算,力求精确度建议使用NSDecimalNumber计算价格。
一、浮点类数据解析
使用Model解析JSON时建议使用NSDecimalNumber类或double类型接收浮点小数类型。如用NSString或float接收数据转换时会出现把2解析成1.999999999这种样式的风险。我的处理是使用NSDecimalNumber解析浮点类型数据并给NSDecimalNumber增加分类转换成double再格式化数据并过滤空数据。

#import "NSDecimalNumber+safeNumber.h"

@implementation NSDecimalNumber (safeNumber)

+ (NSDecimalNumber *)lg_safeNumberWithFormat:(NSDecimalNumber *)object {//格式化空数据
    if (object == nil || [object isEqual:[NSNull null]]) {
        return [[NSDecimalNumber alloc] initWithInt:0];
    }
    double conversionValue = [object doubleValue];
    NSString *doubleString = [NSString stringWithFormat:@"%lf", conversionValue];
    NSDecimalNumber *decNumber = [NSDecimalNumber decimalNumberWithString:doubleString];
    return decNumber;
}

@end

二、浮点类型数据的加减乘除
1、NSDecimalNumberHandler对象
用来设置NSDecimalNumber计算时的精确位数、四舍五入的类型、溢出或除于零等情况的异常处理设置。
下面这个设置表示只舍不入并且保留两位小数

    NSDecimalNumberHandler *handel = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];

(1) NSRoundingMode属性

// 不同NSRoundingMode 下四舍五入例子
//  原始数据 1.2  1.21  1.25  1.35  1.27
// Plain         1.2  1.2   1.3   1.4   1.3
// Down       1.2  1.2   1.2   1.3   1.2
// Up           1.2  1.3   1.3   1.4   1.3
// Bankers  1.2  1.2   1.2   1.4   1.3

typedef NS_ENUM(NSUInteger, NSRoundingMode) {
    NSRoundPlain,   // 四舍五入
    NSRoundDown,    // 只舍不入
    NSRoundUp,      // 只入不舍
    NSRoundBankers  // 也是四舍五入,但是和NSRoundPlain不一样,如果精确的那位是5,要看他精确度的前一位是偶数还是奇数,如果是奇数则入,偶数则舍,例如scale=1,表示精确到小数点后一位, NSDecimalNumber 为1.45时,NSRoundPlain结果为1.5,而NSRoundBankers则是1.4。如果精确的那位是除5外的其他数字和NSRoundPlain规则相同。

(2)scale属性表示精确到小数点后几位,并且NSRoundingMode影响的也是scale位。
(3)raiseOnExactness/raiseOnOverflow/raiseOnUnderflow/raiseOnDivideByZero等属性分别表示数据精确/上溢/下溢/除以零时是否以异常处理,一般情况下都设置为NO。

2、使用NSDecimalNumber来进行加减乘除

    NSDecimalNumberHandler *handel = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundDown scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];//只舍不如 保留两位小数
    NSDecimalNumber *number1 = [[NSDecimalNumber alloc] initWithDouble:0.435];
    NSDecimalNumber *number2 = [[NSDecimalNumber alloc] initWithDouble:100];
    NSDecimalNumber *number3 = [[NSDecimalNumber alloc] initWithDouble:1.23];
    NSDecimalNumber *number4 = [[NSDecimalNumber alloc] initWithDouble:0.699];
    NSDecimalNumber *number5 = [[NSDecimalNumber alloc] initWithDouble:6.2];

    number1 = [number1 decimalNumberByAdding:number2];//number1加number2
    NSLog(@"number1加number2 = %@",number1);
    number1 = [number1 decimalNumberBySubtracting:number3];//number1减number3
    NSLog(@"number1减number3 = %@",number1);
    number1 = [number1 decimalNumberByMultiplyingBy:number4];//number1乘number4
    NSLog(@"number1乘number4 = %@",number1);
    number1 = [number1 decimalNumberByDividingBy:number5 withBehavior:handel];//number1除number5
    NSLog(@"number1除number5 = %@",number1);

打印如下
2020-05-12 15:58:21.584710+0800[8541:960582] number1加number2 = 100.435
2020-05-12 15:58:21.584895+0800[8541:960582] number1减number3 = 99.205
2020-05-12 15:58:21.585067+0800[8541:960582] number1乘number4 = 69.344294999999989841408
2020-05-12 15:58:21.585198+0800[8541:960582] number1除number5 = 11.18

可以看到我们在最后一步使用了withBehavior函数,这样保证了输出结果是两位小数并且只舍不入。

上一篇 下一篇

猜你喜欢

热点阅读