extract core operation name instead of listing all function name variants

This commit is contained in:
Ralf Jung 2025-07-19 12:11:04 +02:00
parent 94ab2b9f15
commit e00051299a

View file

@ -210,61 +210,70 @@ where
let pi_over_2 = (pi / two).value;
let pi_over_4 = (pi_over_2 / two).value;
Some(match (intrinsic_name, args) {
// Remove `f32`/`f64` suffix, if any.
let name = intrinsic_name
.strip_suffix("f32")
.or_else(|| intrinsic_name.strip_suffix("f64"))
.unwrap_or(intrinsic_name);
// Also strip trailing `f` (indicates "float"), with an exception for "erf" to avoid
// removing that `f`.
let name = if name == "erf" { name } else { name.strip_suffix("f").unwrap_or(name) };
Some(match (name, args) {
// cos(±0) and cosh(±0)= 1
("cosf32" | "cosf64" | "coshf" | "cosh", [input]) if input.is_zero() => one,
("cos" | "cosh", [input]) if input.is_zero() => one,
// e^0 = 1
("expf32" | "expf64" | "exp2f32" | "exp2f64", [input]) if input.is_zero() => one,
("exp" | "exp2", [input]) if input.is_zero() => one,
// tanh(±INF) = ±1
("tanhf" | "tanh", [input]) if input.is_infinite() => one.copy_sign(*input),
("tanh", [input]) if input.is_infinite() => one.copy_sign(*input),
// atan(±INF) = ±π/2
("atanf" | "atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input),
("atan", [input]) if input.is_infinite() => pi_over_2.copy_sign(*input),
// erf(±INF) = ±1
("erff" | "erf", [input]) if input.is_infinite() => one.copy_sign(*input),
("erf", [input]) if input.is_infinite() => one.copy_sign(*input),
// erfc(-INF) = 2
("erfcf" | "erfc", [input]) if input.is_neg_infinity() => (one + one).value,
("erfc", [input]) if input.is_neg_infinity() => (one + one).value,
// hypot(x, ±0) = abs(x), if x is not a NaN.
("_hypotf" | "hypotf" | "_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() =>
// `_hypot` is the Windows name for this.
("_hypot" | "hypot", [x, y]) if !x.is_nan() && y.is_zero() =>
x.abs(),
// atan2(±0,0) = ±π.
// atan2(±0, y) = ±π for y < 0.
// Must check for non NaN because `y.is_negative()` also applies to NaN.
("atan2f" | "atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) =>
("atan2", [x, y]) if (x.is_zero() && (y.is_negative() && !y.is_nan())) =>
pi.copy_sign(*x),
// atan2(±x,−∞) = ±π for finite x > 0.
("atan2f" | "atan2", [x, y])
("atan2", [x, y])
if (!x.is_zero() && !x.is_infinite()) && y.is_neg_infinity() =>
pi.copy_sign(*x),
// atan2(x, ±0) = −π/2 for x < 0.
// atan2(x, ±0) = π/2 for x > 0.
("atan2f" | "atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x),
("atan2", [x, y]) if !x.is_zero() && y.is_zero() => pi_over_2.copy_sign(*x),
//atan2(±∞, −∞) = ±3π/4
("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() =>
("atan2", [x, y]) if x.is_infinite() && y.is_neg_infinity() =>
(pi_over_4 * three).value.copy_sign(*x),
//atan2(±∞, +∞) = ±π/4
("atan2f" | "atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() =>
("atan2", [x, y]) if x.is_infinite() && y.is_pos_infinity() =>
pi_over_4.copy_sign(*x),
// atan2(±∞, y) returns ±π/2 for finite y.
("atan2f" | "atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) =>
("atan2", [x, y]) if x.is_infinite() && (!y.is_infinite() && !y.is_nan()) =>
pi_over_2.copy_sign(*x),
// (-1)^(±INF) = 1
("powf32" | "powf64", [base, exp]) if *base == -one && exp.is_infinite() => one,
("pow", [base, exp]) if *base == -one && exp.is_infinite() => one,
// 1^y = 1 for any y, even a NaN
("powf32" | "powf64", [base, exp]) if *base == one => {
("pow", [base, exp]) if *base == one => {
let rng = this.machine.rng.get_mut();
// SNaN exponents get special treatment: they might return 1, or a NaN.
let return_nan = exp.is_signaling() && this.machine.float_nondet && rng.random();
@ -273,7 +282,7 @@ where
}
// x^(±0) = 1 for any x, even a NaN
("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
("pow", [base, exp]) if exp.is_zero() => {
let rng = this.machine.rng.get_mut();
// SNaN bases get special treatment: they might return 1, or a NaN.
let return_nan = base.is_signaling() && this.machine.float_nondet && rng.random();