ruby - Float not equal after division followed by multiplication -


i'm testing small , simple library made in ruby. goal convert eur cny , vice versa. simple.

i tested sure works got unexpected issue. when use to_euro followed to_yuan should go original amount ; doesn't happen. tried .to_f or round(2) amount variable fix tests, raise new ones, it's never equal expect globally ; i'm running out of idea fix :(

class currency    attr_reader :amount, :currency    def initialize(amount, currency='eur')     @amount = amount     @currency = currency   end    def to_yuan     update_currency!('cny', amount * settings.instance.exchange_rate_to_yuan)   end    def to_euro     update_currency!('eur', amount / settings.instance.exchange_rate_to_yuan)   end    def display     "%.2f #{current_symbol}" % amount   end    private    def current_symbol     if currency == 'eur'       symbol = settings.instance.supplier_currency.symbol     elsif currency == 'cny'       symbol = settings.instance.platform_currency.symbol     end   end    def update_currency!(new_currency, new_amount)     unless new_currency == currency       @currency = new_currency       @amount = new_amount     end     self   end  end 

tests

describe currency    let(:rate) { settings.instance.exchange_rate_to_yuan.to_f }    context "#to_yuan"      "should return currency object"       expect(currency.new(20).to_yuan).to be_a(currency)     end      "should convert yuan"       expect(currency.new(20).to_yuan.amount).to eql(20.00 * rate)     end      "should convert euro , yuan"       # state data test       currency = currency.new(150, 'cny')       expect(currency.to_euro).to be_a(currency)       expect(currency.to_yuan).to be_a(currency)       expect(currency.amount).to eql(150.00)     end    end    context "#to_euro"      "should convert euro"       expect(currency.new(150, 'cny').to_euro.amount).to eql(150 / rate)     end    end    context "#display"      "should display euros"       expect(currency.new(10, 'eur').display).to eql("10.00 €")     end      "should display yuan"       expect(currency.new(60.50, 'cny').display).to eql("60.50 ¥")     end    end   end 

and here's rspec result

enter image description here

i'm pretty sure problem common, idea how solve ?

float isn't exact number representation, stated in ruby docs:

float objects represent inexact real numbers using native architecture's double-precision floating point representation.

this not ruby fault, floats can represented fixed number of bytes , therefor cannot store decimal numbers correctly.

alternatively, can use ruby rational or bigdecimal

its common use money gem when dealing currency , money conversion.


Comments