前几天看了一个朋友的博客,说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));
}
}
上面的程序运行结果是:

< http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+yc/D5rPM0PLUy9DQveG5+7Htw/ejrEphdmG1xGRvdWJsZcDg0M274beiyfq+q7bItqrKp87KzOKjrMbkyrWjrLK7vqHKx0phdmGjrLrctuCx4LPM0+/R1La8tObU2tXi0fm1xM7KzOKhozwvcD4KPHA+zqrBy8TcvqvIt7XEse3KvqGivMbL47ihtePK/aOsSmF2YczhuanBy0JpZ0RlY2ltYWzA4KOsuMPA4MzhuanBy7Tzwb+1xLm51OzG99PD09q0tL2oQmlnRGVjaW1hbLbUz/OjrLD8wKiw0cv509C1xLv5sb7A4NDN16q7u7Lj0ru49kJpZ0RlY2ltYWy21M/zo6zSsrD8wKjA+9PDyv3X1tfWt/u0rqGiyv3X1tfWt/vK/dfpwLS0tL2oQmlnRGVjaW1hbLbUz/Oho8/qz7i96cncx+uy6dTEQVBJytay4aGjPC9wPgo8cD48L3A+CjxwPgrLq76rtsi4obXj0M2x5MG/ZG91Ymxlv8nS1LSmwO0xNs6709DQp8r9oaPU2sq1vMrTptPD1tCjrNDo0qq21Lj8tPO78tXfuPzQobXEyv29+NDQ1MvL47rNtKbA7aGjSmF2YdTaamF2YS5tYXRosPzW0MzhIDx3YnI+uam1xEFQScDgQmlnRGVjaW1hbKOs08PAtLbUs6y5/TE2zrvT0NCnzru1xMr9vfjQ0L6ryLe1xNTLy+Oho7HtNS431tDB0LP2wctCaWdEZWNpbWFswOC1xNb30qq5udTsxve6zbe9t6ihozwvcD4KPHA+Cjxicj4KPC9wPgo8cD4KubnU7Mb3w+jK9iCjujx3YnI+PGJyPgpCaWdEZWNpbWFsKGludCm0tL2o0ru49r7f09Cyzsr9y/nWuLao1fvK/SYjMjA1NDA7tcS21M/zoaMgPHdicj48YnI+CkJpZ0RlY2ltYWwoZG91YmxlKbS0vajSu7j2vt/T0LLOyv3L+da4tqjLq76rtsgmIzIwNTQwO7XEttTP86GjIDx3YnI+PGJyPgpCaWdEZWNpbWFsKGxvbmcptLS9qNK7uPa+39PQss7K/cv51ri2qLOk1fvK/SYjMjA1NDA7tcS21M/zoaMgPHdicj48YnI+CkJpZ0RlY2ltYWwoU3RyaW5nKbS0vajSu7j2vt/T0LLOyv3L+da4tqjS1NfWt/u0rrHtyr61xMr9JiMyMDU0MDu1xLbUz/OhozwvcD4KPHA+Cjxicj4KPC9wPgo8cD4Kt723qMPoyvYgo7o8d2JyPjxicj4KYWRkKEJpZ0RlY2ltYWwpQmlnRGVjaW1hbLbUz/PW0LXEJiMyMDU0MDvP4LzTo6zIu7rzt7W72NXiuPa21M/zoaMgPHdicj48YnI+CnN1YnRyYWN0KEJpZ0RlY2ltYWwpQmlnRGVjaW1hbLbUz/PW0LXEJiMyMDU0MDvP4Lz1o6zIu7rzt7W72NXiuPa21M/zoaMgPHdicj48YnI+Cm11bHRpcGx5KEJpZ0RlY2ltYWwpQmlnRGVjaW1hbLbUz/PW0LXEJiMyMDU0MDvP4LPLo6zIu7rzt7W72NXiuPa21M/zoaMgPHdicj48YnI+CmRpdmlkZShCaWdEZWNpbWFsKUJpZ0RlY2ltYWy21M/z1tC1xCYjMjA1NDA7z+Cz/aOsyLu687e1u9jV4rj2ttTP86GjIDx3YnI+PGJyPgp0b1N0cmluZygpvatCaWdEZWNpbWFsttTP87XEyv0mIzIwNTQwO9equ7uzydfWt/u0rqGjIDx3YnI+PGJyPgpkb3VibGVWYWx1ZSgpvatCaWdEZWNpbWFsttTP89bQtcQmIzIwNTQwO9LUy6u+q7bIyv23tbvYoaM8L3A+CjxwPsq+wP2zzNDyo7o8L3A+CjxwPjxwcmUgY2xhc3M9"brush:java;">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。要获取该结果,请使用
static
valueOf(double) 方法。