java中十进制数的总和

发布于 2024-10-26 11:13:20 字数 1070 浏览 1 评论 0原文

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

我有两个数字第一个第二(作为格式化字符串的输出)。我在第一和第二之间进行求和,然后收到一个具有更多小数位的数字!

   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 的值是该问题的最安全值吗?

我该如何解决这种情况?我认为这个问题是由于使用双精度变量而产生的,但是对于浮点数我也有同样的问题。

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

I have a problem for the managemente of decimal number in java (JDK 1.4).

I have two double numbers first and second (as output of formatted String). I do a sum between fist and second and I receive a number with more decimal digits!

   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
    */

I prefer not growing the threshold value (0.5d) because I'm not safe with similar situation (when I started coding, the specs was talking about 0.1d as comparison value).
If it's the only solution, the value of 0.9d is safest value for this problem?

How I can resolve this situation? I thinked that this problem derive by the use of double variables, but with the float I have the same problem.

Some idea (having some tested code line, if possible ;))?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

纸伞微斜 2024-11-02 11:13:20

您可能会遇到舍入错误,但我在这里没有看到它。

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。这通常是许多开发人员的首选解决方案,但恕我直言,这是最后的选择。 ;)

You can get rounding error, but I don't see it here.

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);
}

prints

-0.5

There are two ways to handle this more generally. You can define a rounding error such as

 private static final double ERROR = 1e-9;

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

OR use rounding

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

OR use integers with fixed precision

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);
}

OR You can use BigDecimal. This is often the preferred solution for many developers, but a last option IMHO. ;)

机场等船 2024-11-02 11:13:20

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

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

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

This error will depend slightly on your version of Java (and I see you are using a slightly old one). However, regardless of Java version, for best results when you are particularly worried about decimal accuracy in java, you should use the BigDecimal class for your values.

This is what financial applications use for handling currency, and also what many industrial Java applications use when precision is essential.

EDIT: I see many valid comments that this solution comes with a slight performance hit (also depends on the number of operations you are doing in the first place). And really, if this is the only single place that you encounter an issue and you dont care about precision after it, then ya, go for a workaround. But if this happens frequently and in more than one place, or if you think you might be expanding your application in the future, I would use the safer BigDecimal.

北凤男飞 2024-11-02 11:13:20

双项以 2 的幂存储数字。不可能用 2 的幂准确表示大量数字,因此会遇到舍入问题。使用浮动时也会出现同样的问题。

如果您想减少这些,请使用 Decimal 类型作为数字,这应该会更准确。

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

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

Double items store number in powers of 2. It is not possible to accurately represent a lot of numbers in terms of powers of 2 and so you get rounding issues. The same problem when using floats.

If you want to reduce these, use the Decimal type for the numbers, this should prove to be more accurate.

For doubles and floats, you must use the < comparator to check if 2 numbers are close enough to be considered equal.

See this for more details ->
What is the most effective way for float and double comparison?

唐婉 2024-11-02 11:13:20

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

public static strictfp void main(String[] args)

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

I've tested and on my machine everything is correct (tested in java 1.6). If I were you I would test strictfp modifier to method which has above operations:

public static strictfp void main(String[] args)

The problem can be connected with java version, OS, CPU you're using

╭ゆ眷念 2024-11-02 11:13:20

我同意彼得的观点,我也不认为这种情况会发生。但是,如果这种情况不断发生在您身上,并且小数位数已知并在您的用例中固定,那么使用“int”可能是一种解决方案,它甚至比浮点运算更快。当然,对于视图,您必须将其转换为浮点。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文