add precomputed mathematical constants and specialize the second division residual
.NET Test / .NET tests (push) Successful in 2m23s
.NET Test / .NET tests (push) Successful in 2m23s
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""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});")
|
||||
Reference in New Issue
Block a user