I am trying to transfer money from one "account" to another:
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
Ok, I have this working really well with numbers operating as floats; however, as you know, floats are causing problems.
Please help me get an introductory grasp of how bigdecimal works.
Also, if you are really awesome, help me get it to work in this specific situation.
First, if it is working with floats, you can get it to work with BigDecimal
as well, and you should, because of the obvious reasons.
So, to answer your first question in the comments to your code: Yes, BigDecimal
instantiation has to work with strings, the reason is quite obvious: Stringified number values are not prone to any inaccuracies and do not share the limits of float representation:
# 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
To answer your second question, 1.2E0
is just Scientific Notation for 1.2
. BigDecimal
always uses Scientific Notation since it is intented for use in really precise calculations used in science and financial math.
To comment on your example, using BigDecimal
is surely the right way to go, but you have to use it throughout and store your values accordingly. That means that if you write to an SQL
database, you will have to use a decimal format with the right precision. Also, all instantiations thereform have to be instances of BigDecimal
and never Float
. One float in your entire finance application can rain on your parade if you intend to do financial math with really tiny fractures or high values.
To relieve you of some of the pitfalls of money handling, have a look at the Exchange
Gem. I wrote it to have a way of representing money in a ruby application using BigDecimal
and ISO4217 compatible instantiation. It may help you handling money throughout an application and avoid some of the pitfalls involved.