• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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')