Ruby BigDecimal - 有概念问题



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

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 的工作原理。

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

首先,如果它与浮点数一起工作,你也可以让它与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.2的科学记数法。 BigDecimal总是使用科学记数法,因为它旨在用于科学和金融数学中使用的真正精确的计算。

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

为了减轻您处理金钱的一些陷阱,请查看Exchange宝石。我编写它是为了有一种使用 BigDecimal 和ISO4217兼容实例在 ruby 应用程序中表示货币的方法。它可以帮助您在整个申请过程中处理资金并避免所涉及的一些陷阱。

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

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

最新更新