关于浮点数精度问题我们首先引入一个案例,如下:
NSInteger index = (NSInteger)(2.6 / 0.2);
请问结果是多少? 13吗?恭喜你,打错了,正确答案是12.其实理解这个问题不难,只是在开发的过程很容被忽略从导致程序运行出现bug.
分析问题的原因:
几乎所有的编程语言都采用了 IEEE-745 浮点数表示法,任何使用二进制浮点数的编程语言都会有这个问题. 数字是 64 位双精度浮点数。IEEE-745规范定义了浮点数的格式,对于64位的浮点数在内存中的表示,最高的1位是符号位,接着的11位是指数,剩下的52位为有效数字,具体:
-
第0位:符号位, s 表示 ,0表示正数,1表示负数;
-
第1位到第11位:储存指数部分, e 表示 ;
-
第12位到第63位:储存小数部分(即有效数字),f 表示
比如在 JavaScript 中计算 0.1 + 0.2时,到底发生了什么呢? 首先,十进制的0.1和0.2都会被转换成二进制,但由于浮点数用二进制表达时是无穷的,例如。
1 |
|
IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以两者相加之后得到二进制为
1 |
|
因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了 0.30000000000000004。所以在进行算术计算时会产生误差。
解决办法
其实OC中使用NSDecimalNumber可以很简单的避免这个问题, 例如:
NSDecimalNumber *one = [NSDecimalNumber decimalNumberWithString:@"2.6"];
NSDecimalNumber *two = [NSDecimalNumber decimalNumberWithString:@"0.2"];
NSDecimalNumber *result = [one decimalNumberByDividingBy:two];
NSLog(@"%@",result.stringValue);
另外
如果是一些简单的需求, 可以参照一下
1、浮点数的四舍五入:
1 |
|
2、浮点数取整(舍弃后面的小数部分):
1 |
|
3、浮点数向下取整:
1 |
|
4、浮点数向上取整:
1 |
|