Rss Feed Tweeter button Facebook button Technorati button Reddit button Linkedin button Webonews button Delicious button Digg button Flickr button Stumbleupon button Newsvine button

A Waage Blog

Ruby, Rails, Life

Archive for November, 2011

Ruby floats, BigDecimals and money (currency)

with 3 comments

Fellow Ruby-ers, please be warned!!! DO NOT use Ruby floats when performing arithmetic calculations involving money!

My calculations work in IRB, so I was really confused when I ran into this weird situation where (what I thought was) a simple arithmetic calculation led to strange results in my unit tests (I cannot stress the importance of good unit testing!).

My backend calculation was basically this (simplified):

# arbitrary amounts for these two variables
percentage = 12
total_in_cents = 400

discount = percentage.to_f / 100.0
total_in_float = total_in_cents.to_f * 100.0
new_price = (total_in_float * discount ).round / 100

Now, it’s pretty obvious that 12% of (400 cents) $4.00 should just be $0.48 (48 cents)
However, my barrage of unit tests kept producing strange results where a simple calculation was returning incorrect results. Doing some research, I discovered a series of articles worth reading including:

Also, check out the Money gem – I’ve never used it personally, but people have said good things about it.

Heeding the advice I found online, I re-wrote all my money-related calculations using BigDecimals instead of Floats.

percentage = 12
total_in_cents = 400
discount = BigDecimal(percentage.to_s) / 100
total_in_float = BigDecimal(total_in_cents.to_s) * 100
new_price = (total_in_float * discount ).to_i / 100

After switching over from Floats to BigDecimals, my unit tests all passed!
Lesson learned and hope this heads-up helps you guys too.

Summary:
Use BigDecimals for money calculations and remember to write good UNIT TESTS!!

Written by Andrew Waage

November 9th, 2011 at 5:29 pm