65

I am looking for the best way to convert a Number to a BigDecimal.

Is this good enough?

Number number;
BigDecimal big = new BigDecimal(number.toString());

Can we lose precision with the toString() method ?

hyde
  • 60,639
  • 21
  • 115
  • 176
  • 2
    your code may throw `NumberFormatException` - if `number` is a `Double` that is Infinity or NaN http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Double.html#toString(double) – Ahmed KRAIEM Apr 25 '13 at 13:41
  • Thanks for the tip ! I forgot to check this –  Apr 25 '13 at 13:43

4 Answers4

41

This is fine, remember that using the constructor of BigDecimal to declare a value can be dangerous when it's not of type String. Consider the below...

BigDecimal valDouble = new BigDecimal(0.35);
System.out.println(valDouble);

This will not print 0.35, it will infact be...

0.34999999999999997779553950749686919152736663818359375

I'd say your solution is probably the safest because of that.

David
  • 19,577
  • 28
  • 108
  • 128
  • Yep, I've noticed that. My worries are about `toString()` method for the `Double`, I was wondering if we can loose precision with this method. –  Apr 25 '13 at 13:42
  • No, although you will naturally have more precision if it was a BigDecimal in the first place. If it's dealing with currency, you should always make everything BigDecimal. If it was declared as BigDecimal before being cast from a Double, that would be the best solution in my opinion and take Double out of the equation altogether. – David Apr 25 '13 at 13:49
23

Can we lose precision with toString() method ?

Kind of ... Both Float.toString() and Double.toString() only output the number of digits after the decimal separator, which is required for the output uniquely to correspond to a float or double value.

To use the 0.35 example in david99world's answer, consider the following code:

BigDecimal bd1 = new BigDecimal(0.35);

Number n = 0.35;
BigDecimal bd2 = new BigDecimal(n.toString());

System.out.println(bd1);
System.out.println(bd2);

An intuitive expectation may be that the two BigDecimal instances are identical, but the output shows that they are not:

0.34999999999999997779553950749686919152736663818359375
0.35

The first line is the exact value of the double, since 0.35 cannot be represented exactly. The second line is 0.35, since no more fractional digits are required to represent the distinct value. E.g. the statement 0.34999999999999997779553950749686919152736663818359375 == 0.35 will evaluate to true.

This is actually not a loss of precision when creating the BigDecimal, the uncertainty is already there in your "source" value. The problem is rather that the discrete values possible using e.g. a float or double value as source not necessarily will be represented by the exact equivalent in the BigDecimal instance.

Dan
  • 10,531
  • 2
  • 36
  • 55
jarnbjo
  • 33,923
  • 7
  • 70
  • 94
  • 2
    This is a really good point, but in your trivial example, the `toString` result is actually preferable because it provides the literal number that you typed in the code, as if you had done `new BigDecimal("0.35")`. Is there a situation where the `toString` approach would actually be problematic? – Drew Nutter Jan 07 '21 at 14:11
1

I think this is the best way to convert Number to BigDecimal:

public static BigDecimal convertToBigDecimal(Number number) {
        if (number instanceof Integer
                || number instanceof Long
                || number instanceof Short
                || number instanceof Byte) {
            return BigDecimal.valueOf(number.longValue());
        }
        return BigDecimal.valueOf(number.doubleValue());
    }
JHead
  • 356
  • 2
  • 12
-2

For Number, your solution is probably the best.

For doubles, probably the best way is

BigDecimal.valueOf(myDouble);

It works also for longs and it's optimized for frequently used longs value.

Source

Marco Sulla
  • 15,299
  • 14
  • 65
  • 100