Functional Weave
Code in Rust

inventory.eoq@1.0.0

README.md

1,960 bytes · view raw

# inventory.eoq

The economic order quantity of Harris (1913), popularised by Wilson (1934):

    EOQ = sqrt(2 * D * S / H)

where `D` is annual demand in units, `S` the fixed cost of placing an order and
`H` the cost of holding one unit in stock for a year. It is the order size at
which annual ordering cost (`D / Q * S`) equals annual holding cost
(`Q / 2 * H`), and their sum is least.

**Whole units, rounded exactly.** The answer is a square root, so it is rarely
whole. Rounding it through floating point is where implementations disagree:
`sqrt(6.25)` is exactly 2.5, and JavaScript's `Math.round` makes that 3 while
Python's `round` makes it 2. Here the root is never taken in floating point.
The floor comes from `math.integer-sqrt` applied to `floor(2DS / H)` (the floor
of a square root only changes at whole numbers, so this is exact), and the
rounding decision compares whole numbers:

- `down`: the floor.
- `up`: the floor, plus one unless `2DS / H` is a perfect square.
- `half-up`: plus one when `(2n + 1)^2 * H <= 8DS`, i.e. the root is at least
  `n + 0.5`.
- `half-even`: as half-up, but an exact half goes to the even neighbour.

`half-up` is the usual choice; `up` never under-orders.

**Money is exact.** `orderCost` and `holdingCost` are `Money` in minor units and
must be in the same currency; the currencies cancel, so the result is a plain
unit count. A holding cost quoted as a percentage of unit cost (a 25% carrying
rate) is `money.apply-rate(unitCost, 2500, ...)` first. `8 * D * S` has to stay
within 2^53 - 1, which allows, for example, a million units a year at £1,000,000
an order.

Zero demand gives 0. Holding cost must be positive (with free holding the EOQ is
unbounded) and neither demand nor order cost may be negative.

Sources: F. W. Harris, "How Many Parts to Make at Once", Factory, The Magazine
of Management 10(2), 1913; R. H. Wilson, "A Scientific Routine for Stock
Control", Harvard Business Review 13, 1934.