iOS --NSDecimalNumber 处理计算精度不准确问题

本文介绍了一个在项目开发中遇到的double类型精度不准确的问题,并提供了解决方案——使用NSDecimalNumber进行精确计算。

前言:

       很少写知识文章或技术文章,迈出第一步勇气还是要的。加油。。。

正文:

       前几天在项目开发的时候遇到double类型精度不准确导致代码不能按正常逻辑处理,这个让我很纳闷,因为前几个版本都没有出现这类型的错。试过用NSString来处理,可是加减乘除还是要转换成基本类型,又会计算精度误差。

         问题如图下:

     

刚好有个判断逻辑是:

 if (payAmount1 + payAmount2 < [paySumAmount doubleValue]) {
        UIAlert(@"提示",@"输入的总金额不足以支付订单,请重新输入", @"确定", nil);
        return;
    }
复制代码

很尴尬,明明输入的金额满足支付,却一直被被拦住。

        为了避免偶尔性出现计算精度问题,用NSDecimalNumber 可以完美的处理。不多说上相关代码。

        1.关于NSDecimalNumber属性和方法

/*
声明:

mantissa:为基数
exponent:为幂的次方 例如 传2 相等于 10*10
flag: yes代表正数,no代表负数
return:返回对象NSDecimalNumber
*/
- (instancetype)initWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;
+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa exponent:(short)exponent isNegative:(BOOL)flag;

+ (NSDecimalNumber *)decimalNumberWithString:(nullable NSString *)numberValue;
- (NSNumber *)initWithDouble:(double)value;
- (NSNumber *)initWithFloat:(float)value;
- (NSNumber *)initWithBool:(BOOL)value;
~
~
~

@property (class, readonly, copy) NSDecimalNumber *zero;//0
@property (class, readonly, copy) NSDecimalNumber *one;//1
@property (class, readonly, copy) NSDecimalNumber *minimumDecimalNumber;//最小值
@property (class, readonly, copy) NSDecimalNumber *maximumDecimalNumber;//最大值
@property (class, readonly, copy) NSDecimalNumber *notANumber;//无值

//加法
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//减法
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberBySubtracting:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//乘法
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByMultiplyingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//除法
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber;
- (NSDecimalNumber *)decimalNumberByDividingBy:(NSDecimalNumber *)decimalNumber withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//次方
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power;
- (NSDecimalNumber *)decimalNumberByRaisingToPower:(NSUInteger)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//幂运算
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power;
- (NSDecimalNumber *)decimalNumberByMultiplyingByPowerOf10:(short)power withBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//四舍五入
- (NSDecimalNumber *)decimalNumberByRoundingAccordingToBehavior:(nullable id <NSDecimalNumberBehaviors>)behavior;

//比较2个值
- (NSComparisonResult)compare:(NSNumber *)decimalNumber;
复制代码

  2.NSDecimalNumberHandler 用法 -- 声明四舍五入规则

@property (class, readonly, strong) NSDecimalNumberHandler *defaultDecimalNumberHandler;
    // rounding mode: NSRoundPlain //默认NSRoundPlain
    // scale: No defined scale (full precision)//保留几位小数
    // ignore exactnessException (return nil) //转换异常抛出
    // raise on overflow, underflow and divide by zero.//转换异常抛出


/**
NSRoundingMode:
{
NSRoundPlain:四舍五入   2.56 ->2.6   2.44 -> 2.4
NSRoundDown:向下取值    2.56->2.5    2.44->2.4
NSRoundUp:向上取值      2.56 ->2.6   2.44->2.5
NSRoundBankers:        NSRoundPlain一样(如果大神们有其他特殊例子麻烦告诉一声)
}

scale:保留几个小数
其他:溢出异常报错 为No就可以了。
*/
- (instancetype)initWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero

+ (instancetype)decimalNumberHandlerWithRoundingMode:(NSRoundingMode)roundingMode scale:(short)scale raiseOnExactness:(BOOL)exact raiseOnOverflow:(BOOL)overflow raiseOnUnderflow:(BOOL)underflow raiseOnDivideByZero:(BOOL)divideByZero;
复制代码

    3.简单用法

  NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:position raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO];
   
  NSDecimalNumber *decimal1 = [[NSDecimalNumber alloc] initWithDouble:15.384];
  NSDecimalNumber *decimal2 = [[NSDecimalNumber alloc] initWithDouble:13.555];
 
  //加法
  NSDecimalNumber *result = [decimal1 decimalNumberByAdding:decimal2 withBehavior:roundingBehavior];//28.94

  //减法
  NSDecimalNumber *result1 = [decimal1 decimalNumberBySubtracting:decimal2 withBehavior:roundingBehavior];//1.82

   //比较
   if ([result compare:result1] ==  NSOrderedAscending) { //升序
        //result < result1
   }else if ([result compare:result1] ==  NSOrderedDescending) { //降序
        //result > result1
   }else if ([result1 compare:result1] ==  NSOrderedSame) {
        //result = result1
   }
复制代码

 结束语

边踩坑边学习.蟹蟹


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值