Ruby BigDecimal - 有概念问题

时间:2013-10-20 17:15:27

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

另外,如果你真的很棒,请帮助我在这种特殊情况下使用它。

2 个答案:

答案 0 :(得分: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.2 BigDecimalBigDecimal始终使用Scientific Notation,因为它用于科学和金融数学中使用的精确计算。

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

为了减轻您处理金钱的一些陷阱,请查看Scientific Notation。我写它是为了使用{{1}}和ISO4217兼容实例化在ruby应用程序中表示钱。它可以帮助您在整个申请过程中处理金钱,并避免一些陷阱。

答案 1 :(得分:1)

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

阅读更多相关信息。它开箱即用。它既使用也不浮动,也不使用BigDecimal,而只使用整数。所以根本没有精确损失。