iOS 处理浮点类型精度丢失问题

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的处理方案:

  1. 直接让后台返回一个字符串,用NSDecimalNumber处理计算问题;
  2. 后台传浮点类型,用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

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

  1. 处理精度有关的数据请使用double;
  2. 最好直接让后台返回字符串类型。

你可能感兴趣的:(iOS 处理浮点类型精度丢失问题)