ruby on rails - Float vs Decimal in ActiveRecord

ID : 10353

viewed : 31

Tags : ruby-on-railstypesfloating-pointdecimalrails-activerecordruby-on-rails

Top 5 Answer for ruby on rails - Float vs Decimal in ActiveRecord

vote vote

90

I remember my CompSci professor saying never to use floats for currency.

The reason for that is how the IEEE specification defines floats in binary format. Basically, it stores sign, fraction and exponent to represent a Float. It's like a scientific notation for binary (something like +1.43*10^2). Because of that, it is impossible to store fractions and decimals in Float exactly.

That's why there is a Decimal format. If you do this:

irb:001:0> "%.47f" % (1.0/10) => "0.10000000000000000555111512312578270211815834045" # not "0.1"! 

whereas if you just do

irb:002:0> (1.0/10).to_s => "0.1" # the interprer rounds the number for you 

So if you are dealing with small fractions, like compounding interests, or maybe even geolocation, I would highly recommend Decimal format, since in decimal format 1.0/10 is exactly 0.1.

However, it should be noted that despite being less accurate, floats are processed faster. Here's a benchmark:

require "benchmark"  require "bigdecimal"   d = BigDecimal.new(3)  f = Float(3)  time_decimal = Benchmark.measure{ (1..10000000).each { |i| d * d } }  time_float = Benchmark.measure{ (1..10000000).each { |i| f * f } }  puts time_decimal  #=> 6.770960 seconds  puts time_float  #=> 0.988070 seconds 

Answer

Use float when you don't care about precision too much. For example, some scientific simulations and calculations only need up to 3 or 4 significant digits. This is useful in trading off accuracy for speed. Since they don't need precision as much as speed, they would use float.

Use decimal if you are dealing with numbers that need to be precise and sum up to correct number (like compounding interests and money-related things). Remember: if you need precision, then you should always use decimal.

vote vote

88

In Rails 3.2.18, :decimal turns into :integer when using SQLServer, but it works fine in SQLite. Switching to :float solved this issue for us.

The lesson learned is "always use homogeneous development and deployment databases!"

vote vote

79

In Rails 4.1.0, I have faced problem with saving latitude and longitude to MySql database. It can't save large fraction number with float data type. And I change the data type to decimal and working for me.

   def change     change_column :cities, :latitude, :decimal, :precision => 15, :scale => 13     change_column :cities, :longitude, :decimal, :precision => 15, :scale => 13   end 
vote vote

69

vote vote

56

The prior value for the key is dropped and replaced with the new one.

If you'd like to keep all the values a key is given, you might consider implementing something like this:

import org.apache.commons.collections.MultiHashMap; import java.util.Set; import java.util.Map; import java.util.Iterator; import java.util.List; public class MultiMapExample {     public static void main(String[] args) {       MultiHashMap mp=new MultiHashMap();       mp.put("a", 10);       mp.put("a", 11);       mp.put("a", 12);       mp.put("b", 13);       mp.put("c", 14);       mp.put("e", 15);       List list = null;        Set set = mp.entrySet();       Iterator i = set.iterator();       while(i.hasNext()) {          Map.Entry me = (Map.Entry)i.next();          list=(List)mp.get(me.getKey());           for(int j=0;j<list.size();j++)          {           System.out.println(me.getKey()+": value :"+list.get(j));          }       }    } } 

Top 3 video Explaining ruby on rails - Float vs Decimal in ActiveRecord

Related QUESTION?