I am calling a truncate method to truncate the double value so that there should be a single digit after decimal (without rounding off),
For Ex. truncate(123.48574) = 123.4
.
My truncate method is something like this
public double truncate (double x) {
long y = (long) (x * 10);
double z = (double) (y / 10);
return z;
}
Its working just fine for almost all the values except for this weird output.
double d = 0.787456;
d = truncate(d + 0.1); //gives 0.8 as expected. Okay.
But,
double d = 0.7;
d = truncate(d + 0.1); //should also give 0.8. But its giving 0.7 only.
//Strange I don't know why?
Infact it works fine for all other 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, - , 0.8, 0.9
I mean for example,
double d = 0.8;
d = truncate(d + 0.1); //gives 0.9 as expected
I tried it with BigDecimal
too. But the same. No change.
Here is the code for that.
double d = 0.7;
BigDecimal a = new BigDecimal(d + 0.1);
BigDecimal floored = a.setScale(1, BigDecimal.ROUND_DOWN);
double d1 = floored.doubleValue();
System.out.println(d1); //Still gives 0.7
And again the real fact is that it works fine with Math.round
.
public double roundUp1d (double d) {
return Math.round(d * 10.0) / 10.0;
}
So if I call roundUp1d(0.7 + 0.1)
, it gives 0.8 as expected. But I don't want the values to be rounded off so I can't use this.
Whats the problem with 0.7 ?
Floating points are inherently inaccurate by their design. Other answers here already explain the theory behind this inaccuracy. It is highly recommended that you use BigDecimal
and BigInteger
instead.
In my answer I want to elaborate on how you are using BigDecimal
wrongly and how you can use it correctly. Don't make the mistake of simply using these classes as a wrapper for floating point calculations. In your present code:
BigDecimal a = new BigDecimal(d + 0.1);
Even though you are trying to use BigDecimal
here, you are still performing the addition using regular floating point calculations. This is exactly the same as doing:
double d_a = d + 0.1; //0.799999999 ad infinitum
BigDecimal a = new BigDecimal(d_a);
To take advantage of the accuracy of the BigX
classes, you must use their own calculation methods, as well as the valueOf
static method (not the constructor):
BigDecimal a = BigDecimal.valueOf(d).add( BigDecimal.valueOf(0.1) );
Here, two BigDecimal
objects are created to match exactly 0.7 and 0.1, then the add
method is used to calculate their sum and produce a third BigDecimal
object (which will be 0.8 exactly).
Using the valueOf
static method instead of the constructor ensures the created BigDecimal
object represents the exact double
value as it is shown when converted to a string (0.7 as a string is "0.7"), rather than the approximate value stored by the computer to represent it (the computer stores 0.7 as 0.699999999 ad infinitum).