import math from .health_bmi_types import Bmi, BmiCategory from .math_round_float import round_float def _check_range(name: str, value: float, low: float, high: float, unit: str) -> None: ok = not isinstance(value, bool) and isinstance(value, (int, float)) and math.isfinite(value) if not ok or value < low or value > high: raise ValueError("%s must be a number from %s to %s %s, received %r" % (name, low, high, unit, value)) def bmi(weight_kg: float, height_cm: float) -> Bmi: """Body mass index for an adult: weight over height squared, to one decimal place, and the band it falls in. The bands are published to one decimal place (18.5-24.9, 25-29.9, ...), so the category is read from the rounded index: 24.97 is reported as 25.0 and is overweight, not healthy.""" _check_range("weightKg", weight_kg, 10, 650, "kg") # Height in metres (1.75) is the commonest unit slip; 50 cm is the floor. _check_range("heightCm", height_cm, 50, 272, "cm") metres = float(height_cm) / 100 value = round_float(float(weight_kg) / (metres * metres), 1) category: BmiCategory if value < 18.5: category = "underweight" elif value <= 24.9: category = "healthy-weight" elif value <= 29.9: category = "overweight" elif value <= 34.9: category = "obesity-class-1" elif value <= 39.9: category = "obesity-class-2" else: category = "obesity-class-3" return Bmi(value=value, category=category)