刚从书上学到的一个小点:Java中的精确计算

一直以来都没有机会做非常需要精确计算的项目,所以对常用的浮点数计算没什么经验。刚看书时发现一个有趣的现象,特写出来与大家分享,可能有些高手会觉得小儿科,但我希望不知道的朋友多注意下。

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类型来初始化构造函数,这样可以避免一些莫名其妙的异常错误。具体原因也提供了一些例子,我这里就不写了。

现在不知道在开源包中有没有进行精确计算的工具,要是哪位朋友知道有的话告诉其他朋友一下。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值