简体   繁体   English

如何解决这个糟糕的BigDecimal舍入?

[英]How can I fix this poor BigDecimal rounding?

I'm having some trouble rounding BigDecimals in java. 我在用Java舍入BigDecimals时遇到了一些麻烦。 I'm trying to convert a value from feet to inches and vice versa, this is what I have: 我正在尝试将数值从英尺转换为英寸,反之亦然,这就是我所拥有的:

//To convert from ft to in;
//...
BigDecimal CINCH = new BigDecimal("12");
Inch.setText(CINCH.multiply(VFEET).toString()); //VFEET is the user input

//To convert from in to ft
//...
BigDecimal CFEET = new BigDecimal("12"); //Initially I multiplied the input with 0.0833333333
Feet.setText(VINCH.divide(CFEET, 7, RoundingMode.HALF_UP).toString());  //VINCH is the user input

If i try to convert 1 feet to inch, it returns the expected value (12). 如果我尝试将1英尺转换为英寸,它将返回预期值(12)。 If i try to convert 12 inch to feet, it returns the expected value (1) but with 7 decimal cases like I expected. 如果我尝试将12英寸转换为英尺,它会返回预期值(1),但有7个十进制的小数,如我预期的那样。

If i convert 1 inch to feet, it returns 0.08333333 and if I convert this value from feet to inch, it was supposed to return 1, but instead, it returns 0.9999996. 如果我将1英寸转换为英尺,则返回0.08333333,如果我将此值从英尺转换为英寸,则应返回1,但返回0.9999996。 If i conver 2 inch to feet, it returns 0.1666667 and if I conver this value from ft to in, it returns 2.0000004 如果我将2英寸转换为英尺,则返回0.1666667,如果将该值从ft转换为in,则返回2.0000004

How can I fix this? 我怎样才能解决这个问题? (I know I could just do this with doubles, and that was my first plan but i ran in to an accuracy problem (bigger than this one)) (我知道我可以用双打来做,这是我的第一个计划,但是我遇到了精度问题(比这个大)

Choosing what data type to use for a representation, though, should reflect the underlying problem to be solved. 但是,选择用于表示形式的数据类型应反映要解决的基本问题。 Generally for measurements you would use doubles because the precision of the measurement is generally less than the precision of the representation. 通常对于测量,您将使用双精度,因为测量的精度通常小于表示的精度。 In this case errors in the representation are less significant. 在这种情况下,表示中的错误不太重要。 Generally you would also be dealing with measured values that are similar in scale where the difference between two values doesn't approach the precision of the representation. 通常,您还将处理比例相似的测量值,其中两个值之间的差异不接近表示的精度。 In your case, it appears that you need more precision than can be represented by a double, but do not want numbers displayed to the precision allowed by a decimal. 在您的情况下,您似乎需要比双精度表示的精度更高的精度,但不希望数字显示为小数允许的精度。

One possible solution is to internally keep the values with greater precision than you display. 一种可能的解决方案是在内部保留比显示的精度更高的值。 This would apply regardless of the type, but is easily demonstrated using your example for a decimal . 无论类型如何,这都适用,但是使用您的示例decimal很容易说明。 For example (in C#) 例如(在C#中)

decimal f = 1m;
decimal i = f / 12m;

Console.WriteLine("{0} {1} {2} {3}", f, i, i * 12m, Math.Round(i * 12m, 7));

produces the following output where you can see that by presenting fewer digits we get the expected answer 产生以下输出,您可以看到通过显示较少的数字可以得到预期的答案

1 0.0833333333333333333333333333 0.9999999999999999999999999996 1.0000000

My suggestion would be to do the arithmetic at a higher precision and the display at a lower precision. 我的建议是以较高的精度进行运算,以较低的精度进行显示。 In your case you are doing the arithmetic at a scale of 7, so you may want to present at most 6 digits of precision in the output or conversely set the scale higher so you can present as many digits of precision as your measurements reflect. 在您的情况下,您要以7的小数位进行算术运算,因此您可能希望在输出中显示最多6位精度,或者反过来将小数位设置得更高,以便可以显示测量结果所反映的尽可能多的精度。

You might also find this helpful, Scale() of Divide method in BigDecimal 您可能还会发现BigDecimal中的Divide方法的Scale()有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM