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

まず、float を使用している場合は、それを使用することもできますBigDecimal。理由は明らかです。

したがって、コードへのコメントの最初の質問に答えるには: はい、BigDecimalインスタンス化は文字列で機能する必要があります。その理由は非常に明白です: 文字列化された数値は不正確になる傾向がなく、float 表現の制限を共有しません:

# 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

2 番目の質問に答えるに1.2E0は、 の科学的表記法です1.2。科学および金融数学で使用される非常に正確な計算で使用することを目的としているため、BigDecimal常に科学表記法を使用します。

あなたの例にコメントするには、使用BigDecimalは確かに正しい方法ですが、それを全体で使用し、それに応じて値を保存する必要があります。つまり、SQLデータベースに書き込む場合は、適切な精度の 10 進数形式を使用する必要があります。BigDecimalまた、そこからのすべてのインスタンス化は、 and neverのインスタンスでなければなりませんFloat。非常に小さなフラクチャや高い値を使用して財務計算を行う場合、財務アプリケーション全体で 1 つの float がパレードに雨を降らせる可能性があります。

お金の取り扱いの落とし穴から解放するには、ExchangeGemをご覧ください。BigDecimalISO4217互換のインスタンス化を使用してRubyアプリケーションでお金を表現する方法を持たせるために書きました。アプリケーション全体でお金を処理し、関連する落とし穴を回避するのに役立つ場合があります。

于 2013-10-20T20:14:50.513 に答える
1

この宝石を使用することをお勧めします: github/RubyMoney/money

それについてもう少し読んでください。すぐに使用できます。float も BigDecimal も使用せず、整数のみを使用します。したがって、精度の低下はまったくありません。

于 2013-10-20T17:23:53.017 に答える