0

我正在尝试将钱从一个“帐户”转移到另一个:

puts ("\nTransfer how much?")

require 'bigdecimal'

amount = gets.chomp
amount = BigDecimal(amount) #<--Does BigDecimal have to work with strings???

puts ("\nTransfer to which account?")

acct_to = gets.chomp.to_i #<--Accounts are numbered previously for the user.
acct_to = acct_to - 1 #<--Since the account numbers are stored in an array...

#having a problem with #{amount} in the string below.  It is showing something like
    #1.2E0???
puts ("\nTransfer #{amount} from #{names[acct_from]} to #{names[acct_to]}? [1 - yes] / [2 - no]")

#Makes transfer==============================

e = gets.chomp.to_i

    if e == 1

        puts ("\nTransferring!")

        sum1 = 0
        sum2 = 0

        sum1 = BigDecimal(ac[names[acct_from]].to_s) #<-- ac is a hash
        sum2 = BigDecimal(ac[names[acct_to]].to_s)

        ac[names[acct_from]] = sum1 - amount
        ac[names[acct_to]] = sum2 + amount

        puts ("\n#{names[acct_from]}'s new balance is #{ac[names[acct_from]]}.")
        puts ("\n#{names[acct_to]}'s new balance is #{ac[names[acct_to]]}.")

    end


end 

好的,我可以很好地处理作为浮点数的数字;但是,如您所知,浮点数会引起问题。

请帮助我了解 bigdecimal 的工作原理。

另外,如果你真的很棒,请帮助我让它在这种特定情况下工作。

4

2 回答 2

2

首先,如果它使用浮点数,您也可以使用它BigDecimal,并且您应该使用它,因为显而易见的原因。

因此,要在代码的注释中回答您的第一个问题:是的,BigDecimal实例化必须与字符串一起使用,原因很明显:字符串化的数值不容易出现任何错误,并且不共享浮点表示的限制:

# Think of this number
float = 23.12323423142342348273498721348923748712340982137490823714089374

# Ruby will truncate its precision to 17, because Float's are not made for precise, but for fast calculation
float #=> 23.123234231423424

# Now, if BigDecimal would initialize with a float value, the precision would get lost on the way, too. Therefore, BigDecimal needs strings
big_decimal_from_float = BigDecimal.new(23.12323423142342348273498721348923748712340982137490823714089374.to_s)
big_decimal_from_string = BigDecimal.new("23.12323423142342348273498721348923748712340982137490823714089374")

# Now you'll see that the BigDecimal initialized "with a float value" will have lost some precision

要回答你的第二个问题,1.2E0只是科学记数法1.2BigDecimal始终使用科学记数法,因为它旨在用于科学和金融数学中使用的真正精确的计算。

要评论您的示例,使用BigDecimal肯定是正确的方法,但您必须始终使用它并相应地存储您的值。这意味着,如果您写入SQL数据库,则必须使用具有正确精度的十进制格式。此外,所有的实例化都必须是的实例BigDecimal并且从不Float。如果你打算用非常小的裂缝或高价值做金融数学,你整个金融应用程序中的一个浮动可能会影响你的游行。

为了减轻您处理金钱的一些陷阱,请查看ExchangeGem。我写它是为了在 ruby​​ 应用程序中使用BigDecimal和 ISO4217 兼容的实例化来表示金钱。它可以帮助您在整个应用程序中处理资金并避免一些涉及的陷阱。

于 2013-10-20T20:14:50.513 回答
1

我建议你使用这个 gem: github/RubyMoney/money

阅读更多关于它的内容。它开箱即用。它既不使用浮点数,也不使用 BigDecimal,而只是整数。所以完全没有精度损失。

于 2013-10-20T17:23:53.017 回答