涉及到金额时的计算往往要求保留很高的精度,NSDecimalNumber很好的解决了这个问题,而你不需要再没次都想办法将float或者int型的数值转化为double了
一、问题引出
float a = 0.01;
int b = 99999999;
double c = 0.0;
c = a*b;
NSLog(@"%f",c); //输出结果为 1000000.000000
NSLog(@"%.2f",c); //输出结果为 1000000.00
//明显不够精确
如果我们刚开始都是用的double类型的数值,那是没有问题的
double a = 0.01;
double b = 99999999;
double c = 0.0;
c = a*b;
NSLog(@"%f",c); //输出结果为 999999.990000
NSLog(@"%.2f",c); //输出结果为 999999.99
//这就对了
但是从float或者int型转为double时会出问题
float a = 0.01;
int b = 999999999;
double c = 0.0;
NSLog(@"%f",a*(double)b); //9999999.766483
//精度丢失
通过转化为字符串
NSString *objA = [NSString stringWithFormat:@"%.2f", a];
NSString *objB = [NSString stringWithFormat:@"%.2f", (double)b];
c = [objA doubleValue] * [objB doubleValue];
NSLog(@"%.2f",c); //输出结果 999999.99
二、NSDecimalNumber的使用
NSDecimalNumber *price1 = [NSDecimalNumber decimalNumberWithString:@"15.99"];
NSDecimalNumber *price2 = [NSDecimalNumber decimalNumberWithString:@"29.99"];
NSDecimalNumber *coupon = [NSDecimalNumber decimalNumberWithString:@"5.00"];
NSDecimalNumber *discount = [NSDecimalNumber decimalNumberWithString:@".90"];
NSDecimalNumber *numProducts = [NSDecimalNumber decimalNumberWithString:@"2.0"];
//加法
NSDecimalNumber *subtotal = [price1 decimalNumberByAdding:price2];
//减法
NSDecimalNumber *afterCoupon = [subtotal decimalNumberBySubtracting:coupon];
//乘法
NSDecimalNumber *afterDiscount = [afterCoupon decimalNumberByMultiplyingBy:discount];
//除法
NSDecimalNumber *average = [afterDiscount decimalNumberByDividingBy:numProducts];
//乘方(忘了是不是该这么叫了😂)
NSDecimalNumber *averageSquared = [average decimalNumberByRaisingToPower:2];
NSLog(@"Subtotal: %@", subtotal); // 45.98
NSLog(@"After coupon: %@", afterCoupon); // 40.98
NSLog((@"After discount: %@"), afterDiscount); // 36.882
NSLog(@"Average price per product: %@", average); // 18.441
NSLog(@"Average price squared: %@", averageSquared); // 340.070481
三、Rounding Behavior(不知道怎么翻译,环绕的行为,应该就是末尾处理吧)
Original | 1.2 | 1.21 | 1.25 | 1.35 | 1.27 |
---|---|---|---|---|---|
NSRoundPlain | 1.2 | 1.2 | 1.3 | 1.4 | 1.3 |
NSRoundDown | 1.2 | 1.2 | 1.2 | 1.3 | 1.2 |
NSRoundUp | 1.2 | 1.3 | 1.3 | 1.4 | 1.3 |
NSRoundBankers | 1.2 | 1.2 | 1.2 | 1.4 | 1.3 |
- NSRoundPlain:默认四舍五入
- NSRoundDown:向下保留
- NSRoundUp:向上保留
- NSRoundBankers:如果末尾不是5则按照四舍五入,如果末尾是5,那么末尾5加上倒数第二位,如果和为偶数则进一如果为奇数则舍去
NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler
decimalNumberHandlerWithRoundingMode:NSRoundUp
scale:2
raiseOnExactness:NO
raiseOnOverflow:NO
raiseOnUnderflow:NO
raiseOnDivideByZero:YES];
- RoundingMode:尾数保留策略
- scale:保留几位小数
- raiseOnExactness:精度异常错误是否抛出异常
- raiseOnOverflow:溢出异常错误是否抛出异常
- raiseOnUnderflow:不足异常错误是否抛出异常
- raiseOnDivideByZero:除以0的异常
这里我们只抛出了除以0的异常,为什么其他三个异常不抛出呢,这是因为我看了好多文章人家都是没有抛出前三个异常,而我自己又没有都试试,总结起来就是:懒😂
NSDecimalNumber *subtotal = [NSDecimalNumber decimalNumberWithString:@"40.98"];
NSDecimalNumber *discount = [NSDecimalNumber decimalNumberWithString:@".90"];
NSDecimalNumber *total = [subtotal decimalNumberByMultiplyingBy:discount
withBehavior:roundUp];
NSLog(@"Rounded total: %@", total);
40.98 * 0.9 = 36.882,我们选择了向上保留,所以结果为36.89
四、Comparing NSDecimalNumbers
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%%大于");
}
- Ascending: 升高,就是前边小后边大
这里很多内容都是照抄原文的,在这里向文章作者“梨花落雨”表示感谢,更多内容请参考原文,原文讲解的更加全面
原文地址:<https: www.jianshu.com="" p="" 25d24a184016="">
资源:<http: ios.eezytutorials.com="" nsdecimalnumber-by-example.php=""></http:></https:>
网友评论