Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .math_integer_sqrt import integer_sqrt ← from math.integer-sqrt ^1.0.0 · built alongside by fune
from .math_round_div import RoundingMode ← from math.round-div ^1.0.0 · built alongside by fune
from .money_amount import Money, assert_same_currency ← from money.amount ^1.0.0 · built alongside by fune
MAX_SAFE = 2**53 - 1
MAX_I64 = 2**63 - 1
def economic_batch_quantity(
annual_demand: int,
annual_production_rate: int,
setup_cost: Money,
holding_cost: Money,
mode: RoundingMode,
) -> int:
"""Economic batch quantity, sqrt(2DSP / (H(P - D))), in whole units.
The root is never taken in floating point: the floor is an exact integer
square root and the rounding decision compares whole numbers.
"""
if isinstance(annual_demand, bool) or not isinstance(annual_demand, int) or annual_demand < 0 or annual_demand > MAX_SAFE:
raise ValueError("annualDemand must be a whole number of units, not negative, received %r" % (annual_demand,))
if (
isinstance(annual_production_rate, bool)
or not isinstance(annual_production_rate, int)
or annual_production_rate <= annual_demand
or annual_production_rate > MAX_SAFE
):
raise ValueError(
"annualProductionRate must be a whole number greater than annualDemand, received %r"
% (annual_production_rate,)
)
assert_same_currency(setup_cost, holding_cost)
if setup_cost.minor < 0:
raise ValueError("setupCost must not be negative, received %d" % setup_cost.minor)
if holding_cost.minor <= 0:
raise ValueError("holdingCost must be greater than zero, received %d" % holding_cost.minor)
d, p, s = annual_demand, annual_production_rate, setup_cost.minor
eight = 8 * d * s * p
if eight > MAX_I64:
raise ValueError(
"annualDemand, setupCost and annualProductionRate are too large: 8 x D x S x P must stay within 2^63 - 1"
)
two = 2 * d * s * p
m = holding_cost.minor * (p - d)
n = integer_sqrt(two // m)
odd = 2 * n + 1
if mode == "down":
return n
if mode == "up":
return n if n * n * m == two else n + 1
if mode == "half-up":
return n + 1 if odd * odd * m <= eight else n
if mode == "half-even":
half = odd * odd * m
if half < eight:
return n + 1
if half > eight:
return n
return n if n % 2 == 0 else n + 1
raise ValueError('unknown rounding mode "%s"' % (mode,))