Sinthorion
Sinthorion

Reputation: 327

How to deal with float rounding errors

I'm trying to implement basic 2D vector math functions for a game, in Java. They will be intensively used by the game, so I want them to be as fast as possible.

I started with integers as the vector coordinates because the game needs nothing more precise for the coordinates, but for all calculations I still would have to change to double vectors to get a clear result (eg. intersection between two lines).

Using doubles, there are rounding errors. I could simply ignore them and use something like

d1 - d2 <=  0.0001

to compare the values, but I assume with further calculations the error could sum up until it becomes significant. So I thought I could round them after every possibly unprecise operation, but that turned out to produce much worse results, assumedly because the program also rounds unexact values (eg. 0.33333333... -> 0.3333300...).

Using BigDecimal would be far too slow.

What is the best way to solve this problem?

Upvotes: 2

Views: 1359

Answers (2)

Patricia Shanahan
Patricia Shanahan

Reputation: 26175

This is a minor addition to the prior answer. When converting the float to an integer, it is important to round rather than just casting. In the following program, d is the largest double that is strictly less than 1.0. It could easily arise as the result of a calculation that would have result 1.0 in infinitely precise real number arithmetic.

The simple cast gets result 0. Rounding first gets result 1.

public class Test {
  public static void main(String[] args) {
    double d = Math.nextDown(1.0);
    System.out.println(d);
    System.out.println((int)d);
    System.out.println((int)Math.round(d));
  }
}

Output:

0.9999999999999999
0
1

Upvotes: 2

Evan Bechtol
Evan Bechtol

Reputation: 2865

Inaccurate Method

When you are using numbers that require Precise calculations you need to be sure that you aren't doing something like: (and this is what it seems like you are currently doing)

error accumulation

This will result in the accumulation of rounding errors as the process continues; giving you extremely innacurate data long-term. In the above example, you are actually rounding off the starting float 4 times, each time it becomes more and more inaccurate!


Accurate Method

A better and more accurate way of obtaining numbers is to do this: avoid accumulation of rounding errors

This will help you to avoid the accumulation of rounding errors because each calculation is based off of only 1 conversion and the results from that conversion are not compounded into the next calculation.

The best method of attack would be to start at the highest precision that is necessary, then convert on an as-needed basis, but leave the original intact. I would suggest you to follow the process from the second picture that I posted.

I started with integers as the vector coordinates because the game needs nothing more precise for the coordinates, but for all calculations I still would have to change to double vectors to get a clear result (eg. intersection between two lines).

It's important to note that you should not attempt to perform any type of rounding of your values if there is not noticeable impact on your end result; you will simply be doing more work for little to no gain, and may even suffer a performance decrease if done often enough.

Upvotes: 5

Related Questions