Saqib Ali
Saqib Ali

Reputation: 12625

How can I convert a BigDecimal to a 2-decimal-place string?

I want to convert a BigDecimal object to a currency value to two decimal places. I don't want any rounding. How can I do it?

None of the following approaches worked:

v = BigDecimal("7.1762")
w = BigDecimal("4.2")

v.to_s('2F')            # => "7.17 62"
v.to_s('F')             # => "7.1762"
v.to_s('%0.2F')         # => "0.71762E1"
v.to_s('%0.2f')         # => "0.71762E1"
v.truncate(2).to_s('F') # => "7.17" # This one looks like it worked
w.truncate(2).to_s('F') # => "4.2"  # But it doesn't pad with the trailing zero(es)

Upvotes: 22

Views: 15585

Answers (4)

mwfearnley
mwfearnley

Reputation: 3669

The comments on the accepted answer contain important information.

It's been rightly pointed out that in older versions of Ruby, using "%.2f" % v will result in v being implicitly converted to a floating-point number, causing potential loss of precision/accuracy - e.g. "%.2f" % (10**24) == "999999999999999983222784.00"

You can convert BigDecimal to String accurately, even in older Rubies, by using .to_s("F"). This returns the number in fixed-point format, with a decimal point followed by zero or more decimal digits.

If you add "00" onto the end of the number (to ensure it has two or more decimal digits), then you can then strip it down using a regex like /.*\..{2}/ (any characters; a decimal point; then two more characters), so it only keeps the first two digits after the decimal point.

require 'bigdecimal'
w = BigDecimal("4.2")

 w.truncate(2).to_s("F")                       # => "4.2"
(w.truncate(2).to_s("F") + "00")               # => "4.200"
(w.truncate(2).to_s("F") + "00")[ /.*\..{2}/ ] # => "4.20"

Upvotes: 8

Darkhan
Darkhan

Reputation: 1308

I think this should work, although a little verbose:

money_amount = BigDecimal.new(100)
money_amount.truncate(2).to_s('F').ljust(money_amount.truncate(0).to_s('F').length + 1, '0')

Upvotes: 0

nishu
nishu

Reputation: 1493

Simply formatting with '%.2f' should work

v = BigDecimal("7.1233")
"%.2f" % v #=> "7.12"

v = BigDecimal("7.1")
"%.2f" % v #=> "7.10"

Upvotes: 6

falsetru
falsetru

Reputation: 369424

How about combining BigDecimal#truncate and String#%? :

"%.2f" % BigDecimal("7.1762").truncate(2)
# => "7.17"
"%.2f" % BigDecimal("4.2").truncate(2)
# => "4.20"

Upvotes: 24

Related Questions