How do I divide BigDecimal values in Ruby?
Division with BigDecimal requires more care than the other arithmetic operations. Some divisions produce infinitely repeating decimals, and without an explicit precision, BigDecimal may truncate the result at an unpredictable point. In this entry we will look at the available methods so you can choose the right approach for your situation.
The div Method (Recommended for Division)
Use div with an explicit digit count to control precision:
require 'bigdecimal'
a = BigDecimal("1")
b = BigDecimal("3")
a.div(b, 10)
# => 0.3333333333e0 (10 significant digits)
a.div(b, 20)
# => 0.33333333333333333333e0 (20 significant digits)
The digit count you pass is how many significant digits you want in the result. For most financial work, 10 to 20 is more than sufficient.
The / Operator
The / operator works, but uses a default precision that may not suit every case:
BigDecimal("1") / BigDecimal("3")
# => 0.3333333333333333333333333333333333333333e0
In practice, / works well for values that divide evenly. For repeating fractions, though, it is worth using div with an explicit precision argument — that way you are in control of where truncation happens rather than relying on the default behavior.
Integer Division
div with no precision argument performs integer (floor) division:
BigDecimal("10").div(BigDecimal("3"))
# => 3 (Integer result)
This matches Integer’s div behavior and is useful when you want the whole-number quotient. Note that the return value here is a plain Ruby Integer, not a BigDecimal.
divmod
To get both the quotient and remainder in one call:
q, r = BigDecimal("10").divmod(BigDecimal("3"))
# q => 3, r => BigDecimal("1")
Modulo
BigDecimal("10") % BigDecimal("3")
# => 0.1e1 (i.e., 1.0)
Avoiding Division Errors in Financial Code
We should always specify precision and round the result after division. For the common case of splitting a total among a number of recipients, a helper like this works well:
require 'bigdecimal'
def split_evenly(total, parts, decimal_places: 2)
share = total.div(BigDecimal(parts.to_s), decimal_places + 5)
share.round(decimal_places, BigDecimal::ROUND_HALF_UP)
end
total = BigDecimal("100.00")
split_evenly(total, 3).to_s("F") # => "33.33"
Note that splitting $100 three ways yields $33.33 multiplied by 3 equals $99.99 — the remaining cent must be allocated separately by business logic. This is not a bug in the code; it is an inherent property of dividing an indivisible unit. BigDecimal gives you the precision to detect and handle this correctly. Float would typically hide the discrepancy behind rounding noise, making the problem harder to reason about.