js,java,浮点数运算错误及应对方法
一,浮点数为什么会有运算错误
IEEE 754 标准规定了计算机程序设计环境中的二进制和十进制的浮点数自述的交换、算术格式以及方法.
现有存储介质都是2进制。2进制的进制基数是2,那么一个数字只要被因素包含大于2的质数的数除,都会产生无限循环小数。无限循环小数和无理数都无法,和非无限循环的有理数一起用同一种方式存储到存储介质上的同时还保持计算的兼容性。
对于无限循环小数,可以设计一种格式存储到介质上,但是同时又要和非无限循环的有理数能够计算,效率应该会变得非常低下。 对于无理数,小数位的数字没有规律可循,所以根本无法保存精确值,只能保存近似值。
高精度计算,一般可以将数字转发成string, 去掉小数点,按位计算再保存回string,再加回小数点。
二,错误举例
document.write (0.01 + 0.05); //输出结果为0.060000000000000005
document.write (0.09 + 0.01); //输出结果为0.09999999999999999
document.write(11*22.9); //输出结果为251.89999999999998
三,js如何应对
扩大倍数法:有多少位小数就扩大10的n次方
document.write((0.01*100+0.09*100)/100); //输出结果为0.1
四舍五入法:
document.write((0.01+0.09).toFixed(2)); //保留2位小数,输出结果为0.10
document.write(Math.round((0.01+0.09)*100)/100); //输出结果为0.1
四,java如何应对
扩大倍数法:有多少位小数就扩大10的n次方
System.out.println((0.01*100+0.09*100)/100); //输出结果为0.1
四舍五入法:
System.out.println(Math.rint(0.01*100+0.09*100)/100); //输出结果为0.1
System.out.println(Math.round(0.01*100+0.09*100)/100); //输出结果为0.1
System.out.println(new BigDecimal(0.099).setScale(2, RoundingMode.HALF_UP).doubleValue());
//输出结果为0.10
备注: Java支持7中舍入法
1、 ROUND_UP:远离零方向舍入。向绝对值最大的方向舍入,只要舍弃位非0即进位。
2、 ROUND_DOWN:趋向零方向舍入。向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况。
3、 ROUND_CEILING:向正无穷方向舍入。向正最大方向靠拢。若是正数,舍入行为类似于ROUND_UP,若为负数,舍入行为类似于ROUND_DOWN。Math.round()方法就是使用的此模式。
4、 ROUND_FLOOR:向负无穷方向舍入。向负无穷方向靠拢。若是正数,舍入行为类似于ROUND_DOWN;若为负数,舍入行为类似于ROUND_UP。
5、 HALF_UP:最近数字舍入(5进)。这是我们最经典的四舍五入。
6、 HALF_DOWN:最近数字舍入(5舍)。在这里5是要舍弃的。
7、 HAIL_EVEN:银行家舍入法。银行家舍入法.