4

java (JDK 1.4) 中十进制数的管理有问题。

我有两个第一个第二个(作为格式化String的输出)。我在拳头和秒之间求和,我收到一个带有更多小数位数的数字!

   final double first=198.4;//value extract by unmodifiable format method

   final double second=44701.2;//value extract by unmodifiable format method

   final double firstDifference= first+second; //I receive 44899.598 instead of 44899.6

   final double calculatedDifference=44900.1; // comparison value for the flow

    final double error=firstDifference-calculatedDifference;// I receive -0.50390605 instead 0.5

    if(Math.abs(error)<=0.5d)){
         //I must enter in this branch but the error not allows the correct flow!!!
    }
    /***
    * the flow of program is uncorrect and there's a very visible bug in business view
    */

我不喜欢增加阈值(0.5d),因为在类似的情况下我不安全(当我开始编码时,规范将0.1d作为比较值)。如果它是唯一的解决方案,0.9d的值是这个问题的最安全值吗?

我该如何解决这种情况?我认为这个问题是通过使用双变量得出的,但是对于浮点数我有同样的问题。

一些想法(如果可能的话,有一些经过测试的代码行;))?

4

5 回答 5

3

你可能会得到舍入错误,但我在这里看不到。

final double first=198.4;//value extract by unmodifiable format method
final double second=44701.2;//value extract by unmodifiable format method
final double firstDifference= first+second; //I receive 44899.6
final double calculatedDifference=44900.1; // comparison value for the flow
final double error=firstDifference-calculatedDifference;// I receive -0.5 

if(Math.abs(error)<=0.5d){
    // this branch is entered.
    System.out.println(error);
}

印刷

-0.5

有两种更普遍的处理方法。您可以定义舍入误差,例如

 private static final double ERROR = 1e-9;

 if(Math.abs(error)<=0.5d + ERROR){

或使用四舍五入

final double firstDifference= round(first+second, 1); // call a function to round to one decimal place.

或使用具有固定精度的整数

final int first=1984;// 198.4 * 10
final int second=447012; // 44701.2 * 10
final int firstDifference= first+second;  //I receive 448996
final int calculatedDifference=449001; // comparison value for the flow
final int error=firstDifference-calculatedDifference;// I receive -5 

if(Math.abs(error)<=5){
    // this branch is entered.
    System.out.println(error);
}

或者您可以使用 BigDecimal。这通常是许多开发人员的首选解决方案,但恕我直言,这是最后的选择。;)

于 2011-03-24T18:16:51.433 回答
3

此错误将稍微取决于您的 Java 版本(我看到您使用的是稍微旧的版本)。但是,无论 Java 版本如何,当您特别担心 Java 中的小数精度时,为了获得最佳结果,您应该使用BigDecimal该类作为您的值。

这是金融应用程序用于处理货币的方法,也是许多工业 Java 应用程序在精度至关重要时使用的方法。

编辑:我看到许多有效的评论,该解决方案带有轻微的性能影响(也取决于您首先执行的操作数量)。真的,如果这是您遇到问题的唯一一个地方,并且您不关心它之后的精度,那么请寻求解决方法。但是,如果这种情况经常发生并且发生在多个地方,或者您认为您将来可能会扩展您的应用程序,我会使用更安全的BigDecimal.

于 2011-03-24T18:19:03.867 回答
0

双项以 2 的幂存储数字。根据 2 的幂来准确表示大量数字是不可能的,因此您会遇到四舍五入的问题。使用浮点数时同样的问题。

如果您想减少这些,请使用 Decimal 类型的数字,这应该被证明更准确。

对于双精度数和浮点数,您必须使用 < 比较器来检查 2 个数字是否足够接近以被视为相等。

有关更多详细信息,请参阅此 -> 浮动和双重比较最有效的方法是什么?

于 2011-03-24T18:17:42.037 回答
0

我已经测试并且在我的机器上一切都是正确的(在 java 1.6 中测试)。如果我是你,我会测试具有上述操作的方法的 strictfp 修饰符:

public static strictfp void main(String[] args)

问题可能与您使用的 java 版本、操作系统、CPU 有关

于 2011-03-24T18:20:32.773 回答
0

I agree with Peter, I don't see that happening either. However, if it keeps happening to you and if the number of decimals is known and fixed in your usecase anyway, using "int" might be a solution, that's even faster than floating point operations. For the views you would then have to convert to floating points, of course.

于 2011-03-24T18:55:47.610 回答