浮点数的转化遇到的坑

【浮点数的转化遇到的坑】非原创-搬运记录文章-浮点数的转化遇到的坑

由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用等号(==)判断两个小数是否相等。如何两个小数的差的绝对值很小,比如小于 0.0000001,就可以认为它们相等。
给出除了一个小数比较的方法:
bool (double num1, double num2) { if ((num1 - num2 > -0.0000001) && (num1 - num2) < 0.0000001) return true; else return false; }

iOS Objective-c 中将NSString、NSNumber转化成CGFloat会有精度丢失;
网络传输中,JSON解析数字一般是NSNumber类型,在转化成CGFloat就会造成误差,网络传输数字最好是转成字符串类型。
OC小数转化
在OC中是否也有这样的问题,于是乎我测试下,因为考虑到iOS开发时,显示的小数一般不会超过4位:
CGFloat a = 66.6; CGFloat b = 66.66; CGFloat c = 66.666; CGFloat d = 66.6666; // CGFloat 转化成 NSNumber(一般会放进NSArray, NSDictionary中) NSNumber *an = [NSNumber numberWithFloat:a]; NSNumber *bn = [NSNumber numberWithFloat:b]; NSNumber *cn = [NSNumber numberWithFloat:c]; NSNumber *dn = [NSNumber numberWithFloat:d]; // NSNumber floatValue 转化 float af = [an floatValue]; float bf = [bn floatValue]; float cf = [cn floatValue]; float df = [dn floatValue]; // NSNumber doubleValue 转化 double ab = [an doubleValue]; double bb = [bn doubleValue]; double cb = [cn doubleValue]; double db = [dn doubleValue]; // CGFloat 转化成 NSString NSString *as = [NSString stringWithFormat:@"%f", a]; NSString *bs = [NSString stringWithFormat:@"%f", b]; NSString *cs = [NSString stringWithFormat:@"%f", c]; NSString *ds = [NSString stringWithFormat:@"%f", d]; // NSString floatValue 转化 float asf =[as floatValue]; float bsf =[bs floatValue]; float csf =[cs floatValue]; float dsf =[ds floatValue]; // NSString doubleValue 转化 double asb = [as doubleValue]; double bsb = [bs doubleValue]; double csb = [cs doubleValue]; double dsb = [ds doubleValue];

打印信息:
== CGFloat 打印 a: 66.600000 b: 66.660000 c: 66.666000 d: 66.666600== NSNumber 打印 an: 66.6 bn: 66.66 cn: 66.666 dn: 66.6666== NSNumber floatValue 打印 af: 66.599998 bf: 66.660004 cf: 66.666000 df: 66.666603== NSNumber doubleValue 打印 ab: 66.599998 bb: 66.660004 cb: 66.666000 db: 66.666603== NSString 打印 as: 66.600000 bs: 66.660000 cs: 66.666000 ds: 66.666600== NSString floatValue 打印 asf: 66.599998 bsf: 66.660004 csf: 66.666000 dsf: 66.666603== NSString doubleValue 打印 asb: 66.600000 bsb: 66.660000 csb: 66.666000 dsb: 66.666600

NSString doubleValue 转化下来的小数是比较准确的。
JSON小数转化
App应用一般数据都是从接口传来的
测一测JSON传数字:
NSString *json = @"{"a":66.6, "b":66.66, "c":66.666, "d":66.6666}"; NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"%@", dict); for (NSString *key in [dict allKeys]) { id object = [dict objectForKey:key]; NSLog(@"%@: %@ - %@", key, [object class], object); float xf = [object floatValue]; double yf = [object doubleValue]; printf("nf: %f - df: %fn", xf, yf); }

打印信息:
{ a = "66.59999999999999"; b = "66.66"; c = "66.666"; d = "66.6666"; } d: __NSCFNumber - 66.6666 nf: 66.666603 - df: 66.666600b: __NSCFNumber - 66.66 nf: 66.660004 - df: 66.660000c: __NSCFNumber - 66.666 nf: 66.666000 - df: 66.666000a: __NSCFNumber - 66.59999999999999 nf: 66.599998 - df: 66.600000

JSON传字符串:
NSString *json = @"{"a":"66.6","b":"66.66","c":"66.666","d":"66.6666"}"; NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; NSLog(@"dict: %@", dict); for (NSString *key in [dict allKeys]) { id object = [dict objectForKey:key]; NSLog(@"%@: %@ - %@", key, [object class], object); float xf = [object floatValue]; double yf = [object doubleValue]; printf("nf: %f - df: %fn", xf, yf); }

输出信息:
{ a = "66.6"; b = "66.66"; c = "66.666"; d = "66.6666"; } d: NSTaggedPointerString - 66.6666 nf: 66.666603 - df: 66.666600b: NSTaggedPointerString - 66.66 nf: 66.660004 - df: 66.660000c: NSTaggedPointerString - 66.666 nf: 66.666000 - df: 66.666000a: NSTaggedPointerString - 66.6 nf: 66.599998 - df: 66.600000

最后
聪明的你应该看出:
  1. NSNumber NSString 尽量用 doubleValue 来转化, 千万不能用 floatValue。
  2. 劝后台的同事把请求返回的数据全部设置为 String 类型。
  3. 如果涉及到精确计算的问题,请用 NSDecimalNumber 对象了参考。
参考
iOS浮点数的转化遇到的坑
iOS开发可能遇到的坑——浮点数的转化显示问题

    推荐阅读