## Why You Shouldn’t Use Float for Currency (floating point issues – explained for Ruby and RoR)

It is a VERY BAD IDEEA to use floating point arithmetics to deal with currency. In most of the programming languages. Basically, because you’ll end up loosing money :). And this (on the great majority of cases) is not desirable đź™‚ .

I’ll show you some magic (that you may try at home):
```~\$ ruby --version ruby 1.8.7 (2009-06-12 patchlevel 174) [i486-linux] ~\$ irb irb(main):003:0> (10.12*100).to_i =>; 1011```

So, what just happened?

O.K. Now a little computer science lesson.

### Floating Point (vs Fixed Point)

From wikipedia:

Numbers are in general represented approximately to a fixed number ofÂ significant digits and scaled using anexponent. The base for the scaling is normally 2, 10 or 16. The typical number that can be represented exactly is of the form:

significant digits Ă—Â baseexponent

The termÂ floating point refers to the fact that theÂ radix point (decimal point, or, more commonly in computers, binary point) can “float”; that is, it can be placed anywhere relative to the significant digits of the number. This position is indicated separately in the internal representation, and floating-point representation can thus be thought of as a computer realization ofÂ scientific notation.

#### Short version:

– number is converted to scientific notation, and then coded in: sign bit, exponent, significand

– the precision is not fixed

– much larger range of representable numbers (much more than a fixed point representation), at the cost of precision

### Decimal to Floating Point conversion

In this representation, a large group of rational numbers can not be represented in binary with a fixed number of digits.

For example, if you would like to convert 0.7 in binary format (the example is from http://sandbox.mc.edu/~bennet/cs110/flt/dtof.html) you’ll end up having an ‘endless’ number (in fact, a repeating fraction, in binary).

 0.7 Ă— 2 = 1.4 1 Generate 1 and continue with the rest. 0.4 Ă— 2 = 0.8 0 Generate 0 and continue. 0.8 Ă— 2 = 1.6 1 Generate 1 and continue with the rest. 0.6 Ă— 2 = 1.2 1 Generate 1 and continue with the rest. 0.2 Ă— 2 = 0.4 0 Generate 0 and continue. 0.4 Ă— 2 = 0.8 0 Generate 0 and continue. 0.8 Ă— 2 = 1.6 1 Generate 1 and continue with the rest. 0.6 Ă— 2 = 1.2 1 Generate 1 and continue with the rest. â€¦

The reason why the process seems to continue endlessly is that it does. The number 7/10, which makes a perfectly reasonable decimal fraction, is a repeating fraction in binary, just as the faction 1/3 is a repeating fraction in decimal. (It repeats in binary as well.) We cannot represent this exactly as a floating point number. The closest we can come in four bits is .1011. Since we already have a leading 1, the best eight-bit number we can make is 1.1011.

A good simulator can be fount at http://babbage.cs.qc.edu/IEEE-754/Decimal.html

### And now back to our issue..

Ruby floating point values are stored in binary format.
10.12 (decimal) can not be represented exactly in binary:

>> sprintf(“%0.50f”, 10.12)
=> “10.11999999999999921840299066388979554176330566406250”

The default conversion of float to string (e.g., for output) rounds
to 6 (or maybe 7) places and truncates trailing zeros:

>> sprintf(“%0.6f”, a).sub(/0+\Z/,”)
=> “10.12”

Float#to_i truncates:

>> sprintf(“%0.50f”, 10.12 * 100 )
=> “1011.99999999999988631316227838397026062011718750000000”
>> (10.12 * 100).to_i
=> 1011

A very usefull add/sub/mul/div can be found at http://www.ecs.umass.edu/ece/koren/arith/simulator/FPMul/ . A more detailedÂ explanation from there:

```A    + 1.0100001111010111000010100011110101110000101000111101 *23 = 10.12
B    + 1.1001000000000000000000000000000000000000000000000000 *26 = 100

A*B  + 1.1111100111111111111111111111111111111111111111111111|011 *29

Postnormalization Step
A*B  + 1.1111100111111111111111111111111111111111111111111111|01 *29

Round to Zero
A*B  + 1.1111100111111111111111111111111111111111111111111111 *29 = 1011.9999999999999```

### Further references

Wikipedia provides even more examples of accuracy problems:http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.

### One Response

You will find the code for a program that calculates loan information here testerCodeTest.zip. Given a principal, interest rate, and term, the program will determine if these inputs are valid and inform the user of the amount of interest due at the end of the loan period. (Assume no payments and no compounding interest.) This is a simple application that is executed on the command line by changing the lib/directory and using the following command:

ruby interest_calculator.rb {PRINCIPAL} {INTEREST RATE} {TERM}
The requirements are listed below. Your assignment is to develop a set of automated acceptance tests for this software. For this exercise we will define acceptance tests as tests that investigate a system to determine whether it correctly implements a given responsibility. You may or may not find defects.

1.The Amount will be equal to Principal x (Interest Rate / 100) x Term in years
2.Term must be entered as an integer in months
3.Principal must be entered as whole dollars, no cents
4.The system will parse out commas and %
5.The Interest Rate will be considered an annual rate and must be entered as a percentage
6.The system will round the entered rate to hundredths of a percent
7.The rate cannot be negative and cannot be greater than 100
8.If a term is not entered, it is assumed to be one year