NSDecimalNumber货币精确计算(解决价格精度问题)

在开发中使用基本的数据类型进行相关的运算或者是将字符串类型转化成数字类型总会有失精度的问题,特别是电商类的应用在进行商品合计时总会遇到失精度的问题,多次遇到很是苦恼呀自从用了NSDecimalNumber这些问题都解决了整理分享一下。

 
NSDecimalNumber是NSNumber的不可变子类。苹果针对浮点型计算时存在精度计算误差的问题而提供的一个计算类,它是基于10进制的定点计算保证了精度不会缺失。同时也可以定制精度的取正类型:向上取正、向下去正、四舍五入等。相对与浮点类型的计算,NSDecimalNumber提供了更加精准的计算。
主要解决一下问题:  
1、字符串转float等不精确问题。  
2、精确计算  
3、保留小数位数  
4、四舍五入及其它的保留小数位数规则
 
具体用法如下:
 1 NSDecimalNumber的运算 
 2 //1、字符串 -> NSDecimalNumber 
 3 NSDecimalNumber *num1 = [NSDecimalNumber decimalNumberWithString:@”123”]; 
 4 NSLog(@”num1 == %@”,num1); 
 5 //2、NSNumber -> NSDecimalNumber(基础类型的话,先转成NSNumber) 
 6 NSDecimalNumber *num2 = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithInt:123] decimalValue]]; 
 7 NSLog(@”num2 == %@”,num2);
 8  
 9 //相关运算
10 /*加 +
11 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
12 - (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;//带保留小数位数
13 */
14 NSDecimalNumber *num3 = [num1 decimalNumberByAdding:num2];
15 NSLog(@"num3 == %@",num3);
16  
17 /*减 -
18 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
19 - (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;//带保留小数位数
20 */
21 NSDecimalNumber *num4 = [num1 decimalNumberBySubtracting:num2];
22 NSLog(@"num4 == %@",num4);
23  
24 /*乘 *
25 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
26 - (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;//带保留小数位数
27 */
28 NSDecimalNumber *num5 = [num1 decimalNumberByMultiplyingBy:num2];
29 NSLog(@"num5 == %@",num5);
30  
31 /*除 \
32 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
33 - (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;//带保留小数位数
34 */
35 NSDecimalNumber *num6 = [num1 decimalNumberByDividingBy:num2];
36 NSLog(@"num6 == %@",num6);
37  
38 /*比较
39 - (NSComparisonResult)compare:(NSNumber *)decimalNumber;
40 */
41  
42 NSComparisonResult result = [num1 compare:num2];
43 NSLog(@"result == %ld",(long)result);
44  
45  
46 //保留小数及相关参数含义
47 /*保留小数
48 + (instancetype)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero;
49 */
50  
51   //1、 NSRoundingMode
52 // Rounding policies :
53 // Original
54 //    value 1.2  1.21  1.25  1.35  1.27
55 // Plain    1.2  1.2   1.3   1.4   1.3
56 // Down     1.2  1.2   1.2   1.3   1.2
57 // Up       1.2  1.3   1.3   1.4   1.3
58 // Bankers  1.2  1.2   1.2   1.4   1.3
59  
60 /* typedef NS_ENUM(NSUInteger, NSRoundingMode) {
61     NSRoundPlain,   // Round up on a tie        四舍五入
62     NSRoundDown,    // Always down == truncate  向下保留
63     NSRoundUp,      // Always up                向上保留
64     NSRoundBankers  // on a tie round so last digit is even 貌似是:
65  
66     if(四舍五入位 == 5)(四舍五入位(5)+  保留位 )%2 == 0 ? 入 : 舍 ;
67  
68     if(四舍五入位 != 5) 遵从四舍五入
69 };
70 */
71 //2、scale 保留小数个数
72 //3、其它:溢出等是否报错
73  
74 NSDecimalNumber *num_1 = [NSDecimalNumber decimalNumberWithString:@"1.2"];
75 NSDecimalNumber *num_2 = [NSDecimalNumber decimalNumberWithString:@"3.4"];
76 NSDecimalNumberHandler *handel = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundBankers scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
77  
78 NSDecimalNumber *num_3 = [num_1 decimalNumberByDividingBy:num_2 withBehavior:handel];
79 NSLog(@"num_3 == %@",num_3);
80  
81 //打印结果
82 /*
83 2015-12-11 13:26:28.269 test[32280:9906455] num1 == 123
84 2015-12-11 13:26:28.269 test[32280:9906455] num2 == 123
85 2015-12-11 13:26:28.269 test[32280:9906455] num3 == 246
86 2015-12-11 13:26:28.270 test[32280:9906455] num4 == 0
87 2015-12-11 13:26:28.270 test[32280:9906455] num5 == 15129
88 2015-12-11 13:26:28.270 test[32280:9906455] num6 == 1
89 2015-12-11 13:26:28.270 test[32280:9906455] result == 0
90 2015-12-11 13:26:28.270 test[32280:9906455] num_3 == 0.35
91 */

 

// Rounding policies :
// Original
// value 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 (特殊的四舍五入,碰到保留位数后一位的数字为5时,根据前一位的奇偶性决定。为偶时向下取正,为奇数时向上取正。如:1.25保留1为小数。5之前是2偶数向下取正1.2;1.35保留1位小数时。5之前为3奇数,向上取正1.4) 
 
typedef NS_ENUM(NSUInteger, NSRoundingMode) { 
NSRoundPlain, // Round up on a tie 
NSRoundDown, // Always down == truncate 
NSRoundUp, // Always up 
NSRoundBankers // on a tie round so last digit is even
};
//scale:保留有效小数的个数(为0的无效小数后自动过滤).
//Exactness:进度异常、Overflow:向上溢出、Underflow:向下溢出、DivideByZero:除数为0。当参数为YES出错会抛出异常,为NO时忽略异常。返回nil.
NSDecimalNumberHandler *roundUp = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundUp scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:YES];

 

 
 
 
posted @ 2016-12-21 19:27  #零下一度&  阅读(1714)  评论(0编辑  收藏  举报