This question already has answers here:
new BigDecimal(double) vs new BigDecimal(String) [duplicate]
(4 answers)
Closed 4 years ago.
Why does the following return 1?
new BigDecimal(0.82).setScale(5, BigDecimal.ROUND_HALF_DOWN)
.compareTo(new BigDecimal(0.82))
I expect this to return 0 because BigDecimal.compareTo ignores scale according to its documentation:
Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. [...]
new BigDecimal(0.82) is not actually 0.82, because you're passing a double value -- the double closest to 0.82, which is not exactly 0.82 -- to the constructor, so new BigDecimal(0.82) is a BigDecimal equal to the double closest to 0.82.
Instead, use new BigDecimal("0.82").
The problem is that you use the constructor BigDecimal#BigDecimal(double). It returns a BigDecimal that represents the double's binary floating-point value (see its documentation). However, 0.82 isn't representing the value 0.82 but
0.81999999999999995115018691649311222136020660400390625
Because of that .setScale(5, BigDecimal.ROUND_HALF_DOWN) actually changes the value, not only the scale. The resulting value after applying the method is
0.82000
The compareTo method ignores the scale but not different values. As explained, your two BigDecimal actually represent different values. Thus the compareTo does not return 0:
0.82000 != 0.81999999999999995115018691649311222136020660400390625
See the documentation of the method:
Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. [...]
Related
This question already has answers here:
Format of BigDecimal number
(4 answers)
How do I format a number in Java?
(9 answers)
Is floating point math broken?
(31 answers)
Closed 3 years ago.
I'm using BigDecimal data type, when I set
new BigDecimal(21.30);
then, I returned it as xml source, it shows as
21.30000000000710522735760100185871124467578125
Another number
new BigDecimal(23.11)
returned
23.1099999994315658113818187512921995859375
I want to show results with the same decimals as I set on create.
The results of this constructor can be somewhat unpredictable. One
might assume that writing new BigDecimal(0.1) in Java creates
a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625.
This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1,
appearances notwithstanding.
If you check the BigDecimal java doc you will find out that you will have to use the constructor which takes a String parameter to end up with the behavior you need.
This question already has answers here:
BigDecimal from Double incorrect value?
(4 answers)
Convert double to BigDecimal and set BigDecimal Precision
(8 answers)
Closed 4 years ago.
I want to retrieve the value of the bigDecimal with the exact value as it was instantiated here
BigDecimal balance = new BigDecimal(2300000870000000000067.7797);
The value I retrieve at the moment using balance is 2300000869999999975424.
Can you please advise how can I retrieve it as 2300000870000000000067.7797 itself?
You have used java.math.BigDecimal.BigDecimal(double val) constructor.
From JavaDoc:
java.math.BigDecimal.BigDecimal(double val)
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.
Notes:
1. The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
2. The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
3. When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
Here First point suggests that :
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
Second point suggests to use the constructor with string argument for exact value.
This is the reason for difference of value.
You are trying to use a literal number that cannot fit in a double which has a maximum of 15 decimals precision - probably why you want to use BigDecimal in the first place. So your number is converted to the most acurate representation in a double before initialising BigDecimal. Then the BigDecimal contructor compounds the error by messing up the already messed up double.
You will have to represent numbers as Strings to get that precision.
double x = 2300000870000000000067.7797d;
System.out.println("double:"+x);
BigDecimal balance = new BigDecimal(2300000870000000000067.7797);
System.out.println("balance:"+balance);
BigDecimal stringbased = new BigDecimal("2300000870000000000067.7797");
System.out.println("stringbased:"+stringbased);
Prints
double:2.30000087E21
balance:2300000869999999975424
stringbased:2300000870000000000067.7797
The java doc itself suggest about BigDecimal(Double val):
The results of this constructor can be somewhat unpredictable.
You should use the following instead:
BigDecimal balance = new BigDecimal("2300000870000000000067.7797");
This question already has answers here:
Integer division: How do you produce a double?
(11 answers)
Closed 6 years ago.
I'm currently working on a Trafficsimulation which is based on a grid system. For some reason the line of code, which calculates how many tiles i have to add always returns 0. I have tried it without the variables but it still doesn't work.
double blocksToAdd = o.getVelocity()*((1000/Main.FPS)/1000);
Currently the velocity is equal to 1.0f and the Simulation runs at 10 FPS, so blocksToAdd should be 0.1, but it always returns 0.
Since Main.FPS is an int, 1000/Main.FPS is also an int, equal to 100. You then proceed to calculate 100/1000. Since this is an integer division, only the "whole" part is taken, giving 0.
Using floating point literals will cause Java to use floating point division, which should produce the correct result:
double blocksToAdd = o.getVelocity() * ((1000.0 /Main.FPS ) / 1000.0);
// Here --------------------------------------^--------------------^
Most likely due to integer division tuncating the fraction.
Replace the first 1000 with 1000.0 and all will be well. (The latter is a floating point double literal which causes the division to be computed in floating point.) There are other remedies but I find this one to be the clearest.
I have two pieces of code new BigDecimal("1.240472701") and new BigDecimal(1.240472701). Now if i use compareTo method of java on both the methods then i get that they are not equal.
When i printed the values using System.out.println() method of java. I get different results for both the values. For example
new BigDecimal("1.240472701") -> 1.240472701
new BigDecimal(1.240472701) -> 1.2404727010000000664291519569815136492252349853515625
So i want to understand what could be reason for this?
You can refer the Java doc of public BigDecimal(double val) for this:
public BigDecimal(double val)
Translates a double into a BigDecimal
which is the exact decimal representation of the double's binary
floating-point value. The scale of the returned BigDecimal is the
smallest value such that (10^scale × val) is an integer.
The results of this constructor can be somewhat unpredictable. One
might assume that writing new BigDecimal(0.1) in Java creates a
BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with
a scale of 1), but it is actually equal to
0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that
matter, as a binary fraction of any finite length). Thus, the value
that is being passed in to the constructor is not exactly equal to
0.1, appearances notwithstanding.
The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates
a BigDecimal which is exactly equal to 0.1, as one would expect.
Therefore, it is generally recommended that the String constructor be
used in preference to this one.
When a double must be used as a source
for a BigDecimal, note that this constructor provides an exact
conversion; it does not give the same result as converting the double
to a String using the Double.toString(double) method and then using
the BigDecimal(String) constructor. To get that result, use the static
valueOf(double) method.
The string "1.240472701" is a textual representation of a decimal value. The BigDecimal code parses this and creates a BigDecimal with the exact value represented in the string.
But the double 1.240472701 is merely a (close) approximation of that exact decimal value. Double cannot represent all decimal values exactly, so the exact value stored in the double differs slightly. If you pass that to a BigDecimal, it takes that differing value and turns it into an exact BigDecimal. But the BigDecimal only has the inexact double to go by, it does not know the exact text representation. So it can only represent the value in the double, not the value of the source text.
In the first case:
String --> BigDecimal
Because BigDecimal is made to exactly represent decimal values, that conversion is exact.
In the second case:
1 2
Source code text --> double --> BigDecimal
In the second case, precision is lost in the first conversion (1). The second conversion (2) is exact, but the input -- the double -- is an inexact representation of the source code text 1.240472701 (in reality, it is 1.2404727010000000664291519569815136492252349853515625).
So: never initialize a BigDecimal with a double, if you can avoid it. Use a string instead.
That is why the first BigDecimal is exact and the second is not.
Since user thegauravmahawar provided the answer from docs. Yes, it is because of Scaling in BigDecimal case.
So the values might seem equal to You but internally java uses Scaling while storing the value of BigDecimal type.
Reason: Scaling.
Improvement:
You could call setScale to the same thing on the numbers you're comparing:
like this
new BigDecimal ("7.773").setScale(2).equals(new BigDecimal("7.774").setScale (2))
This will save you from making any mistake.
According to the JavaDoc for BigDecimal, the compareTo function does not account for the scale during comparison.
Now I have a test case that looks something like this:
BigDecimal result = callSomeService(foo);
assertTrue(result.compareTo(new BigDecimal(0.7)) == 0); //this does not work
assertTrue(result.equals(new BigDecimal(0.7).setScale(10, BigDecimal.ROUND_HALF_UP))); //this works
The value I'm expecting the function to return is 0.7 and has a scale of 10. Printing the value shows me the expected result. But the compareTo() function doesn't seem to be working the way I think it should.
What's going on here?
new BigDecimal(0.7) does not represent 0.7.
It represents 0.6999999999999999555910790149937383830547332763671875 (exactly).
The reason for this is that the double literal 0.7 doesn't represent 0.7 exactly.
If you need precise BigDecimal values, you must use the String constructor (actually all constructors that don't take double values will work).
Try new BigDecimal("0.7") instead.
The JavaDoc of the BigDecimal(double) constructor has some related notes:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
So to summarize: If you want to create a BigDecimal with a fixed decimal value, use the String constructor. If you already have a double value, then BigDecimal.valueOf(double) will provide a more intuitive behaviour than using new BigDecimal(double).