Ruby BigDecimal to_s: Converting BigDecimal to String
BigDecimal’s to_s method returns a string in engineering notation by default, which tends to surprise developers who expect a plain decimal string. Knowing why this happens — and how to get the format you actually want — is worth a few minutes of attention.
Default Behavior
require 'bigdecimal'
BigDecimal("123.456").to_s
# => "0.123456e3"
The default format uses a 0. prefix with a power-of-ten exponent. This reflects BigDecimal’s internal representation, not what you would typically want to display to a user.
Getting a Plain Decimal String
Pass "F" (for fixed-point) to to_s and you get the familiar decimal format:
BigDecimal("123.456").to_s("F")
# => "123.456"
BigDecimal("0.0825").to_s("F")
# => "0.0825"
BigDecimal("1000").to_s("F")
# => "1000.0"
In practice, to_s("F") is what you will reach for whenever you need to display or serialize a BigDecimal value.
Engineering Notation with Grouping
You can also pass a digit-group width for the engineering format, which is occasionally useful for presenting large numbers with visual spacing:
BigDecimal("123456.789").to_s("3")
# => "123 456.789e0"
Formatting for Display
For display in financial applications, combine to_s("F") with Ruby’s built-in string formatting:
require 'bigdecimal'
price = BigDecimal("1234.5")
"$%.2f" % price.to_f # fast but loses precision
# => "$1234.50"
# Safer: format after rounding to the right scale
formatted = price.round(2).to_s("F")
# => "1234.5"
sprintf("$%s", price.round(2).to_s("F"))
# => "$1234.5"
Note the trade-off: using price.to_f before the format string is faster, but it routes the value through binary floating-point and surrenders BigDecimal’s precision. For financial output, rounding first and formatting the string directly is the safer approach.
For currency display with zero-padding, round first and then split manually:
def format_currency(amount)
rounded = amount.round(2).to_s("F")
integer_part, decimal_part = rounded.split(".")
decimal_part = (decimal_part || "").ljust(2, "0")[0, 2]
"$#{integer_part}.#{decimal_part}"
end
format_currency(BigDecimal("19.9")) # => "$19.90"
format_currency(BigDecimal("100")) # => "$100.00"
This helper ensures you always get exactly two decimal places regardless of the source value — important when displaying prices to end users.