遇到Ruby舍入错误的问题

时间:2013-01-31 21:19:21

标签: ruby rounding rounding-error

我不能为我的生活弄清楚为什么我的generate_receipt方法为我的“导入的餐盘项目”返回54.9时它应该等于54.65。我编写了RSpec测试来确认数组确实返回了正确的值。

47.50 + 4.75 + 2.40 = 54.65

为什么它会返回54.9而不是54.65 ?!这种四舍五入发生在哪里?如何让它返回正确的值?我很难过。

describe :calcualte_sales_tax do

  it "should return the correct array" do
    calculate_sales_tax(@receipt).should eq([0, 4.75])
  end

end

describe :calculate_import_tax do

  it "should return the correct array" do
    calculate_import_tax(@receipt).should eq([0.50, 2.40])
  end

end 

@receipt = {
    "1"=>{:item=>"imported chocolates", :price=>10.00, :quantity=>1},    
    "2"=>{:item=>"imported dinner plates", :price=>47.50, :quantity=>1}
    }

def generate_receipt(receipt)
  n = 0
  while n < receipt.length 
    receipt["#{n+1}"][:price]+=calculate_sales_tax(receipt)[n]
    receipt["#{n+1}"][:price]+=calculate_import_tax(receipt)[n]
    n+=1
  end
  receipt
end

def calculate_import_tax(receipt)
  taxes = []
  receipt.each do |k,v|
    if (v[:item] =~ /imported/)
      subtotal = v[:price]
      # v[:price]+=(((((5 * subtotal)/100)*20.ceil) / 20.0))
      # taxes<<(5 * subtotal)/100
      taxes<<((5 * subtotal/100)*20).ceil/20.0.round(2)
    else
      taxes<<0
    end
  end
  taxes
end

def calculate_sales_tax(receipt)
  tax_free_items = ["book", "chocolate bar", "chocolates", "pills"]
  taxes = []
  receipt.each do |k,v|
    if (v[:item] =~ /chocolate\s/) ||
      (v[:item] =~ /chocolates/) || 
      (v[:item] =~ /book/) || 
      (v[:item] =~ /pills/)
      taxes<<0
    else
      subtotal = v[:price]
      # v[:price]+=(((((10 * subtotal)/100)*20.ceil) / 20.0))
      # taxes<<(10 * subtotal)/100
      taxes<<((10 * subtotal/100)*20).ceil/20.0
    end
  end
  taxes
end

2 个答案:

答案 0 :(得分:1)

def generate_receipt(receipt)
  n = 0
  while n < receipt.length
    puts receipt["#{n+1}"][:price].inspect
    receipt["#{n+1}"][:price]+=calculate_sales_tax(receipt)[n].round(2)
    puts receipt["#{n+1}"][:price].inspect
    puts calculate_import_tax(receipt)[n]
    receipt["#{n+1}"][:price]+=calculate_import_tax(receipt)[n].round(2)
    puts receipt["#{n+1}"][:price].inspect
    puts "-----"
    n+=1
  end
  receipt
end

返回:

47.5
52.25
2.65
54.9

该错误在您的calculate_import_tax方法中。它返回2.65,而不是2.40。

编辑:

得到它:)。

    receipt["#{n+1}"][:price]+=calculate_sales_tax(receipt)[n]
    receipt["#{n+1}"][:price]+=calculate_import_tax(receipt)[n]

这些行正在更新收据的价格。因此,您的测试是独立运行的,但销售税是在计算进口税之前修改原始价格 ...

答案 1 :(得分:0)

1)Ruby将没有小数部分的数字视为INTEGERS。除非计算包含浮点数,否则不会创建具有小数部分的结果。

2)10 * X / 100 * 20 == X * 2

3)法定计数可能需要指定的准确性,因此您可能需要使用专门的库进行此类数字运算。

快速解决方案是将代码更改为:

10.0 *小计/ 100.0 * 20.0

现在Ruby会将所有这些数字视为浮点数。