【问题标题】:Java Math.pow() Rounding ErrorJava Math.pow() 舍入错误
【发布时间】:2012-07-03 21:24:59
【问题描述】:

我遇到了(我怀疑是)舍入错误的问题。

我有一个字符串0.686357E-01,我正在尝试将其转换为双精度。我已经能够使用Pattern.split() 函数将其拆分,并且我可以很好地捕获基值和指数值。但是,一旦我尝试将它们适当地相乘,就会得到以下结果:0.06863570000000001。

这是我的相关代码:

pattern = Pattern.compile("E\\+?");
String[] number = pattern.split(string);

double base = Double.parseDouble(number[0]);
int exponent = Integer.parseInt(number[1]);

number= base*Math.pow(10, exponent);

那么,如何避免舍入误差? (有一些方法可以解决它,但如果可以,那么我想知道如何解决这个问题)

谢谢。

【问题讨论】:

  • 这不是舍入错误。这就是大多数编程语言中 float/double 的行为方式。处理浮点数永远不可能有 100% 的精度。这就是为什么人们不鼓励使用(float1 == float2) 而只是使用abs(float1 - float2) < epsilon。我相信精度只能保证到 10^15。
  • 有趣 - 我以前从未经历过这种行为。没有办法避免吗?
  • @MattS 第一次做所有事情。这实际上是一个复杂的数值分析,problem 让 CPU 架构师和制造商头疼。

标签: java double


【解决方案1】:

你不需要拆分它,Double.parseDouble 可以很好地处理这些数字。

double number = Double.parseDouble("0.686357E-01");

See? It works!

【讨论】:

  • 问题是有时这个数字实际上有一个解析器似乎不喜欢的指数“E+00”。否则我会那样做。
  • @MattS:嗯......这对我来说解析得很好。 ideone.com/onONy我认为你的问题在别处。
  • 有趣,我刚试了一下,它似乎确实有效。我一定是犯了一个错误,之前把它搞砸了。谢谢!
【解决方案2】:

0.0686357 不能完全表示为双精度值。

两种解决方案:

  • 使用例如BigDecimal。
  • 在转换回人类可读时将显示的精度限制为一定数量的有效数字。

【讨论】:

    【解决方案3】:

    浮点数没有完美的精度。如果这是一个问题,请使用BigDecimal:

    String string = "0.686357E-01";
    BigDecimal number = new BigDecimal(string);
    System.out.println(number);
    

    【讨论】:

      【解决方案4】:

      Double 将总是这样打印,但值将保持正确。您需要格式化输出以获得正确的值。见DecimalFormat类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多