修复了没有 BigDecimal 的浮点精度问题

Fix for float precision issue without BigDecimal

提问人:wvp 提问时间:8/6/2013 更新时间:8/6/2013 访问量:656

问:

我在对浮点值的舍入有疑问。

以下代码为我提供了以下结果:

public class ProductOrder {

  public static void main(String[] args) {
    int q = 48;
    float p = 6.95f;

    System.out.println(q * p);
  }

------
Output: 333.59998

虽然预期结果应该是 333.6

当我用 49 替换 q 时,没关系,我得到 340,55

Java 浮点精度

评论

1赞 DannyMo 8/6/2013
为什么“没有”?这种情况正是它的用途(双关语)。BigDecimal

答:

-1赞 jh314 8/6/2013 #1

这里的问题是浮点会受到浮点精度误差的影响。您可以使用两倍的精度(您最终仍会得到错误,但它比使用 ) 更准确。doublefloat

例如

public static void main(String[] args) {
    int q = 48;
    double p = 6.95;

    System.out.println(q * p);
}

这将给出 333.6。

2赞 Patricia Shanahan 8/6/2013 #2

如前所述,BigDecimal 专为精确处理短十进制分数特别重要的情况而设计,并且比任何二进制浮点格式都更适合这些情况。

第二种最佳解决方案是以整数美分为单位工作,并在显示过程中仅插入小数点。

如果您必须使用二进制浮点数,double 通常是比浮点数更好的选择,除非您正在处理大量数字并且知道浮点数具有足够的精度。

对于输出,如果您期望结果在小数点后不超过 2 位小数位,则可以使用 DecimalFormat 进行相应的舍入:

导入 java.text.DecimalFormat;

public class Test {
  public static void main(String[] args) {
    DecimalFormat df = new DecimalFormat("#0.##");
    int q = 48;
    float p = 6.95f;
    System.out.println(df.format(q * p));
  }
}

印刷品 333.6

0赞 Joni 8/6/2013 #3

默认格式设置生成的最少数字数是区分数字与其相邻数字所需的数字数。这意味着,如果由于舍入误差而使结果略有偏差,您将得到“丑陋”的输出。

处理此问题的一种方法是使用精确算术(BigDecimal 或整数算术)。另一种方法是对输出进行四舍五入,例如:

System.out.printf("%f", p*q);
0赞 Jim Garrison 8/6/2013 #4

该数字不能完全表示为 ,其精度最多为 6 位十进制数字。当您尝试以过高的精度(8 位数字)打印它时,会显示潜在的舍入错误。333.6float

double精度高达 15 位。

但是,正如其他人所指出的,如果您正在处理财务计算,您应该在 .BigDecimal

作为参考,您可以使用 IEEE-754 浮点转换网站来查看任何给定十进制数的确切表示方式。floatdouble