2016-08-01 104 views
0

我正在測試一個我在Ruby中製作的小而簡單的庫。目標是從EUR轉換爲CNY,反之亦然。簡單。除法後乘以浮點不等於

我測試了它,以確保一切正常,但我得到了意想不到的問題。當我使用to_euro後跟to_yuan時,應該回到原來的amount;它不會發生。我試圖.to_fround(2)amount變量,它修復了一些測試,提出了新的測試,但它永遠不會等於我所期望的全局;我跑出來的想法來解決這個問題:(

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 

測試

describe Currency do 

    let(:rate) { Settings.instance.exchange_rate_to_yuan.to_f } 

    context "#to_yuan" do 

    it "should return Currency object" do 
     expect(Currency.new(20).to_yuan).to be_a(Currency) 
    end 

    it "should convert to yuan" do 
     expect(Currency.new(20).to_yuan.amount).to eql(20.00 * rate) 
    end 

    it "should convert to euro and back to yuan" do 
     # 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" do 

    it "should convert to euro" do 
     expect(Currency.new(150, 'CNY').to_euro.amount).to eql(150/rate) 
    end 

    end 

    context "#display" do 

    it "should display euros" do 
     expect(Currency.new(10, 'EUR').display).to eql("10.00 €") 
    end 

    it "should display yuan" do 
     expect(Currency.new(60.50, 'CNY').display).to eql("60.50 ¥") 
    end 

    end 


end 

這是我的RSpec的結果

enter image description here

我敢肯定這個問題很常見,任何想法如何解決很容易嗎?

+3

如果您需要精確的結果,請勿使用Float,但使用BigDecimal。 – user1934428

+0

使用乘法而不是除法。 –

+0

Float幾乎總是不準確的[Nice條款在大多數編程語言中這是如此](http://itreallymatters.net/post/386327451/floating-point-arithmetics-in-19-programming#.V59qqaK1VwA)。對於精確的數學使用'BigDecimal'。 – engineersmnky

回答

1

浮法不是一個確切的數字表示,如在ruby docs指出:

浮動對象表示使用本機體系結構的雙精度浮點表示不精確實數。

這不是ruby錯誤,因爲浮點數只能由固定數量的字節表示,因此無法正確存儲十進制數。

或者,你可以使用紅寶石RationalBigDecimal

它也是相當普遍與貨幣和貨幣轉換處理時使用的money gem