1
0
mirror of https://github.com/MikeMcl/decimal.js.git synced 2026-03-02 03:49:24 +00:00

#217 Compute acos with less cancellation near x=1

This commit is contained in:
Alden
2023-02-12 23:02:53 -05:00
committed by Michael Mclaughlin
parent 7f01abd83d
commit 08e5a381d2
8 changed files with 141 additions and 7 deletions

3
test/hypothesis/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
__pycache__
.hypothesis
.ipynb_checkpoints

View File

@@ -0,0 +1,99 @@
from decimal import Decimal, getcontext
import json
import subprocess
import hypothesis
from hypothesis import given, settings
from hypothesis.strategies import decimals, integers, tuples
from mpmath import mp
import pytest
mp.prec = 500
getcontext().prec = 14
node = subprocess.Popen(
["node", "evaluate.mjs"], stdout=subprocess.PIPE, stdin=subprocess.PIPE
)
def get_decimal(func: str, args: list, config: dict):
arg = json.dumps({"func": func, "args": args, "config": config}).encode() + b"\r"
node.stdin.write(arg)
node.stdin.flush()
return Decimal(node.stdout.readline().strip().decode())
def assert_matches(x, mpfunc, jsfunc=None):
if jsfunc is None:
jsfunc = mpfunc
y = Decimal(str(getattr(mp, mpfunc)(x))) * Decimal("1.0")
z = get_decimal(jsfunc, [str(x)], {"precision": 14})
assert y == z
@pytest.mark.parametrize("fn", "sin cos tan atan asinh".split())
@given(
x=tuples(
decimals(
allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14
),
integers(min_value=-99, max_value=99),
).map(lambda tup: tup[0] * Decimal(10) ** tup[1])
)
@settings(max_examples=100_000)
def test_matches(x, fn):
assert_matches(x, fn)
@pytest.mark.parametrize("fn", "ln log10 sqrt".split())
@given(
x=tuples(
decimals(
allow_nan=False,
allow_infinity=False,
min_value=1e-13,
max_value=1,
places=14,
),
integers(min_value=-99, max_value=99),
).map(lambda tup: tup[0] * Decimal(10) ** tup[1])
)
@settings(max_examples=100_000)
def test_positive_domain(x, fn):
assert_matches(x, fn)
@pytest.mark.parametrize("fn", "asin acos atanh".split())
@given(
x=decimals(
allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14
)
)
@settings(max_examples=100_000)
def test_inverse_trig(x, fn):
assert_matches(x, fn)
@pytest.mark.parametrize("fn", "sinh cosh tanh exp".split())
@given(
x=tuples(
decimals(
allow_nan=False, allow_infinity=False, min_value=-1, max_value=1, places=14
),
integers(min_value=-99, max_value=3),
).map(lambda tup: tup[0] * Decimal(10) ** tup[1])
)
@settings(max_examples=100_000)
def test_small_domain(x, fn):
assert_matches(x, fn)
@given(
x=tuples(
decimals(
allow_nan=False, allow_infinity=False, min_value=1, max_value=10, places=14
),
integers(min_value=0, max_value=99),
).map(lambda tup: tup[0] * Decimal(10) ** tup[1])
)
@settings(max_examples=100_000)
def test_acosh(x):
assert_matches(x, 'acosh')

View File

@@ -0,0 +1,26 @@
// listen for test cases, and provide the results.
// give JSON of the test case, receive the result
// Example:
// > {"func":"tan", "args":["12.5"], "config":{"precision":8}}
// -0.066468242
import {Decimal} from '../../decimal.mjs';
import {createInterface} from 'readline';
const readline = createInterface({
input: process.stdin,
output: process.stdout
});
readline.on("close", () => {console.log('\n'); process.exit(0);});
readline.on("line", (line) => {
if (line) {
const {func, args, config} = JSON.parse(line);
config.defaults = true;
Decimal.set(config);
const result = Decimal[func](...args);
console.log(result);
}
});

View File

@@ -0,0 +1,3 @@
hypothesis
mpmath
node