1+ from decimal import Decimal , getcontext
2+ import json
3+ import subprocess
4+ import hypothesis
5+ from hypothesis import given , settings
6+ from hypothesis .strategies import decimals , integers , tuples
7+ from mpmath import mp
8+ import pytest
9+
10+ mp .prec = 500
11+ getcontext ().prec = 14
12+
13+ node = subprocess .Popen (
14+ ["node" , "evaluate.mjs" ], stdout = subprocess .PIPE , stdin = subprocess .PIPE
15+ )
16+
17+
18+ def 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+
25+ def 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 )
43+ def 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 )
61+ def 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 )
72+ def 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 )
86+ def 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 )
98+ def test_acosh (x ):
99+ assert_matches (x , 'acosh' )
0 commit comments