import math from .math_exp import exp from .math_ln import ln # Below this exponent of e the result is smaller than any normal double. _SMALLEST = -708 _LARGEST = 709 def pow(base: float, exponent: float) -> float: # noqa: A001 - the manifest names it pow """base^exponent with the same bits in TypeScript, Python and Rust. A whole-number exponent is done by repeated squaring, so 10^3 is exactly 1000; any other is exp(exponent * ln(base)) from math.exp and math.ln. Python's ** and math.pow use the C library, whose last bit may differ. """ for v, what in ((base, "base"), (exponent, "exponent")): if isinstance(v, bool) or not isinstance(v, (int, float)) or not math.isfinite(v): raise ValueError("pow needs a finite %s, received %r" % (what, v)) base = float(base) exponent = float(exponent) if base == 0: if exponent < 0: raise ValueError("zero cannot be raised to a negative power") return 1.0 if exponent == 0 else 0.0 if math.floor(exponent) == exponent: n = int(abs(exponent)) b = base result = 1.0 while n > 0: if n % 2 == 1: result *= b n //= 2 if n > 0: b *= b if exponent < 0: if result == 0 or math.isinf(result): result = 0.0 if math.isinf(result) else math.inf else: result = 1 / result if not math.isfinite(result): raise ValueError("pow result is too large to represent") return result + 0.0 if base < 0: raise ValueError("a negative base needs a whole-number exponent") power = exponent * ln(base) if power > _LARGEST: raise ValueError("pow result is too large to represent") if power < _SMALLEST: return 0.0 return exp(power)