Currency calculations

As part of your new program, you need to 'count' money from £0.0 to £1.00 in steps of 10p, but you notice that your computer generates some odd results. So you compile a table of the actual results versus the expected results, and the output is as follows:

Expected Result Actual Result Pass/Fail
£0.0 £0.0 Pass
£0.1 £0.1 Pass
£0.2 £0.2 Pass
£0.3 £0.30000000000000004 Fail
£0.4 £0.4 Pass
£0.5 £0.5 Pass
£0.6 £0.6 Pass
£0.7 £0.7 Pass
£0.8 £0.7999999999999999 Fail
£0.9 £0.8999999999999999 Fail
£1.0 £0.9999999999999999 Fail

Why is the program's answer different from what you might expect--surely adding 10p is simple?

A fault in the computer A fault/bug in the language Floating-point operations aren't accurate

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

1 solution

Tony Flury
Jun 16, 2016

Whenever you see this sort of output it is almost always the result of a bug in your application, specifically you have used a floating point type to represent your currency values, and floating point numbers cannot represent all values accurately.

The normal floating point number type cannot represent 0.1 (10p) or 0.01 (1p) accurately, and therefore calculations with them will result in accurate answers, especially when those calculations are repeated. To fix this issue you have 3 main options :

  1. Perform all your calculations as integers in the lowest unit (in this case 1p), and then format the output correctly. Integer mathematics is always precise (unless you overflow your integer values), and you only have complexity in your input/output formatting (and even then your code will only be dividing by 100 or modulo 100.

  2. Use a fixed precision number type. In many languages this will add complexity to your code, or more dependencies (as your application needs another library), both of which can lead to faults in your application.

  3. Continue to use floating point, but make sure you format the output to round to 2 decimal places. While this may seem the quick fix it is nearly always the wrong answer, as you are still getting inaccurate results but hiding the issues behind your formatting.

It is recommended that you should always use Option 1 - as it is adds the least complexity and will always provide accurate calculations.

As proof of the inaccuracies of floating point numbers (in Python3, but C and other languages are likely to be similar) :

>>> a = 0.1
>>> b = 0.01 + 0.01 + 0.01 + 0.01 + 0.01 + 0.01 + 0.01 + 0.01 + 0.01 + 0.01    # Add 0.01 ten times
>>> a == b                                                           # Logic says that  0.1 is equal to 0.01 * 10  - surely
False
>>> a 
0.1
>>> b
0.09999999999999999

Oh, now that is brilliant. So, could you shed some light on how floating point arithmetic works, from a numerical perspective, and possibly architectural perspective?

Sherif Azmy - 4 years, 11 months ago

Log in to reply

On most computers, floating points values are implemenetd to the IEEE 754 Standard .

The linked article goes into a lot of detail about how the numbers are stored (and there are separate and detailed algorithms implemented as to how to display those numbers as a human readable value).

The crux of the issue is that all values are represted in binary, and in binary fractions many fractional values cannot be accurately represented in a finite number of binary digits.

You know that in binary, an integer is represented as a sequence of 1s & 0s, where the 1s & 0s indicate which powers of 2 are summed together :

5 = 10 1 2 = 1 × 2 2 + 0 × 2 1 + 1 × 2 0 = 4 + 1 5 = 101_2 = 1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 = 4 + 1

For fractions we still have 1s & 0s, where they now indicate which powers of 1 2 \frac12 are summed together :

3 4 = 0.11 = 1 × 1 2 1 + 1 × 1 2 2 = 1 2 + 1 4 \frac{3}{4} = 0.11 = 1 \times \frac12^1 + 1 \times \frac12^2 = \frac 12 + \frac 14

You can see from this that some values are difficult to represent as a binary fraction - and some are impossible in a fixed number of binary digits :

1 10 = 0.0001100110011... = 1 16 + 1 32 + 1 256 + 1 512 + 1 4096 + 1 8192 . . . \frac{1}{10} = 0.0001100110011... = \frac{1}{16} + \frac{1}{32} + \frac{1}{256} + \frac{1}{512} + \frac{1}{4096} + \frac{1}{8192}... (this sum continues indefinitely as far as I know).

Architecturally speaking, the floating point format was designed to optimise the balance between memory usage (for storage), computation costs, and the accuracy of the value which is represented. Computations are relatively easy in this format (as they are the same as normal binary addition for integers, which Processors are already designed for).

There is an alterantive format which has been implemented on some procesors and some langauges - which is effectively binary coded decimal fractions - where instead of the value being stored in binary, each decimal digit from 0 to 9 is stored in a sequence of 4 bits. The issue with this format is that although 4 bits are used to represent 10 possible values, the same bit string could actually represent 16 different values , and therefore the format is not space efficient. It is also complex for a computer to execute computations on such values, and often the processors had specific sections of the CPU designed to execute Binary coded decimal formats. It is worth nothing that even this format can't represent all values accurately - for instance just like using decimal fractions you cannot represent 1 3 \frac 13 accurately - the decimal 0.3333333 continues indefinitely.

I hope this helps,

Tony Flury - 4 years, 11 months ago

Log in to reply

Ah, thanks a lot for the extra information, Tony. :) I appreciate it.

Sherif Azmy - 4 years, 11 months ago

Imo, any solution/explanation about floating point arithmetic is incomplete without a link to the following paper:

What every computer scientist should know about floating-point arithmetic

Prasun Biswas - 4 years, 11 months ago

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...