Java中使用BigDecimal进行浮点数运算
最近研究了一下java的浮点数计算问题,从网上查询了相关的资料,汇总并经过了一些整理和调试,最后完成此文,欢迎大家指出其中的错误和问题。
在java中,float声明的变量是单精度浮点数,double声明的变量是双精度浮点数,顾名思义就是double型的实体占用内存空间是float的两倍。float是4个字节而double是8个字节。float和double类型的数据,无法精确表示计算结果,这是由于float和double是不精确的计算。大家可以通过下面代码可以看出来:
public class test
{
public static void main(string[] args)
{
system.out.println(0.05 + 0.01);
system.out.println(1.0 - 0.42);
system.out.println(4.015 * 100);
system.out.println(123.3 / 100);
}
}
运行的结果为:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
要想获得理想的效果,我们可以尝试使用java.text.decimalformat格式化浮点数:
decimalformat可以按照一定的格式格式化数字,常用的格式化字符是#、0等。例:
system.out.println(new java.text.decimalformat("0.00").format(3.125));
system.out.println(new java.text.decimalformat("0.00").format(3.135));
但是得到的结果是:
3.12
3.14
这是因为decimalformat是使用half-even 舍入(round_half_even),简单的说就是向当四舍五入的5的时候向最近的偶数靠。所以使用decimalforamt也无法得到可靠的浮点数。最后我们可以考虑使用bigdecimal来获得更精确的计算:
bigdecimal提供了多个构造函数,和浮点数有关的有:
bigdecimal(double val) translates a double into a bigdecimal.
bigdecimal(string val) translates the string repre sentation of a bigdecimal into a bigdecimal.
但是用double参数来创建对象得到不精确的值,只有通过string来创建对象才是最准确的。
例如:
bigdecimal bd1=new bigdecimal(0.05);
system.out.println(bd1.tostring());
bigdecimal bd2=new bigdecimal("0.05");
system.out.println(bd2.tostring());
得到结果:
0.05000000000000000277555756156289135105907917022705078125
0.05
所以,我们最终需要使用string来创建对象,这样得到的结果才是最精确的。另外,如果是double数,我们还可以使用:bigdecimal.valueof(double val),原因很简单,其jdk源码如下所示:
public static bigdecimal valueof(double val)
{
return new bigdecimal(double.tostring(val));
}
最后需要说明的是:bigdecimal的加减乘除其实最终都返回的是一个新的bigdecimal对象,因为bigdecimal是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以a.add(b);虽然做了加法操作,但是a并没有保存加操作后的值,正确的用法应该是a=a.add(b)。
推荐阅读
-
Java中使用BigDecimal进行浮点数运算
-
Java使用BigDecimal进行高精度计算的示例代码
-
Java中BigDecimal的基本运算(详解)
-
使用BigDecimal进行精确运算(实现加减乘除运算)
-
java三目运算符中使用trim()中“ “.trim()==““竟然是false;
-
在AIX Version 5.3中使用Java和PHP技术进行开发,第1部分:设置Java环境
-
java中使用cglib中的BeanCopier类进行bean的复制
-
使用flex中的httpservice方法与java进行交互
-
[转]java中byte转换int时为何与0xff进行与运算
-
[转]java中byte转换int时为何与0xff进行与运算