Win a copy of The Way of the Web Tester: A Beginner's Guide to Automating Tests this week in the Testing forum!

Greenhorn
Posts: 1
We are using Java JDK 1.4.2_03.
In our application we are adding a bunch of doubles. What is happening is that when we add two doubles
say 0.02 + 0.03 the output comes as 0.05000001 instead of 0.05.
We tried with floats as well but still face this issue. We cannot round off or truncate the values.
I am attaching a sample code where you can see this happening.

Please let us know if anyone knows anything on this front.

[ Jess added a carriage return, in order to keep the screen from stretching... ]
[ October 13, 2004: Message edited by: Jessica Sant ]

Dun Dagda
Ranch Hand
Posts: 54
This seems like fairly standard behaviour for floating point numbers. If you want to control the format of their display, e.g. rounding them off appropriately to a certain number of decimal places, you need to do something like use the DecimalFormat class from java.text.
I have modified your class to the following, which more or less does what you want. If you have a look at the JDK documentation, you might be able to find a more modern formatting class that works even better (the solution below mostly works, but not with all your numbers for some reason).

import java.text.*;

public static void main (String [] args){
double dTotalAmount = 0;
float fTotalAmount = 0;
NumberFormat f = new DecimalFormat("#0.0#");
String [] numValues = new String [] {"0.32","0.45","0.65","0.56","0.55","0.96","0.42","0.92","0.05","0.76","0.87","0.27"};
System.out.println("\n\nusing double - \n\n");
for(int x=0; x<numValues.length; x++)
{
double tempAmount = (double)Double.parseDouble(numValues[x]);
dTotalAmount += tempAmount;
System.out.println("tempAmount = "+tempAmount+" & dTotalAmount = "+dTotalAmount);
}
System.out.println("\n\nusing float - \n\n");
for(int x=0; x<numValues.length; x++)
{
float tempAmount = (float)Float.parseFloat(numValues[x]);
fTotalAmount += tempAmount;
System.out.println("tempAmount = "+tempAmount+" & fTotalAmount = "+fTotalAmount);
}
}
}

Dun Dagda
Ranch Hand
Posts: 54
Oops! Sorry, the above code should look like this (where I actually use the DecimalFormat object to call the format method on your numbers) Doh!
:roll:

[ Jess added UBB [code] tags to perserve whitespace ]
[ October 13, 2004: Message edited by: Jessica Sant ]

Nigel Browne
Ranch Hand
Posts: 703
If you are using floats or doubles to hold currency amounts, DONT. Instead either work in the smallest monetary unit for your country and keep track of the decimal point or use the BigDecimal class to hold the values.

Jessica Sant
Sheriff
Posts: 4313
I'm moving this to the intermediate forum, where I think its a better fit.

Please continue the discussion there. Thanks!

Ian Darwin
author
Ranch Hand
Posts: 64
I talk about this in Chapter 5, Numbers. How many different real values are there? An infinite number. Does everybody understand infinity? If you look at the milky way at night, you get an idea: maybe that's a nearly-infinite number of stars. But when the Hubble Space Telescope looks into the dark spaces between the stars, it sees a clearer picture. In every area of space out there the size of the head of a pin held at arm's length, there are thousands upon thousands of galaxies , each one of them roughly the size of our own milky way galaxy. And if you could magically go to one of those far-distant galaxies ("Ahead Warp Factor 22. Make it so."), you would find, beyond the rim of star light, more dark spaces in the sky with, you guessed it, more galaxies than you can count, in every area the size of a pin.

That's my brief look at infinity.

Now back to Java. Floating point numbers are an approximation of real numbers. They only have 32 bits for float, 64 bits for double. So, no matter what floating point machine you use, it will give rounding errors for some values.

The easiest thing you can do is discard the accumulated error. One way has been mentioned, with number Format objects that only present a few significant digits.

You can also eliminate it by (again, as has been mentioned), using an integer value such as a long. In North America, you'd use cents, and just print with two digits after the decimal point. However for some currencies and some amounts even the long isn't, well, long enough, so you'd use BigInteger. But then you have object creation overhead. And they're immutable, so you create a new one every time you do an addition or subtraction.

Summary: if long fits, use that. If "close enough" works, use double. If not, use BigInteger or BigDecimal.

Ian

r phipps
Ranch Hand
Posts: 60
Try this i hope it helps.

import java.text.*;

public static void main (String [] args){
double dTotalAmount = 0;
float fTotalAmount = 0;
NumberFormat f = new DecimalFormat("#0.0#");
String [] numValues = new String [] {"0.32","0.45","0.65","0.56","0.55","0.96","0.42","0.92","0.05","0.76","0.87","0.27"};
System.out.println("\n\nusing double - \n\n");
for(int x=0; x<numValues.length; x++)
{
double tempAmount = (double)Double.parseDouble(numValues[x]);
dTotalAmount += tempAmount;
NumberFormat number = NumberFormat.getNumberInstance();
number.setMaximumFractionDigits(2);
String dTotalAmountString = number.format(dTotalAmount);
System.out.println("tempAmount = "+tempAmount+" & dTotalAmount = "+dTotalAmountString);
}
System.out.println("\n\nusing float - \n\n");
for(int x=0; x<numValues.length; x++)
{
float tempAmount = (float)Float.parseFloat(numValues[x]);
fTotalAmount += tempAmount;
NumberFormat number = NumberFormat.getNumberInstance();
number.setMaximumFractionDigits(2);
String fTotalAmountString = number.format(fTotalAmount);
System.out.println("tempAmount = "+tempAmount+" & fTotalAmount = "+fTotalAmountString);
}
}
}