from __future__ import annotations
from typing import TypeAlias
from mpmath import mp, mpf
FHS_MPMATH_PRECISION = 100
[docs]
class MPFloat(mpf):
"""
Multiprecision or arbitrary precision float.
Wraps the mpmath.mpf multiprecision float class such that
creating an MPFloat from a Python float does not lose precision.
"""
def __new__(cls, val: FloatLike, **kwargs):
mp.dps = FHS_MPMATH_PRECISION
return super().__new__(cls, mp.mpmathify(str(val)), **kwargs)
[docs]
@staticmethod
def assert_almosteq(
test_value: MPFloat,
expected_value: MPFloat,
rel_tolerance: FloatLike | None = 1e-14,
abs_tolerance: FloatLike | None = 1e-22,
sig_figs: int = 25,
) -> None:
mp.dps = FHS_MPMATH_PRECISION
assert mp.almosteq(test_value, expected_value, rel_tolerance, abs_tolerance), (
f"assert {mp.nstr(test_value, n=sig_figs)} == {mp.nstr(expected_value, n=sig_figs)} "
f"with tolerance(s) rel={mp.nstr(rel_tolerance, n=sig_figs)}, abs={mp.nstr(abs_tolerance, n=sig_figs)}: "
f"The difference of {mp.nstr(mp.fabs(mp.fsub(test_value, expected_value)))} "
"does not comply to the allowed tolerance(s)."
)
FloatLike: TypeAlias = int | float | MPFloat