Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a double initialized with a small whole number value be used with accuracy in a BigDecimal context?

It is well documented that using a double can lead to inaccuracies and that BigDecimal guarantees accuracy so long as there are no doubles in the mix.

However, is accuracy guaranteed if the double in question is a small whole number?

For example, although the following will be inaccurate/unsafe:

BigDecimal bdDouble = new BigDecimal(0.1d); // 0.1000000000000000055511151231257827021181583404541015625

will the following always be accurate/safe?

BigDecimal bdDouble = new BigDecimal(1.0d); // 1

Is it safe to assume that small whole number doubles are safe to use with BigDecimals - if so, what is the smallest whole number that would introduce an inaccuracy?

>> Additional info in response to initial answers:

Thanks for the answers. Very helpful.

Just to add a little more detail, I have a legacy interface which supplies doubles, but I can be certain that these doubles will represent whole numbers having being themselves converted from Strings to doubles via Double.parseDouble(String) where the String is a guaranteed whole number representation.

I do not want to create a new interface which passes me Strings or BigDecimals if I can avoid it.

I can immediately convert the double to a BigDecimal on my side of the interface and make all internal calculations using BigDecimal calls, but I want to be sure that is as safe as creating a new BigDecimal/String interface.

Given that in my original example using 0.1d does not accurately result in 0.1, as shown by the fact that the actual BigDecimal is 0.1000000000000000055511151231257827021181583404541015625, it appears that some fractions will introduce an inaccuracy.

On the other hand, given that in my original example using 1.0d does accurately results in 1, it appears that whole numbers retain accuarcy. It appears that this is guaranteed up to a value of 2^53, if I understand your answers correctly.

Is that a correct assumption?

like image 936
Mr.Mike Avatar asked Apr 20 '15 13:04

Mr.Mike


People also ask

What is the difference between BigDecimal and double?

A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001 ) could result in the 0.001 being dropped altogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.

Why use BigDecimal instead of double?

The main disadvantage is BigDecimal is slower than double. So if we have a system where low latency is crucial than the decimal part of a number, we should go for double. But in financial or any other systems where each digit of decimal part are important, BigDecimal should be chosen over double/float.

How accurate is BigDecimal?

BigDecimal precision is de facto unlimited since it is based on an int array of arbitrary length. Though operations with double are much faster than with BigDecimal this data type should never be used for precise values, such as currency.

How do you initialize a double value?

An object of Double class can hold a single double value. There are mainly two constructors to initialize a Double-object. A. Double(double b): Creates a Double-object initialized with the value provided where it takes a value with which to initialize as a parameter.


1 Answers

The BigDecimal aspect isn't as relevant to this question as "what is the range of integers that can be exactly represented in double?" - in that every finite double value can be represented exactly by BigDecimal, and that's the value you'll get if you call the BigDecimal(double) constructor. So you can be confident that if the value you wish to represent is an integer which is exactly representable by a double, if you pass that double to the BigDecimal constructor, you'll get a BigDecimal which exactly represents the same integer.

The significand of a double is 52 bits. Due to normalization, that means you should expect to be able to store integer values in the range [-253, 253] exactly. Those are pretty large numbers.

Of course, if you're only in the business of representing integers, it's questionable as to why you're using double at all... and you need to make sure that any conversions you're using from original source data to double aren't losing any information loss - but purely on the matter of "what range of integers are exactly representable as double values" I believe the above is correct...

like image 178
Jon Skeet Avatar answered Sep 22 '22 14:09

Jon Skeet