一直以来都没有机会做非常需要精确计算的项目,所以对常用的浮点数计算没什么经验。刚看书时发现一个有趣的现象,特写出来与大家分享,可能有些高手会觉得小儿科,但我希望不知道的朋友多注意下。
demo1:
大家运行出来結果应该是3.0199999999999996,而不是3.02.其实代码都没错,只是计算机存储浮点数时是用二进制的,所有的数都保存为以2的N次方。0.5很好表示(2的-1次方),但0.1就没那么好精确了。
有兴趣的朋友可以看一下1.01, 2.01,1.01+2.01, 3.02 的二进制表示有什么区别,你会发现3.02和1.01+2.01的最后一个bit不同。
说了这么多怎么解决精确计算呢?其实java为我们提供了Decimal类与BigDecimal类就是来解决精确计算的,当然精确计算肯定会相对计算慢一些,但如果你要精确计算,你自己权衡一下是要精确还是要性能。
demo2:
其实結果为
现在我们把输出結果的地方加DecimalFormat类格式化一下。
demo 3:
输出結果为:
結果似乎正确了,其实还没有,请看下一个。
demo4:
输出結果为:24.20,不是24.21。
要想得到24.21的精确結果,推荐使用BigDecimal提供更大的或更小的数进行运算。
demo5:
这样就对了。
看到资料上说BigDecimal推荐使用String类型来初始化构造函数,这样可以避免一些莫名其妙的异常错误。具体原因也提供了一些例子,我这里就不写了。
现在不知道在开源包中有没有进行精确计算的工具,要是哪位朋友知道有的话告诉其他朋友一下。
demo1:
public static void demo1() {
double a = 1.01;
double b = 2.01;
System.out.println(a + b);
System.out.println();
}
大家运行出来結果应该是3.0199999999999996,而不是3.02.其实代码都没错,只是计算机存储浮点数时是用二进制的,所有的数都保存为以2的N次方。0.5很好表示(2的-1次方),但0.1就没那么好精确了。
有兴趣的朋友可以看一下1.01, 2.01,1.01+2.01, 3.02 的二进制表示有什么区别,你会发现3.02和1.01+2.01的最后一个bit不同。
说了这么多怎么解决精确计算呢?其实java为我们提供了Decimal类与BigDecimal类就是来解决精确计算的,当然精确计算肯定会相对计算慢一些,但如果你要精确计算,你自己权衡一下是要精确还是要性能。
demo2:
public static void demo2() {
double area;
for (int i = 1; i < 10; i++) {
area = 3.14 * i * i;
System.out.println("圆的半径为" + i + ", 其面积为" + area);
}
System.out.println();
}
其实結果为
圆的半径为1, 其面积为3.14
圆的半径为2, 其面积为12.56
圆的半径为3, 其面积为28.259999999999998
圆的半径为4, 其面积为50.24
圆的半径为5, 其面积为78.5
圆的半径为6, 其面积为113.03999999999999
圆的半径为7, 其面积为153.86
圆的半径为8, 其面积为200.96
圆的半径为9, 其面积为254.34
现在我们把输出結果的地方加DecimalFormat类格式化一下。
demo 3:
public static void demo3() {
double area;
DecimalFormat df = new DecimalFormat("#.000");
for (int i = 1; i < 10; i++) {
area = 3.14 * i * i;
System.out.println("圆的半径为" + i + ", 其面积为" + df.format(area));
}
System.out.println();
}
输出結果为:
圆的半径为1, 其面积为3.140
圆的半径为2, 其面积为12.560
圆的半径为3, 其面积为28.260
圆的半径为4, 其面积为50.240
圆的半径为5, 其面积为78.500
圆的半径为6, 其面积为113.040
圆的半径为7, 其面积为153.860
圆的半径为8, 其面积为200.960
圆的半径为9, 其面积为254.340
結果似乎正确了,其实还没有,请看下一个。
demo4:
public static void demo4() {
double area = 24.205;
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(area));
System.out.println();
}
输出結果为:24.20,不是24.21。
要想得到24.21的精确結果,推荐使用BigDecimal提供更大的或更小的数进行运算。
demo5:
public static void demo5() {
double area = 24.205;
BigDecimal bd = new BigDecimal(Double.toString(area));
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(bd.doubleValue());
System.out.println();
}
这样就对了。
看到资料上说BigDecimal推荐使用String类型来初始化构造函数,这样可以避免一些莫名其妙的异常错误。具体原因也提供了一些例子,我这里就不写了。
现在不知道在开源包中有没有进行精确计算的工具,要是哪位朋友知道有的话告诉其他朋友一下。