Skip to content

Commit 44befa5

Browse files
committed
Revert "Remove unused inverse approximation variants"
This reverts commit 95bbb30.
1 parent 95bbb30 commit 44befa5

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

src/computable/approximation.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ pub(super) enum Approximation {
101101
// rational in the node avoids a child Computable::approx call before
102102
// entering that series.
103103
AsinRational(Rational),
104+
PrescaledAsin(Computable),
104105
// Generic non-rational asin uses the stable half-angle atan transform. A
105106
// deferred node keeps construction thin for symbolic radicals and endpoint
106107
// inputs that may never be approximated.
@@ -123,6 +124,7 @@ pub(super) enum Approximation {
123124
// approximation and keeps the exact value symbolic until the kernel rounds.
124125
AsinhRational(Rational),
125126
AtanhDirect(Computable),
127+
PrescaledAtanh(Computable),
126128
AtanhRational(Rational),
127129
PrescaledCos(Computable),
128130
// Small exact-rational Real::cos construction uses this leaf to avoid
@@ -239,6 +241,7 @@ impl Approximation {
239241
PrescaledAtan(c) => atan_computable(signal, c, p),
240242
AtanRational(r) => atan_rational(signal, r, p),
241243
AsinRational(r) => asin_rational(signal, r, p),
244+
PrescaledAsin(c) => asin_computable(signal, c, p),
242245
AsinDeferred(c) => asin_deferred(signal, c, p),
243246
AcosPositive(c) => acos_positive(signal, c, p),
244247
AcosPositiveRational(r) => acos_positive_rational(signal, r, p),
@@ -250,6 +253,7 @@ impl Approximation {
250253
PrescaledAsinh(c) => asinh_computable(signal, c, p),
251254
AsinhRational(r) => asinh_rational(signal, r, p),
252255
AtanhDirect(c) => atanh_direct(signal, c, p),
256+
PrescaledAtanh(c) => atanh_computable(signal, c, p),
253257
AtanhRational(r) => atanh_rational(signal, r, p),
254258
PrescaledCos(c) => cos(signal, c, p),
255259
PrescaledCosRational(r) => cos_rational(signal, r, p),
@@ -2107,6 +2111,44 @@ fn asin_rational(signal: &Option<Signal>, r: &Rational, p: Precision) -> BigInt
21072111
scale(sum, calc_precision - p)
21082112
}
21092113

2114+
// Approximate asin(c) for small |c|.
2115+
fn asin_computable(signal: &Option<Signal>, c: &Computable, p: Precision) -> BigInt {
2116+
// Dedicated tiny-argument asin series. It avoids the generic atan/sqrt
2117+
// transform, which is overkill and slower when |x| is already very small.
2118+
if p >= 1 {
2119+
return Zero::zero();
2120+
}
2121+
2122+
let iterations_needed: i32 = -p / 2 + 4;
2123+
let calc_precision = p - bound_log2(2 * iterations_needed) - 5;
2124+
let op_prec = calc_precision - 3;
2125+
let op_appr = c.approx_signal(signal, op_prec);
2126+
let op_squared = scale(&op_appr * &op_appr, op_prec);
2127+
2128+
// Borrowed magnitude checks matter here because tiny inverse-trig benches
2129+
// run many short series from cold caches.
2130+
let max_trunc_error = BigUint::one()
2131+
<< usize::try_from(p - 4 - calc_precision).expect("truncation shift is nonnegative");
2132+
let mut current_term = scale(op_appr, op_prec - calc_precision);
2133+
let mut sum = current_term.clone();
2134+
let mut n = 0_i32;
2135+
2136+
while current_term.magnitude() > &max_trunc_error {
2137+
if should_stop(signal) {
2138+
break;
2139+
}
2140+
n += 1;
2141+
current_term = scale(current_term * &op_squared, op_prec);
2142+
let numerator = (2 * n - 1) * (2 * n - 1);
2143+
let denominator = (2 * n) * (2 * n + 1);
2144+
current_term *= numerator;
2145+
current_term /= denominator;
2146+
sum += &current_term;
2147+
}
2148+
2149+
scale(sum, calc_precision - p)
2150+
}
2151+
21102152
fn asin_deferred(signal: &Option<Signal>, c: &Computable, p: Precision) -> BigInt {
21112153
// Generic asin uses asin(x) = 2*atan(x / (sqrt(1-x^2)+1)).
21122154
// Keeping this as one approximation node mirrors the deferred acos and
@@ -2285,6 +2327,42 @@ fn atanh_direct(signal: &Option<Signal>, c: &Computable, p: Precision) -> BigInt
22852327
.approx_signal(signal, p)
22862328
}
22872329

2330+
// Approximate atanh(c) for small |c|.
2331+
fn atanh_computable(signal: &Option<Signal>, c: &Computable, p: Precision) -> BigInt {
2332+
// Dedicated tiny-argument atanh series, also reused by the ln1p kernel after
2333+
// it transforms ln(1+x) into 2*atanh(x/(2+x)).
2334+
if p >= 1 {
2335+
return Zero::zero();
2336+
}
2337+
2338+
let iterations_needed: i32 = -p / 2 + 4;
2339+
let calc_precision = p - bound_log2(2 * iterations_needed) - 5;
2340+
let op_prec = calc_precision - 3;
2341+
let op_appr = c.approx_signal(signal, op_prec);
2342+
let op_squared = scale(&op_appr * &op_appr, op_prec);
2343+
2344+
// Borrowed magnitude checks matter here because tiny inverse-hyperbolic
2345+
// benches run many short series from cold caches.
2346+
let max_trunc_error = BigUint::one()
2347+
<< usize::try_from(p - 4 - calc_precision).expect("truncation shift is nonnegative");
2348+
let mut current_power = scale(op_appr, op_prec - calc_precision);
2349+
let mut current_term = current_power.clone();
2350+
let mut sum = current_term.clone();
2351+
let mut n = 1_i32;
2352+
2353+
while current_term.magnitude() > &max_trunc_error {
2354+
if should_stop(signal) {
2355+
break;
2356+
}
2357+
n += 2;
2358+
current_power = scale(current_power * &op_squared, op_prec);
2359+
current_term = &current_power / n;
2360+
sum += &current_term;
2361+
}
2362+
2363+
scale(sum, calc_precision - p)
2364+
}
2365+
22882366
fn atanh_rational(signal: &Option<Signal>, r: &Rational, p: Precision) -> BigInt {
22892367
// Direct exact-rational variant of the tiny atanh series. This mirrors the
22902368
// direct rational trig kernels: preserve the symbolic rational payload and

src/computable/node.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,9 @@ impl Computable {
587587
(Approximation::AsinRational(left), Approximation::AsinRational(right)) => {
588588
left == right
589589
}
590+
(Approximation::PrescaledAsin(left), Approximation::PrescaledAsin(right)) => {
591+
Computable::internal_structural_eq(left, right)
592+
}
590593
(Approximation::AsinDeferred(left), Approximation::AsinDeferred(right)) => {
591594
Computable::internal_structural_eq(left, right)
592595
}
@@ -622,6 +625,9 @@ impl Computable {
622625
(Approximation::AtanhDirect(left), Approximation::AtanhDirect(right)) => {
623626
Computable::internal_structural_eq(left, right)
624627
}
628+
(Approximation::PrescaledAtanh(left), Approximation::PrescaledAtanh(right)) => {
629+
Computable::internal_structural_eq(left, right)
630+
}
625631
(Approximation::AtanhRational(left), Approximation::AtanhRational(right)) => {
626632
left == right
627633
}
@@ -1800,11 +1806,13 @@ impl Computable {
18001806
| Approximation::AcoshNearOne(_)
18011807
| Approximation::AcoshDirect(_) => Some(Some(Sign::Plus)),
18021808
Approximation::PrescaledAtan(child)
1809+
| Approximation::PrescaledAsin(child)
18031810
| Approximation::AsinDeferred(child)
18041811
| Approximation::AsinhNearZero(child)
18051812
| Approximation::AsinhDirect(child)
18061813
| Approximation::PrescaledAsinh(child)
1807-
| Approximation::AtanhDirect(child) => Some(child.exact_sign()),
1814+
| Approximation::AtanhDirect(child)
1815+
| Approximation::PrescaledAtanh(child) => Some(child.exact_sign()),
18081816
Approximation::PrescaledExp(_) => Some(Some(Sign::Plus)),
18091817
Approximation::Negate(_)
18101818
| Approximation::Offset(_, _)

0 commit comments

Comments
 (0)