问题描述:
在iOS开发中:涉及价格金额处理,后台有时会返回Number类型的数据,打印或者经过Json转Model后的NSString有时会出现精度丢失的问题,如果涉及到金额的加减乘除运算问题将暴露得更为明显。
代码示例:
NSArray *numbers = @[
@9,
@9.00,
@9.09,
@9.19,
@9.29,
@9.39,
@9.49,
@9.59,
@9.69,
@9.79,
@9.89,
@9.99,
@10.00,
@10,
];
for (int i = 0; i < numbers.count; i++) {
NSNumber *number = numbers[I];
NSString *newValue = [number stringValue];
NSLog(@"newValue:%@,number:%@",newValue,number);
}
我们看输出的结果可以看出来将NSNumber转换成NSSting的过程中和存储的时间可能都会出现精度丢失。
问题分析
因为浮点数在计算机中是采用IEEE规定的标准浮点格式,即二进制科学表示法。 在这种表示法中,一个数 S = M * 2 ^ N。
其中N表示阶码,M表示位数(有效数字位)。 例如一个float类型的浮点,在32bit位上,占4个字节,字节表示为
【31】N:【30 ~ 23】 M:【22~0】
a)31位表示符号位: 0正,1负
b)中间8位是阶码位: 表示范围【-128 ~ 127】,对于float类型数据规定其偏移量为127
c)后面23位是有效数字位: 因为科学计数法,整数位定死了是1,所以这里记录的是小数点后面的二进制为
指数N决定它的范围,因为M总是一个以1开头的小数,以float来说即是:-2 ^ 128 ~ 2 ^ 128,即float能表示的数的大小的范围。
而它的精度是由位数(也就是有效的数据位)来决定的, 2 ^ 23 = 8388608,总共7位,表示最多能用7位有效数字,最多能表示到.8388708即小数点后7位,由于不能完全表示全部的7位数,所以它的精度范围是6位~7位。
同理可得double的精度是2 ^ 52 = 4503599627370496, 共16位,所以精度为15 ~ 16位。
总结:
float/double类型的范围和精度的计算方式,对于高精度的计算是不合适的,存在着精度的丢失。相对于float ;double的精度更高一些在用的时间要做好取舍