Java的算术运算更加精确

4
我是一名Java开发者,正在开发一款与数学有关的Web应用程序。在进行带小数点的基本算术运算时,我经常会得到准确度不高且难以理解的结果。
以下是我的问题描述:
double a = 0.15;
double b = 0.01;
System.out.println(a - b);
// outputs 0.13999999999999999

float a = 0.15;
float b = 0.01;
System.out.println(a - b);
// outputs 0.14

float a = 0.16f;
float b = 0.01f;
System.out.println(a - b);
// outputs 0.14999999

double a = 0.16;
double b = 0.01;
System.out.println(a - b);
// outputs 0.15

两者都不太可靠,不能完全准确。是否有更精确的数字类或者应该将值四舍五入?


http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html - arun
对于1/3也不会很好用。 - Thilo
2
strictfp 仍然是浮点数,所以这并没有帮助(它只是确保所有用户得到完全相同的混乱结果)。 - Thilo
你能使用Java 7中的链接,并提供一个在BigDecimal中如何实现的示例吗? - Peter Lawrey
但主要问题是,如果有的话,strictfp降低你的精度! - Marko Topolnik
显示剩余2条评论
4个回答

6

您可以使用 BigDecimal 进行此操作。这样做虽然不美观,但是它能够正常工作:

BigDecimal a = new BigDecimal("0.15");
BigDecimal b = new BigDecimal("0.01");
System.out.println(a.subtract(b));

请确保使用字符串参数或valueOf方法来构造它们,例如:
BigDecimal x = new BigDecimal("0.15");   // This is ok
BigDecimal x = BigDecimal.valueOf(0.15); // This is also ok

而不是使用双参数,像这样:

BigDecimal x = new BigDecimal(0.15); // DON'T DO THIS

因为如果你传入一个double,你也会将double的不准确性传递到新的BigDecimal实例中。如果你传入一个字符串,BigDecimal会知道™并且做正确的事情™。


1
你应该使用 BigDecimal.valueOf(0.15),而不是 new BigDecimal(0.15) - Peter Lawrey
@PeterLawrey 没错,我漏掉了那个。我已经更新了我的答案。 - jqno
不过对于“1/3”这样的情况,它的效果并不太好。你需要使用有理数。 - Thilo
@Thilo 没错,但是OP要求的是“小数的基本算术”,而不是“有理数的基本算术” :). - jqno

2

在使用 double 时,您需要应用合理的四舍五入。如果这样做,您可以获得15位精度,在大多数情况下已经足够了。

double a = 0.15;
double b = 0.01;
System.out.printf("%.2f%n", a - b);

double a2 = 0.16;
double b2 = 0.01;
System.out.printf("%.2f%n", a2 - b2);

打印

0.14
0.15

1

BigDecimal 怎么样?

虽然对于所有的除法都不会完全准确(例如 1/3),但这并不是 JDK 的一部分,你需要使用分数,但可以像两个整数(或 BigIntegers)一样轻松实现。易于实现


0
  BigDecimal  a = new BigDecimal(".15");
  BigDecimal  b = new BigDecimal(".01"),
  BigDecimal  c = new BigDecimal(0);

  c = a.subtract(b);      
  System.out.println(c);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接