Floating Point Imprecision

If you are working with financial data one thing you need to have a decent grasp on is the idea of floating point imprecision.

What is floating point imprecision?

Floating point imprecision stems from the problem of trying to store numbers like 1/10 or (.10) in a computer with a binary number system with a finite amount of numbers.

Why does the computer have trouble storing the number .10 in binary? This is actually not an issue with the computer but a mathmatical consquence of using a binary number system.

To illustrate, lets go over a fractional number that behaves the same way in our decimal number system…

How do you express the fraction 1/3 in decimal? You probably know that dividing 1 by 3 gives .333333333 with the 3 repeating forever. To precisely express this number you would need a number system with an infinite amount of numbers.

Due to the way in which binary works .10 is such a number for binary. What would .10 look like in binary?

0.00011001100110011001100110011001100110011001100110011001100110...

So, as you can see, to properly represent this number we would need an infinite amount of numbers after the binary point. Obviously, we do not have an infinite amount of space available in a computer and so the computer must calculate an approximate value.

It turns out that most fractional decimals cannot be represented precisely in binary and so there are a lot of fractional decimals that are approximated when stored in the computer.

What this all means is that if you are storing currency as a float then most of the calculations you are performing are not entirely correct. Let’s take a look at this simple C program to prove what I mean. As part of the example lets say that you use variables a and b to represent $.33 and $.10 respectively.

#include <stdio.h>

int main(void)
{


    float a = .33;
    float b = .10;

    float c = a + b;

    printf("%.2f\n", c);
}

You compile and run your program and C gives you back

> 0.43

You think that everything is good, because $0.33 + $0.10 does indeed equal $0.43. However, what you cant see is that the number returned to you is not actually .43. Let’s change our printf statement to printf("%.100f\n", c); so that C will show 100 numbers after the decimal point and then re-run our code:

>0.4300000071525573730468750000000000000000000000000000000000000000000000000000000000000000000000000000

Now you can see the problem. Your number is not at all .43! This example wouldn’t show rounding errors that you would quickly notice. However, what if we changed variable b from .10 to 1000000.00 in order to represent us adding 33 cents to 1 million dollars?

The number we get back would be after running the program with that change would be:

>1000000.3125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Wow! And that is how quickly you can start performing calculations where people start to notice things like several cents missing. This is why you should NEVER store currency using a floating point data type!

So, What’s the Solution?

Many modern programming lanuages have a special decimal data type that you can use to calculate currency with more exact precision. If you are using an older lanuage like C that doesn’t have a decimal data type built in then you can use integers to store currency by recording everything in cents.

As the below program shows you can use the float type to input and then print your currency. The main thing to avoid is performing any operations on your currency unless its stored as an integer.

#include <stdio.h>
#include <math.h>

int main(void)
{

    float a,b;
    int money1, money2, money3;
    float x, y, z;

    a = .33;
    b = 1000000.00;


    x = .33;
    y = 1000000.00;
    z = x + y;

    money1 = round(a * 100);
    money2 = round(b * 100);
    money3 = money1 + money2;

    printf("Using integers the result of adding .33 and 1,000,000.00 is: %.2f\n", money3 / 100.0);
    printf("Using floats the result .33 and 1,000,000.00 is: %.2f\n", z);

}

This program prints out the following results:

> Using integers the result of adding .33 and 1,000,000.00 is: 1000000.33
> Using floats the result .33 and 1,000,000.00 is: 1000000.31

Be sure to let me know any tips you have about storing currencies or if you see any issues with the above! I am fascinated with learning as much as possible about the best techniques for handling currency and about any of the gotchas along the way!