Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Floating Point Variable Not Working

Tags:

java

When I run the program posted below, I get some weird results.

The program is suppose to print a message at multiples of when i = 5,000,000, however, it sometimes prints the message when i is not equal to a multiple of 5 million.

When I change the numberOfTests from 50 million to 5 million, the program runs fine. Also, if I change it from a float to a double, the program works fine as well.

What's wrong with my current code? Is the floating variable not working? Why is this happening? How can I prevent this in the future?

public static void main(String[] args)
{
    final int numberOfTests = 50 * 1000 * 1000;
    final float IncrementsPercentageToPrintResults = .10f;

    for(int i = 1; i <= numberOfTests; i++)
    {
        if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0)
        {
            System.out.println("Currently at " + (int) (((float) i / numberOfTests) * 100) + "%." );
            System.out.println(" i = " + i);                
        }   
    }   

}

Output:
Currently at 10%.
 i = 5000000
Currently at 20%.
 i = 10000000
Currently at 30%.
 i = 15000000
Currently at 40%.
 i = 19999999
Currently at 40%.
 i = 20000000
Currently at 40%.
 i = 20000001
Currently at 50%.
 i = 24999999
Currently at 50%.
 i = 25000000
Currently at 50%.
 i = 25000001
Currently at 60%.
 i = 29999999
Currently at 60%.
 i = 30000000
Currently at 60%.
 i = 30000001
Currently at 70%.
 i = 34999998
Currently at 70%.
 i = 34999999
Currently at 70%.
 i = 35000000
Currently at 70%.
 i = 35000001
Currently at 70%.
 i = 35000002
Currently at 80%.
 i = 39999998
Currently at 80%.
 i = 39999999
Currently at 80%.
 i = 40000000
Currently at 80%.
 i = 40000001
Currently at 80%.
 i = 40000002
Currently at 90%.
 i = 44999998
Currently at 90%.
 i = 44999999
Currently at 90%.
 i = 45000000
Currently at 90%.
 i = 45000001
Currently at 90%.
 i = 45000002
Currently at 100%.
 i = 49999998
Currently at 100%.
 i = 49999999
Currently at 100%.
 i = 50000000
like image 557
Programmer Avatar asked Mar 30 '26 02:03

Programmer


1 Answers

This happens because of something called numeric promotion. Any time there is an expression involving two different types of numbers, the "narrowest" numbers are promoted to the "widest" numbers.

You have an expression like this here:

if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0)

Here, IncrementPercentageToPrintResults is a float so it happens that every other number in the expression gets promoted to float.

The problem is that for large numbers, float is actually less precise than an int.

So actually, for a float, after ±2^24 (±16,777,216), it cannot represent odd numbers anymore. So a number like 19,999,999 gets rounded to 20,000,000. The larger the number is, the more imprecise floating point becomes.

There are a number of solutions and the best one here is to simply not multiply an int by a floating point fraction to do division. Just divide numberOfTests by 10:

if(i % (IncrementsPercentageToPrintResults / 10) == 0)

The other OK solution is to use double instead of float because double can represent all values in an int exactly.

Another is, if you really want, to cast the resulting float to an int:

(int)(IncrementsPercentageToPrintResults * numberOfTests)

However, the multiplication expression is still rounded to float so that only works here because float can represent the value 5,000,000 exactly. Sometimes a cast like that is necessary but here it's not. Just use division or double.

The two obligatory links are:

  • What Every Computer Scientist Should Know About Floating-Point Arithmetic
  • The Floating-Point Guide
like image 50
Radiodef Avatar answered Apr 02 '26 04:04

Radiodef



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!