How can I convert a BigDecimal to a 2-decimal-place string?
How about combining BigDecimal#truncate
and String#%
? :
"%.2f" % BigDecimal("7.1762").truncate(2)
# => "7.17"
"%.2f" % BigDecimal("4.2").truncate(2)
# => "4.20"
Ruby output numbers to 2 decimal places
First of all, you should not use floats to represent monetary values. So instead, let's use a more appropriate type: (there's also the Ruby Money gem)
require 'bigdecimal'
my_hash = {
foo: BigDecimal.new('1.00'),
bar: BigDecimal.new('4.50'),
abc: BigDecimal.new('0.00'),
xyz: BigDecimal.new('1.23')
}
There are several options to represent monetary values. All of the following JSON strings are valid according to the JSON specification and all require special treatment upon parsing. It's up to you to choose the most appropriate.
Note: I'm implementing a custom
to_json
method to convert theBigDecimal
instances to JSON using Ruby's default JSON library. This is just for demonstration purposes, you should generally not patch core (or stdlib) classes.
1. Numbers with fixed precision
This is what you asked for. Note that many JSON libraries will parse these numbers as floating point values by default.
class BigDecimal
def to_json(*)
'%.2f' % self
end
end
puts my_hash.to_json
Output:
{"foo":1.00,"bar":4.50,"abc":0.00,"xyz":1.23}
2. Numbers as strings
This will work across all JSON libraries, but storing numbers as strings doesn't look quite right to me.
class BigDecimal
def to_json(*)
'"%.2f"' % self
end
end
puts my_hash.to_json
Output:
{"foo":"1.00","bar":"4.50","abc":"0.00","xyz":"1.23"}
3. Numbers as integers
Instead of representing monetary values as fractional numbers, you simply output the cents as whole numbers. This is what I usually do.
class BigDecimal
def to_json(*)
(self * 100).to_i.to_s
end
end
puts my_hash.to_json
Output:
{"foo":100,"bar":450,"abc":0,"xyz":123}
Ruby big decimal with 2 numbers after the decimal point
It can, but this is a kind of output format.
sprintf( "%.02f", a)
# => "1.00"
You can define a method like this:
class BigDecimal
def to_string
sprintf( "%.02f", self)
end
end
a.to_string
=> "1.00"
As suggested by @CarySwoveland, you also can write like this
sprintf( "%.02f" % a)
sprintf( "%.02f %.02f %.02f" % [a, b, c])
How do I format a BigDecimal to only show as many decimal digits as needed?
For your views, look at the methods from the NumberHelper, in particular the number_with_precision
, http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_with_precision
Particularly, you want the strip_insignificant_zeros option.
Ruby convert 2 decimal string into a number and keep the two decimals
Float
You can convert "5565.80" to a float :
value = "5565.80".to_f
# 5565.8
And then display the value with two decimals :
'%.2f' % value
# "5565.80"
A float has double-precision in Ruby, so your value will actually be :
5565.800000000000181898940354...
As a float, you cannot save exactly 5565.80
.
Exact values
Integer
If you want exact values (e.g. for currency), you could use integers for cents :
"5565.80".delete('.').to_i
# 556580
When you need the corresponding float, you could divide it by 100.0
.
Decimal
If you're working with a database, you could use decimal(20,2)
or something equivalent.
BigDecimal
You could also use BigDecimal
:
require 'bigdecimal'
BigDecimal.new("5565.80")
It will save the exact value but will be much slower than int or float.
Handling BigDecimal trailing zero's Ruby
sprintf("%2.f", v)
should work. The options for sprintf
can be found at
http://ruby-doc.org/core-2.3.0/Kernel.html#method-i-sprintf
Also, if you're using Rails, the number_with_precision
helper is probably easier to use - you can find the documentation at http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_with_precision
Parse a decimal value from a String in Ruby
(Found it myself after a bit of digging)
BigDecimal is the standard Ruby fixed-point type, and it's constructor takes a String and handles the parsing for you:
BigDecimal.new("123.45")
How do you round a float to 2 decimal places in JRuby?
Float#round can take a parameter in Ruby 1.9, not in Ruby 1.8. JRuby defaults to 1.8, but it is capable of running in 1.9 mode.
Related Topics
Scraping a Site That Requires Login Username and Password on Two Separate Pages
Algorithm to Print All Valid Combations of N Pairs of Parenthesis
How to Use Before :All with Capybara
Include Erb Delimiters Inside of a String in an Erb Block
Rails Gem to Break a Paragraph into Series of Sentences
Can't Install Ruby via Rvm, Error Running '_Rvm_Make -J4' on Ubuntu 22.04
Ruby How to Merge Two CSV Files with Slightly Different Headers
Rotating Letters in a String So That Each Letter Is Shifted to Another Letter by N Places
Best Way to Find_Or_Create_By_Id But Update the Attributes If the Record Is Found
Nokogiri Issues with Ruby on Rails
Overriding Model in Gem, Adding Callback and Methods
Uninstall Ruby on Rails on MAC Os X 10.6
Pg::Error: Error: Invalid Byte Sequence for Encoding "Utf8": 0Xfc
Error Creating Rails Db Using Rake Db:Create
Store Image in Database Using Rails Paperclip Plugin
What's the Best Way to Return an Enumerator::Lazy When Your Class Doesn't Define #Each
What Is the Equivalent to Rspec's 'It "Should …", Focus: True Do' in Minitest/Spec
Ruby Looks for Class Variable in the Object Instead of Specific Class