Module: Philiprehberger::Money::Allocation
- Included in:
- Philiprehberger::Money
- Defined in:
- lib/philiprehberger/money/allocation.rb
Overview
Fair allocation of money across ratios using the largest remainder method
Instance Method Summary collapse
-
#allocate(ratios) ⇒ Array<Money>
Split money by ratios, distributing remainder cents fairly.
Instance Method Details
#allocate(ratios) ⇒ Array<Money>
Split money by ratios, distributing remainder cents fairly
Uses the largest remainder method: calculate exact shares, floor each, then distribute remaining cents to shares with the largest fractional parts.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/philiprehberger/money/allocation.rb', line 14 def allocate(ratios) total_ratio = ratios.sum(BigDecimal('0')) exact_shares = ratios.map { |r| BigDecimal(cents.to_s) * BigDecimal(r.to_s) / total_ratio } floored = exact_shares.map { |s| s.floor.to_i } remainder = cents - floored.sum # Distribute remaining cents to shares with the largest fractional parts fractional_parts = exact_shares.each_with_index.map { |s, i| [s - s.floor, i] } fractional_parts.sort_by! { |frac, _i| -frac } remainder.abs.times do |n| idx = fractional_parts[n][1] floored[idx] += remainder.positive? ? 1 : -1 end floored.map { |c| self.class.new(c, currency.code) } end |