77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""Reproduce DoubleDouble's precomputed mathematical constants.
|
|
|
|
Run: python3 -B 1-tests/Just.PreciseMath.Tests/ReferenceData/generate_constants.py
|
|
Standard library only; no dependency on the implementation under test.
|
|
Decimal evaluates formulas at 160 and 240 digits; Fraction-based splitting
|
|
rounds the high and then the exact residual to nearest-even binary64.
|
|
"""
|
|
|
|
from decimal import Decimal, localcontext
|
|
from fractions import Fraction
|
|
|
|
from generate_irrational_arithmetic import arctan_inverse, split
|
|
|
|
|
|
def constants(precision: int) -> dict[str, tuple[float, float]]:
|
|
with localcontext() as context:
|
|
context.prec = precision
|
|
one = Decimal(1)
|
|
pi = 16 * arctan_inverse(5) - 4 * arctan_inverse(239)
|
|
e = one.exp()
|
|
ln2 = Decimal(2).ln()
|
|
ln10 = Decimal(10).ln()
|
|
sqrt2 = Decimal(2).sqrt()
|
|
sqrt3 = Decimal(3).sqrt()
|
|
sqrt5 = Decimal(5).sqrt()
|
|
sqrt_pi = pi.sqrt()
|
|
sqrt_tau = (2 * pi).sqrt()
|
|
values = {
|
|
"Pi": pi,
|
|
"E": e,
|
|
"Ln2": ln2,
|
|
"Tau": 2 * pi,
|
|
"PiOver2": pi / 2,
|
|
"PiOver3": pi / 3,
|
|
"PiOver4": pi / 4,
|
|
"PiOver6": pi / 6,
|
|
"InvPi": one / pi,
|
|
"InvTau": one / (2 * pi),
|
|
"DegToRad": pi / 180,
|
|
"RadToDeg": 180 / pi,
|
|
"InvE": one / e,
|
|
"Ln10": ln10,
|
|
"Log2E": one / ln2,
|
|
"Log10E": one / ln10,
|
|
"Log2Of10": ln10 / ln2,
|
|
"Log10Of2": ln2 / ln10,
|
|
"Sqrt2": sqrt2,
|
|
"Sqrt3": sqrt3,
|
|
"Sqrt5": sqrt5,
|
|
"InvSqrt2": one / sqrt2,
|
|
"InvSqrt3": one / sqrt3,
|
|
"SqrtPi": sqrt_pi,
|
|
"InvSqrtPi": one / sqrt_pi,
|
|
"TwoInvSqrtPi": 2 / sqrt_pi,
|
|
"SqrtTau": sqrt_tau,
|
|
"InvSqrtTau": one / sqrt_tau,
|
|
"GoldenRatio": (one + sqrt5) / 2,
|
|
}
|
|
pairs = {name: split(Fraction(value)) for name, value in values.items()}
|
|
for name, value in values.items():
|
|
high, low = pairs[name]
|
|
assert high + low == high, f"Unnormalized constant: {name}"
|
|
assert low != 0.0, f"Lost residual: {name}"
|
|
assert abs(Fraction(high) + Fraction(low) - Fraction(value)) <= abs(Fraction(value)) / (1 << 105)
|
|
return pairs
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pairs = constants(160)
|
|
assert pairs == constants(240), "Increase precision: binary64 constants did not stabilize"
|
|
print("// Expected test components")
|
|
for name, (high, low) in pairs.items():
|
|
print(f' [InlineData("{name}", {high!r}, {low!r})]')
|
|
print("\n// Precomputed properties")
|
|
for name, (high, low) in pairs.items():
|
|
print(f" public static DoubleDouble {name} => new({high!r}, {low!r});")
|