电商类应用涉及金额计算,力求精确度建议使用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函数,这样保证了输出结果是两位小数并且只舍不入。