use symplex::prelude::*;
fn dec(ctx: &Context, s: &str) -> Result<String, SymplexError> {
ctx.parse(s).unwrap().eval_decimal(16)
}
fn check(ctx: &Context, cases: &[(&str, &str)]) {
for (src, want) in cases {
match dec(ctx, src) {
Ok(v) => assert_eq!(v, *want, "{src}"),
Err(e) => panic!("{src}: {e:?}"),
}
}
}
fn refused_nonzero_underflow(ctx: &Context, src: &str) {
match dec(ctx, src) {
Err(SymplexError::Unevaluable { reason }) => {
assert!(reason.contains("not 0 but underflows"), "{src}: {reason}");
}
other => panic!("{src}: {other:?}"),
}
}
#[test]
fn besselj_below_the_range_next_to_an_exact_one() {
let ctx = Context::new();
check(
&ctx,
&[
("1 + besselj(10^9, 1)", "1"),
("1 - besselj(10^9, 1)", "1"),
("2 - besselj(10^9 + 1, -1)", "2"),
("1 + besselj(-10^9, 1)", "1"),
("besselj(10^9, 1) - besselj(10^9, 1)", "0"),
],
);
refused_nonzero_underflow(&ctx, "besselj(10^9, 1)");
refused_nonzero_underflow(&ctx, "besselj(-3423610157, -281)");
refused_nonzero_underflow(&ctx, "besselj(-10^20, 1)");
refused_nonzero_underflow(&ctx, "besselj(10^9, 1) + besselj(10^9, 2)");
refused_nonzero_underflow(&ctx, "besselj(10^9, 1) - besselj(10^9, 2)");
}
#[test]
fn bessel_values_below_the_range_scaled() {
let ctx = Context::new();
check(
&ctx,
&[
(
"log(besselj(8345185991999992, 61/10^27))",
"-787890140073435000",
),
("log(besselj(10^9, 1))", "-20416413028.78693"),
("log(besseli(10^9, 1))", "-20416413028.78693"),
("log(besselj(10^9, sqrt(2)))", "-20069839438.50696"),
("log(-besselj(10^9 + 1, -1))", "-20416413050.20334"),
("log(besselj(-10^9, 1))", "-20416413028.78693"),
("log(-besselj(-(10^9 + 1), 1))", "-20416413050.20334"),
(
"besselj(10^9, 1)/besselj(10^9, 2)",
"2.167797969242782e-301029996",
),
("besselj(10^9 + 1, 1)/besselj(10^9, 1)", "4.999999995e-10"),
("log(besselj(5000, 10^(-1000000)))", "-11512966521.84964"),
],
);
}
#[test]
fn quotients_of_values_below_the_range() {
let ctx = Context::new();
check(
&ctx,
&[
("erfc(10^5)/erfc(10^5 + 1)", "2.141309654941964e86859"),
("Ei(-10^10)/Ei(-10^10 - 1)", "2.718281828730873"),
],
);
}
#[test]
fn products_across_the_exponent_range() {
let ctx = Context::new();
check(
&ctx,
&[
("exp(-10^10)/exp(-10^10 + 1)", "0.3678794411714423"),
("erfc(10^8)*10^8*exp(10^16)", "0.5641895835477563"),
],
);
}
#[test]
fn bessel_functions_of_large_order() {
let ctx = Context::new();
check(
&ctx,
&[
("bessely(20000, 300)", "-1.333952734774281e33811"),
("besselk(20000, 300)", "2.208253217266176e33810"),
("bessely(20000, 30000)", "0.0005692866273543233"),
("besselk(20000, 30000)", "1.124185674656564e-10231"),
("besseli(20000, 30000)", "1.233560008614248e10226"),
("besseli(1000, 120000)", "3.886788206303692e52110"),
("besselj(20000, 19000)", "1.028759708090584e-96"),
("besselj(20000, 30000)", "-0.005305319444533382"),
("besseli(10^6, 10^6)", "9.698087220358665e231405"),
("besseli(10^6, 5*10^5)", "4.444541563012309e-141411"),
("bessely(3909, 3909/2)", "-4.633653287822352e763"),
("besselj(44907, 2335164/97)", "1.923640277212473e-7635"),
],
);
}
#[test]
fn bessel_functions_at_the_turning_point() {
let ctx = Context::new();
check(
&ctx,
&[
("besselj(20000, 20000)", "0.01647894210697408"),
("bessely(20000, 20000)", "-0.02854236636399093"),
],
);
}
#[test]
fn polylog_of_large_negative_order() {
let ctx = Context::new();
check(
&ctx,
&[
("polylog(-1500, 1/2)", "4.011514728419479e4353"),
("polylog(-1500, -1/2)", "-1.297731989364847e3353"),
("polylog(-1500, -9/10)", "1.368395424288717e3367"),
("polylog(-20000, 1/3)", "2.137893787064944e76520"),
],
);
}
#[test]
fn jacobi_beyond_degree_2000() {
let ctx = Context::new();
check(
&ctx,
&[
("jacobi(2500, 1/3, 1/5, 1/7)", "0.01765605895237283"),
("jacobi(5000, 1/3, 1/5, 1/7)", "0.01083267558645747"),
("jacobi(2001, 1/3, 1/3, 0)", "0"),
],
);
}