Module: Amount::Allocation
- Included in:
- Amount
- Defined in:
- lib/amount/allocation.rb
Overview
Splitting and proportional allocation. Both operations return ‘[parts, remainder]`, preserving the invariant that the parts plus remainder always sum back to the receiver’s atomic value (including the sign).
Instance Method Summary collapse
-
#allocate(weights) ⇒ Array<(Array<Amount>, Amount)>
Allocates proportionally by integer weights and returns the leftover explicitly.
-
#split(n) ⇒ Array<(Array<Amount>, Amount)>
Splits into equal parts and returns the leftover explicitly.
Instance Method Details
#allocate(weights) ⇒ Array<(Array<Amount>, Amount)>
Allocates proportionally by integer weights and returns the leftover explicitly.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/amount/allocation.rb', line 41 def allocate(weights) raise ArgumentError, "weights must be non-empty" if weights.empty? raise ArgumentError, "weights must be non-negative integers" unless weights.all? { |weight| weight.is_a?(Integer) && weight >= 0 } total = weights.sum raise ArgumentError, "weights must sum to positive value" unless total.positive? sign = atomic_sign absolute_atomic = @atomic.abs allocations = weights.map { |weight| absolute_atomic * weight / total } remainder = absolute_atomic - allocations.sum parts = allocations.map { |allocation| build(sign * allocation) } [parts, build(sign * remainder)] end |
#split(n) ⇒ Array<(Array<Amount>, Amount)>
Splits into equal parts and returns the leftover explicitly.
20 21 22 23 24 25 26 27 28 |
# File 'lib/amount/allocation.rb', line 20 def split(n) raise ArgumentError, "n must be positive" unless n.is_a?(Integer) && n.positive? sign = atomic_sign base, remainder = @atomic.abs.divmod(n) parts = Array.new(n) { build(sign * base) } [parts, build(sign * remainder)] end |