"""Decimal utilities.""" from decimal import ROUND_HALF_UP, ROUND_UP, Decimal # One billionth DEFAULT_TOLERANCE = Decimal('1e-9') def safe_round_up( value: Decimal | float | int | str, exp: Decimal | int = Decimal('1'), tolerance: Decimal = DEFAULT_TOLERANCE, ) -> Decimal: """Round up to the given decimal places, accounting for floating-point drift.""" # Sanitize value if not isinstance(value, Decimal): value = Decimal(str(value)) # Sanitize exp if isinstance(exp, int): exp = Decimal(10) ** -exp elif not isinstance(exp, Decimal): raise TypeError(f'exp must be int or Decimal, got {type(exp).__name__}') # Correct floating-point drift rounded = value.quantize(exp, rounding=ROUND_HALF_UP) value = rounded if abs(value - rounded) < tolerance else value return value.quantize(exp, rounding=ROUND_UP) def to_cent( value: Decimal | float | int | str, tolerance: Decimal = DEFAULT_TOLERANCE ) -> Decimal: """Round up to the nearest cent, accounting for floating-point drift.""" return safe_round_up(value, Decimal('0.01'), tolerance)