1、介绍
2、格式化浮点数
3、java.math.BigDecimal
1、介绍
在Java中float和double类型的数据,无法精确表示计算结果。这是由于float和double是不精确的计算。
例:
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);
System.out.println(0.05);
得到如下结果:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
如何实现浮点数字的精确计算,下面从2个方面讨论,一是从四舍五入,二是从使用BigDecimal工具类来实现精确计算。
2、格式化浮点数
1)Math.round()
Math类中的round方法实现的四舍五入无法精确到小数,如果经过×100的计算后再四舍五入还是没有办法保证得到精确的结果。
2)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也无法得到可靠的浮点数。
3、java.math.BigDecimal
BigDecimal提供的一个不变的、任意精度的有符号十进制数对象,可以用它来实现浮点数的精确计算。
1)构造函数说明
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数,可以先转为String
2)基本计算
利用BigDecimal的
add
加法
subtract
减法
multiply
乘法
divide
除法
setscale
四舍五入
下面程序说明基本计算的方法
//以下代码使用java.math.BigDecimal来实现浮点数的精确计算
//+
BigDecimal bd3=new BigDecimal(String.valueOf(0.05));
BigDecimal bd4=new BigDecimal(String.valueOf(0.01));
System.out.println((bd3.add(bd4)).doubleValue());
//-
BigDecimal bd5=new BigDecimal(String.valueOf(0.05));
BigDecimal bd6=new BigDecimal(String.valueOf(0.01));
System.out.println((bd5.subtract(bd6)).doubleValue());
//*
BigDecimal bd7=new BigDecimal(String.valueOf(0.05));
BigDecimal bd8=new BigDecimal(String.valueOf(0.01));
System.out.println((bd7.multiply(bd8)).doubleValue());
///这里没有考虑数据错误的可能情况
//定义了精确位数
int scale=10;
BigDecimal bd9=new BigDecimal(String.valueOf(0.05));
BigDecimal bd10=new BigDecimal(String.valueOf(0.03));
System.out.println((bd9.divide(bd10,scale,BigDecimal.ROUND_HALF_EVEN)).doubleValue());
//四舍五入
scale=4;
BigDecimal bd11=new BigDecimal(String.valueOf(3.1415926));
System.out.println(bd11.setScale(scale,BigDecimal.ROUND_HALF_DOWN).toString());
在程序中多次用到了BigDecimal的精确模式这个参数,下面说明如下:
ROUND_CEILING
Rounding mode to round towards positive infinity.
向正无穷方向舍入
ROUND_DOWN
Rounding mode to round towards zero.
向零方向舍入
ROUND_FLOORRounding mode to round towards negative infinity.
向负无穷方向舍入
ROUND_HALF_DOWN
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
ROUND_HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP ,如果是偶数,使用ROUND_HALF_DOWN
ROUND_HALF_UP
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6
ROUND_UNNECESSARYRounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
计算结果是精确的,不需要舍入模式
ROUND_UP
Rounding mode to round away from zero.
向远离0的方向舍入
下面是本文的示例代码:
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
);
System.out.println(
0.05
);
//
可以利用DecimalFormat类来格式化浮点数,但是得到的结果也有可能是错误的值
System.out.println(
new
java.text.DecimalFormat(
"
0.00
"
).format(
3.125
));
System.out.println(
new
java.text.DecimalFormat(
"
0.00
"
).format(
3.135
));
//
以下代码是java.math.BigDecimal的构造函数
BigDecimal bd1
=
new
BigDecimal(
0.05
);
System.out.println(bd1.toString());
BigDecimal bd2
=
new
BigDecimal(
"
0.05
"
);
System.out.println(bd2.toString());
//
以下代码使用java.math.BigDecimal来实现浮点数的精确计算
//
+
BigDecimal bd3
=
new
BigDecimal(String.valueOf(
0.05
));
BigDecimal bd4
=
new
BigDecimal(String.valueOf(
0.01
));
System.out.println((bd3.add(bd4)).doubleValue());
//
-
BigDecimal bd5
=
new
BigDecimal(String.valueOf(
0.05
));
BigDecimal bd6
=
new
BigDecimal(String.valueOf(
0.01
));
System.out.println((bd5.subtract(bd6)).doubleValue());
//
*
BigDecimal bd7
=
new
BigDecimal(String.valueOf(
0.05
));
BigDecimal bd8
=
new
BigDecimal(String.valueOf(
0.01
));
System.out.println((bd7.multiply(bd8)).doubleValue());
//
/这里没有考虑数据错误的可能情况
//
定义了精确位数
int
scale
=
10
;
BigDecimal bd9
=
new
BigDecimal(String.valueOf(
0.05
));
BigDecimal bd10
=
new
BigDecimal(String.valueOf(
0.03
));
System.out.println((bd9.divide(bd10,scale,BigDecimal.ROUND_HALF_EVEN)).doubleValue());
//
四舍五入
scale
=
4
;
BigDecimal bd11
=
new
BigDecimal(String.valueOf(
3.1415926
));
System.out.println(bd11.setScale(scale,BigDecimal.ROUND_HALF_UP).toString());
得到的结果:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999
0.05
3.12
3.14
0.05000000000000000277555756156289135105907917022705078125
0.05
0.06
0.04
5.0E-4
1.6666666667
3.1416