0

I'm having some trouble rounding BigDecimals in java. 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). If i try to convert 12 inch to feet, it returns the expected value (1) but with 7 decimal cases like I expected.

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. 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

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

Luso
  • 125
  • 2
  • 9
  • how about getting rid of rounding, i.e. using _RoundingMode.UNNECESSARY_? – Juvanis Jul 21 '13 at 13:48
  • Doubles is actually the right answer for measurement. Decimals should be used for things that have an exact numeric quantity, like financial values. See http://ericlippert.com/2013/07/18/why-not-allow-doubledecimal-implicit-conversions though it doesn't specifically address your problem. – tvanfosson Jul 21 '13 at 13:49
  • @Juvanis I tried using RoundingMode.UNNECESSARY... the program crashes when I try to convert... (I tried 1 in to ft) – Luso Jul 21 '13 at 13:52
  • @tvanfosson I tried with doubles and it actually worked! It returned the right value when I converted 1 in to ft and the returned value to in again! it solved it! I didn't write in the question but the problems I had with doubles happened while converting 1 meter (or dm/cm/mm) to picometer. – Luso Jul 21 '13 at 14:04
  • You may want to try using a [Rational](http://jscience.org/api/org/jscience/mathematics/number/Rational.html), which doesn't do any rounding – Zim-Zam O'Pootertoot Jul 21 '13 at 14:05

1 Answers1

0

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. For example (in 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.

You might also find this helpful, Scale() of Divide method in BigDecimal

Community
  • 1
  • 1
tvanfosson
  • 524,688
  • 99
  • 697
  • 795