Double increments in Java
Solution 1
Welcome to the world of floating point, where 0.1 isn't 0.1. The problem is that many numbers, including 0.1, cannot be represented exactly in a double
. So you aren't really adding exactly 0.1 to x
each time through the loop.
One approach is to use integer arithmetic and divide by 10:
int i = 0;
while (i <= 10) {
double x = i / 10.0;
. . .
i++;
}
Another approach is to make x
a BigDecimal
, where you can specify that you want a particular precision. It basically is doing what the above loop does (an integer plus a scale), but packaged up in a nice class with lots of bells and whistles. Oh, and it has arbitrary precision.
Solution 2
you need to use the decimal formatter to get the expected output.
Below is the code for generating the expected output:
import java.text.DecimalFormat;
public class FloatIncrement {
public static void main (String args[]){
double x= 0.0;
DecimalFormat form = new DecimalFormat("#.#");
while(x<0.9){
x= x+0.1;
System.out.println("X : "+Double.valueOf(form.format(x)));
}
}
}
Solution 3
To get output you want, you could use DecimalFormat
. Here is some sample code.
import java.text.DecimalFormat;
public class DF {
public static void main(String [] args) {
double x = 0.1;
DecimalFormat form = new DecimalFormat("#.#");
while (x <= .9) {
System.out.println(Double.valueOf(form.format(x)));
x += 0.1;
}
}
}
As far as the implementation you have now, there is no guarantee as to the precision of what gets printed due to the nature of floating point numbers.
Solution 4
Using BigDecimal
double x = 0.0;
int decimalPlaces = 2;
while ( x<=1 )
{
x += 0.1;
BigDecimal bd = new BigDecimal(x);
bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
x = bd.doubleValue();
System.out.println(x);
}
user1483799
Updated on October 22, 2020Comments
-
user1483799 over 3 years
Possible Duplicate:
How to iterate between 0.1f and 1.0f with 0.1f increments in Java?Part of my program needs to use values inside a while loop as:
0.1
0.2
0.3
...
0.9
so I need to provide them inside that loop. Here is the code:
double x = 0.0; while ( x<=1 ) { // increment x by 0.1 for each iteration x += 0.1; }
I need the output to be EXACTLY:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
But it actually gives me something like:
0.1
0.2
0.300000000000000000000000004
0.4
0.5
0.6
0.79999999999999999999999999
0.89999999999999999999999999
0.99999999999999999999999999
-
Mukus over 11 yearsYou seem to be adding the right number. I don't see why this would not work.
-
cHao over 11 years@TejaswiRana: It doesn't work because 0.1 is actually something like 0.0999999999999999999999 or 0.10000000000000000001. Decimal fractions can't be losslessly represented by a double.
-
-
Mukus over 11 yearsReally? When you add 0.1 you are not actually adding 0.1? That can throw off a lot of calculations in a lot of applications that exist till date.
-
cHao over 11 years@TejaswiRana: Yep. That's why
double
is only a good idea for calculations that can tolerate the rounding error. Game physics calculations? Sure. Money? Hell no. Basically if the number is a measurement, doubles are generally ok; if it's a count, use a BigDecimal or integers instead. -
Ted Hopp over 11 yearsThe opening sentence is a bit misleading. Every
double
is a rational value; the issue is the converse: not every rational value is adouble
value. -
Shariq over 11 yearsYou could also round to one significant figure using the code available here. stackoverflow.com/questions/202302/…
-
Mukus over 11 yearsSo then if I were creating a banking app, what would I use as data type? Float?
-
Mukus over 11 years@cHao I take it that this is the same for C# too?
-
Ted Hopp over 11 years@TejaswiRana - A lot of applications that use
double
are written using tolerances to compensate for this. For those that are not written that way, either the roundoff errors are not important or the applications are buggy. Alternative approaches include all-integer arithmetic, arbitrary precision packages (which are basically all-integer arithmetic at their core), or rational arithmetic packages (likewise integer-based). -
cHao over 11 years@TejaswiRana: Floats are even worse than doubles as far as rounding error is concerned. For a banking app, you'd probably do best to have a certain number of decimal digits you want to keep, and multiply your amounts so that you can turn them into ints or longs.
-
Shariq over 11 years@TedHopp - changed my answer; you're right. I didn't explain what I meant by rational - I meant in memory, the number isn't represented as a ratio of a numerator to a denominator.
-
cHao over 11 years@TejaswiRana: Yep. Same for most languages that support floating point numbers. C#, PHP, Java, C, C++, VB, etc.
-
Mukus over 11 yearsstackoverflow.com/questions/2863388/… It gets even worse in C#
-
cHao over 11 years@TejaswiRana: Not so much, actually. .net has a
Decimal
type, which is a decimal floating-point number (rather than the binary ones the CPU probably supports).0.1
can be accurately and losslessly represented by a C#decimal
(though it looks like0.1m
or somethig like that in C#), so it's safe to use for money. Drawback is, a lot of operations (logs, non-integer exponentiation, basically anything that'd typically yield an irrational result) isn't supported for them without the help of third-party libs. -
user207421 over 11 years@cHao For a banking or accounting application it would be tantamount to criminal incompetence to use floating point at all. I've seen contractors hauled over the coals for it and required to remedy at their own expense.
-
squiguy over 11 yearsThat is some good looking code :)
-
cHao over 11 years@EJP: There's a bit of difference with C#'s decimal floating-point, though. A
decimal
can accurately hold around 30 significant digits. That's enough for even a trillionth of a penny on amounts in the trillions. -
simbu94 over 11 years@squiguy thank you for your suggestion
-
Ivan Balashov almost 4 yearsThe error is accumulated in this example. Better to reduce number of floating point operations if you can (not relevant to this case, but matters if your loops goes to a large number).