Search code examples
javadatetimeprecisiondate-arithmeticdate-difference

Different results of different, but equal math operations on float in Java


Question about Java math operations on float and int data types.

I have to calculate the date difference in years between two dates.

The code:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Object date = obj.getInfoItem().getInfoValue();
 
Date today = new Date();
Date birthDate = null;
float dateDiff;
int age0, age1;
 
try {
    // unify the date format
    birthDate = format.parse(date.toString());
    today = format.parse(format.format(today));
} catch (ParseException e) {
    e.printStackTrace();
}
 
// calculate the age in years with round    
dateDiff = today.getTime() - birthDate.getTime();
age0     = (int)((dateDiff / (24 * 60 * 60 * 1000)) / 365);
age1     = (int)(dateDiff / (365 * 24 * 60 * 60 * 1000));

Since the date difference in Java is calculated in milliseconds, thus we have to do some housekeeping work after calculation and convert received result from milliseconds to years.

After code execution, I got the following results in debugger:

dateDiff = 8.4896639E11  
age0 = 26  
age1 = 577

age0 is a correct result.

Since both operations on age0 and age1 are mathematically equal, why outcomes are different? Why there is a difference between operations «(float / (a\*b\*c)) / d» and «(float / (a\*b\*c\*d))», where a, b, c, d are int.


Solution

  • To expand on Sotirios' comment: The integer literals 365, 24, 60, and 1000 all have type int. Therefore, multiplication will be performed using the int type. Since the mathematical result is 31536000000, and the largest possible int is 2147483648, the result overflows and the result will wrap around. The result will thus be the int whose value is equivalent to 31536000000 modulo 232, which is 1471228928. Only then is it converted to a float to be divided into dateDiff. Appending an L to the end of any of the integer literals will fix it, since now at least one of the multiplications will be performed using long. But it might be clearer to change 365 to 365.0 (or 365f). (Actually, @Chill's suggestion to use f on all the constants appears best to me, although it's not really necessary.)