1from decimal import Decimal, getcontext 2import json 3import subprocess 4import hypothesis 5from hypothesis import given, settings 6from hypothesis.strategies import decimals, integers, tuples 7from mpmath import mp 8import pytest 9 10mp.prec = 500 11getcontext().prec = 14 12 13node = subprocess.Popen( 14 ["node", "evaluate.mjs"], stdout=subprocess.PIPE, stdin=subprocess.PIPE 15) 16 17 18def get_decimal(func: str, args: list, config: dict): 19 arg = json.dumps({"func": func, "args": args, "config": config}).encode() + b"\r" 20 node.stdin.write(arg) 21 node.stdin.flush() 22 return Decimal(node.stdout.readline().strip().decode()) 23 24 25def assert_matches(x, mpfunc, jsfunc=None): 26 if jsfunc is None: 27 jsfunc = mpfunc 28 y = Decimal(str(getattr(mp, mpfunc)(x))) * Decimal("1.0") 29 z = get_decimal(jsfunc, [str(x)], {"precision": 14}) 30 assert y == z 31 32 33@pytest.mark.parametrize("fn", "sin cos tan atan asinh".split()) 34@given( 35 x=tuples( 36 decimals( 37 allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14 38 ), 39 integers(min_value=-99, max_value=99), 40 ).map(lambda tup: tup[0] * Decimal(10) ** tup[1]) 41) 42@settings(max_examples=100_000) 43def test_matches(x, fn): 44 assert_matches(x, fn) 45 46 47@pytest.mark.parametrize("fn", "ln log10 sqrt".split()) 48@given( 49 x=tuples( 50 decimals( 51 allow_nan=False, 52 allow_infinity=False, 53 min_value=1e-13, 54 max_value=1, 55 places=14, 56 ), 57 integers(min_value=-99, max_value=99), 58 ).map(lambda tup: tup[0] * Decimal(10) ** tup[1]) 59) 60@settings(max_examples=100_000) 61def test_positive_domain(x, fn): 62 assert_matches(x, fn) 63 64 65@pytest.mark.parametrize("fn", "asin acos atanh".split()) 66@given( 67 x=decimals( 68 allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14 69 ) 70) 71@settings(max_examples=100_000) 72def test_inverse_trig(x, fn): 73 assert_matches(x, fn) 74 75 76@pytest.mark.parametrize("fn", "sinh cosh tanh exp".split()) 77@given( 78 x=tuples( 79 decimals( 80 allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14 81 ), 82 integers(min_value=-99, max_value=3), 83 ).map(lambda tup: tup[0] * Decimal(10) ** tup[1]) 84) 85@settings(max_examples=100_000) 86def test_small_domain(x, fn): 87 assert_matches(x, fn) 88 89@given( 90 x=tuples( 91 decimals( 92 allow_nan=False, allow_infinity=False, min_value=1, max_value=10, places=14 93 ), 94 integers(min_value=0, max_value=99), 95 ).map(lambda tup: tup[0] * Decimal(10) ** tup[1]) 96) 97@settings(max_examples=100_000) 98def test_acosh(x): 99 assert_matches(x, 'acosh')