前几天看了一个朋友的博客,说Java中浮点数运算精度丢失的问题,他给出了问题,也指出了C语言相对于Java的优势,其实,Java中也是可以解决浮点运算精度丢失问题的。
那就是:BigDecimal。
先看一段程序:
public class DoubleTest { public static void main(String args[]) { System.out.println("0.05 + 0.01 = " + (0.05 + 0.01)); System.out.println("1.0 - 0.42 = " + (1.0 - 0.42)); System.out.println("4.015 * 100 = " + (4.015 * 100)); System.out.println("123.3 / 100 = " + (123.3 / 100)); } }
上面的程序运行结果是:
上面程序运行结果表明,Java的double类型会发生精度丢失问题,其实,不尽是Java,很多编程语言都存在这样的问题。
为了能精确的表示、计算浮点数,Java提供了BigDecimal类,该类提供了大量的构造器用于创建BigDecimal对象,包括把所有的基本类型转换层一个BigDecimal对象,也包括利用数字字符串、数字字符数组来创建BigDecimal对象。详细介绍请查阅API手册。
双精度浮点型变量 double 可以处理 16 位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。 Java 在 java.math 包中提 供的 API 类 BigDecimal ,用来对超过 16 位有效位的数进行精确的运算。表 5.7 中列出了 BigDecimal 类的主要构造器和方法。
构造器描述 :
BigDecimal(int) 创建一个具有参数所指定整数值的对象。
BigDecimal(double) 创建一个具有参数所指定双精度值的对象。
BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。
方法描述 :
add(BigDecimal)BigDecimal 对象中的值相加,然后返回这个对象。
subtract(BigDecimal)BigDecimal 对象中的值相减,然后返回这个对象。
multiply(BigDecimal)BigDecimal 对象中的值相乘,然后返回这个对象。
divide(BigDecimal)BigDecimal 对象中的值相除,然后返回这个对象。
toString() 将 BigDecimal 对象的数值转换成字符串。
doubleValue() 将 BigDecimal 对象中的值以双精度数返回。
示例程序:
public class BigDecimalTest { public static void main(String[] args) { BigDecimal f1 = new BigDecimal("0.05"); BigDecimal f2 = BigDecimal.valueOf(0.01); BigDecimal f3 = new BigDecimal(0.05); System.out.println("使用String作为BigDecimal构造器参数:"); System.out.println("0.05 + 0.01 = " + f1.add(f2)); System.out.println("0.05 - 0.01 = " + f1.subtract(f2)); System.out.println("0.05 * 0.01 = " + f1.multiply(f2)); System.out.println("0.05 / 0.01 = " + f1.divide(f2)); System.out.println("使用double作为BigDecimal构造器参数:"); System.out.println("0.05 + 0.01 = " + f3.add(f2)); System.out.println("0.05 - 0.01 = " + f3.subtract(f2)); System.out.println("0.05 * 0.01 = " + f3.multiply(f2)); System.out.println("0.05 / 0.01 = " + f3.divide(f2)); } }
程序运行结果:
从上面的运行结果可以看出,BigDecimal进行算术运算的效果,而且,在创建BigDecimal对象时,一定要使用String对象作为构造器参数,而不是直接使用double数字。
API手册中是这样解释的:
注:
public BigDecimal(double val)
- 此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double (或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样, 传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
- 另一方面, String 构造方法是完全可预知的:写入 new BigDecimal("0.1") 将创建一个 BigDecimal ,它 正好 等于预期的 0.1。因此,比较而言,通常建议优先使用 String 构造方法 。
- 当 double 必须用作 BigDecimal 的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用
Double.toString(double)
方法,然后使用BigDecimal(String)
构造方法,将 double 转换为 String 。要获取该结果,请使用 staticvalueOf(double)
方法。
http://www.tuicool.com/articles/nAFr6r