【问题标题】:Java loss of precisionJava 精度损失
【发布时间】:2010-03-05 19:38:25
【问题描述】:

我有一个担心精度损失的问题

我的任务是将数字打印为字符串

int exponent = ...
int[] Mantissas = { 1, 2, 5 };
double dataStep = java.lang.Math.pow(10.0, exponent) * Mantissas[mantissaIndex];
...
for (int i = 0; i < NSteps; i++)
                    steps[i] = firstStep + i * dataStep;
draw(steps);

例如,0.2*7=1.4000000000000001; 0.0000014/10=1.3999999999999998E-7

如何解决这个问题?

UPD:主要问题是字符串输出格式。我不担心失去大约 0.00000001 的价值。 现在我将它解决为 String.format("%f", value), 但我认为这不是好方法

【问题讨论】:

  • stackoverflow 上最常见的问题。
  • 我们应该有一个 fubar 徽章来问这个问题。

标签: java string precision


【解决方案1】:

正如其他人所提到的,您必须使用 java.math.BigDecimal 而不是 float/double。然而,这也带来了一系列问题。

例如,当您调用 BigDecimal(double) 时,您传入的值将扩展为其完整表示:

BigDecimal oneTenth = new BigDecimal(0.1);
BigDecimal oneMillion = new BigDecimal(1000000);
oneTenth.multiply(oneMillion)
out> 100000.0000000000055511151231257827021181583404541015625000000

但是当您使用 BigDecimal(String) 构造函数时,会表示 eact 值并且您会得到 ​​p>

BigDecimal oneTenth = new BigDecimal("0.1");
BigDecimalr oneMillion = new BigDecimal(1000000);
oneTenth.multiply(oneMillion)
out> 100000.0

您可以在 Joshua Bloch 和 Neal Gafter 精彩的 Java puzzlers 书籍和 this 信息文章中阅读更多关于 BigDecimal 的限制。最后请注意,BigDecimal 上的 toString 将以科学记数法打印,因此您必须正确使用 toPlainString

【讨论】:

    【解决方案2】:

    double 类型没有无限精度,不能精确表示小数。您正在观察正常的舍入误差。对于任意精度算术,您需要改用 java.math.BigDecimal。

    【讨论】:

    • 好的,java.math.BigDecimal m=new BigDecimal(1.4).setScale(1000); m=m.divide(new BigDecimal(10).setScale(1000)); System.out.println(m);输出为 0.1399999999999999911182158029987476766109466552734375 ;我想在我的图表控件上打印“0.14”
    • 不要使用 new BigDecimal(double) 使用 new BigDecimal(String) 或 BigDecimal.valueOf(double)。 new BigDecimal(double) 的行为与双精度完全一样。
    【解决方案3】:

    在 SO 上搜索“浮点数”,您会得到很多关于为什么会发生这种情况的答案。它与浮点数在计算机中的表示方式有关。

    How is floating point stored? When does it matter?

    关于此事的另一篇文章-Floating Point Approximation

    【讨论】:

      猜你喜欢
      • 2014-07-13
      • 1970-01-01
      • 1970-01-01
      • 2020-07-28
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      相关资源
      最近更新 更多