This article is a response to http://vladzloteanu.wordpress.com/2010/01/06/ruby-on-rails-interview-questions-update/

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×base^{exponent}The term

floating pointrefers 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 *2^{3}= 10.12 B + 1.1001000000000000000000000000000000000000000000000000 *2^{6}= 100

A*B + 1.1111100111111111111111111111111111111111111111111111|011 *2^{9}

## Postnormalization Step

A*B + 1.1111100111111111111111111111111111111111111111111111|01 *2^{9}

## Round to Zero

A*B + 1.1111100111111111111111111111111111111111111111111111 *2^{9}= 1011.9999999999999

**Further references**

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

Filed under: ActiveRecord, Currency, Data Modelling, ruby-on-rails Tagged: | currency, decimal, float, floating point issues, interview questions, rails, ruby

jony, on January 15, 2010 at 11:20 PM said:Assignment(Can anyone please help me out to write the code)

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.

Business Rules:

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

9.Principal and Interest Rate are required fields

10.Principal must be greater than zero and less than 10 million

Expected Results

You may use any Ruby acceptance testing frameworks of your choosing (Cucumber, Test::Unit, RSpec, etc…). Your acceptance tests should be able to be run with a simple command and output the test results in a readable manner.

What To Submit

Your files should be sent in a zip archive. Please make sure to include source files and build files in the archive (if applicable), along with a README file that describes how to build it and how to run it. You should also list the required libraries and versions, including the version of Ruby used for your solution.