美文网首页
ios中精度丢失的问题

ios中精度丢失的问题

作者: guoguojianshu | 来源:发表于2019-04-04 09:06 被阅读0次

    1. 问题:

    在iOS开发中,我们经常要使用浮点类型去接收后台返回过来的的数据,这时往往会遇到精度问题,特别是在开发金融类APP的时候,例如:

    // 后台返回数据中price为71.49:  
    NSString * jsonStr = @"{\"price\":71.49}"; 
    NSData *jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding]; 
    NSDictionary *json = [NSMutableDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil]];
    NSLog(@"处理之前:%@", [json[@"price"] stringValue]);
    // 当我们用浮点类型去接收的时: price = 71.48999999999999
    

    2. 苹果提供的解决方案:NSDecimalNumber

    苹果针对浮点型计算时存在精度计算误差的问题,而提供的一个NSDecimalNumber的计算类。
    NSDecimalNumber继承于NSNumber,它可以是正(负)小数的10进制数,通过定点计算保证了精度不会缺失。
    NSDecimalNumber可以定制四种精度的取正类型分别是:向上取正、向下取正、四舍五入和特殊的四舍五入(碰到保留位数后一位的数字为5时,根据前一位的奇偶性决定。为偶时向下取正,为奇数时向上取正如:1.25保留1为小数。5之前是2偶数向下取正1.2;1.35保留1位小数时。5之前为3奇数,向上取正1.4)。
    相对与浮点类型的计算,NSDecimalNumber提供了更加精准的计算。

    3. 居于NSDecimalNumber的处理方案:

    直接让后台返回一个字符串,用NSDecimalNumber处理计算问题;
    后台传浮点类型,用NSDecimalNumber处理精度丢失问题。

    这里我直接使用一个继承于NSObjec的工具类LSLDecimalNumberTool来处理,实现如下:

    @implementation LSLDecimalNumberTool
    
    + (float)floatWithdecimalNumber:(double)num {
        return [[self decimalNumber:num] floatValue];
    }
    
    + (double)doubleWithdecimalNumber:(double)num {
        return [[self decimalNumber:num] doubleValue];
    }
    
    + (NSString *)stringWithDecimalNumber:(double)num {
        return [[self decimalNumber:num] stringValue];
    }
    
    + (NSDecimalNumber *)decimalNumber:(double)num {
        NSString *numString = [NSString stringWithFormat:@"%lf", num];
        return [NSDecimalNumber decimalNumberWithString:numString];
    }
    
    @end
    
    • 接着上面的代码,使用NSDecimalNumber来处理之后的数据:
    NSLog(@"------------------");
    NSString *priceStr = [LSLDecimalNumberTool stringWithDecimalNumber:[json[@"price"] doubleValue]];
    NSLog(@"处理之后:%@", priceStr);
    
    • 运行结果:
    // 运行结果:
    2017-09-01 23:32:20.340917+0800 DecimalNumberDemo[4006:1155999] 处理之前:71.48999999999999
    2017-09-01 23:32:20.340977+0800 DecimalNumberDemo[4006:1155999] ------------------
    2017-09-01 23:32:20.341049+0800 DecimalNumberDemo[4006:1155999] 处理之后:71.49
    

    最后在处理精度问题时,建议两点:

    处理精度有关的数据请使用double,然后使用NSDecimalNumber包装一层;
    最好直接让后台返回字符串类型。

    相关文章

      网友评论

          本文标题:ios中精度丢失的问题

          本文链接:https://www.haomeiwen.com/subject/ixixiqtx.html