use vyre::Error;
pub const REFERENCE_TRANSCENDENTAL_ULP_BUDGET: u32 = 4;
pub const BACKEND_TRANSCENDENTAL_ULP_BUDGET: u32 = 128;
pub const BACKEND_ELEMENTARY_F32_ULP_BUDGET: u32 = 4;
#[must_use]
#[inline]
pub fn canonical_sin(x: f32) -> f32 {
libm::sinf(x)
}
#[must_use]
#[inline]
pub fn canonical_cos(x: f32) -> f32 {
libm::cosf(x)
}
#[must_use]
#[inline]
pub fn canonical_sqrt(x: f32) -> f32 {
libm::sqrtf(x)
}
#[must_use]
#[inline]
pub fn canonical_inverse_sqrt(x: f32) -> f32 {
1.0 / canonical_sqrt(x)
}
#[must_use]
#[inline]
pub fn canonical_reciprocal(x: f32) -> f32 {
canonical_f32(1.0 / canonical_f32(x))
}
#[must_use]
#[inline]
pub fn canonical_exp(x: f32) -> f32 {
libm::expf(x)
}
#[must_use]
#[inline]
pub fn canonical_exp2(x: f32) -> f32 {
libm::exp2f(x)
}
#[must_use]
#[inline]
pub fn canonical_log(x: f32) -> f32 {
libm::logf(x)
}
#[must_use]
#[inline]
pub fn canonical_log2(x: f32) -> f32 {
libm::log2f(x)
}
#[must_use]
#[inline]
pub fn canonical_tan(x: f32) -> f32 {
libm::tanf(x)
}
#[must_use]
#[inline]
pub fn canonical_acos(x: f32) -> f32 {
libm::acosf(x)
}
#[must_use]
#[inline]
pub fn canonical_asin(x: f32) -> f32 {
libm::asinf(x)
}
#[must_use]
#[inline]
pub fn canonical_atan(x: f32) -> f32 {
libm::atanf(x)
}
#[must_use]
#[inline]
pub fn canonical_tanh(x: f32) -> f32 {
libm::tanhf(x)
}
#[must_use]
#[inline]
pub fn canonical_sinh(x: f32) -> f32 {
libm::sinhf(x)
}
#[must_use]
#[inline]
pub fn canonical_cosh(x: f32) -> f32 {
libm::coshf(x)
}
#[must_use]
#[inline]
pub fn canonical_f32(value: f32) -> f32 {
crate::execution::typed_ops::canonical_f32(value)
}
#[must_use]
#[inline]
pub fn canonical_ulp_distance(left: f32, right: f32) -> u32 {
let left = canonical_f32(left);
let right = canonical_f32(right);
if left == right || left.to_bits() == right.to_bits() {
return 0;
}
ordered_f32_key(left).abs_diff(ordered_f32_key(right))
}
#[inline]
fn ordered_f32_key(value: f32) -> u32 {
let bits = value.to_bits();
if bits & 0x8000_0000 == 0 {
bits | 0x8000_0000
} else {
!bits
}
}
pub fn pending_float_types() -> Error {
Error::interp(
"pending upstream float variants in vyre::ir; reference interpreter is integer-only until those variants land",
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn canonical_f32_collapses_nan_payloads() {
let quiet_payload = f32::from_bits(0x7FC1_2345);
let signaling_payload = f32::from_bits(0x7F81_2345);
assert_eq!(canonical_f32(quiet_payload).to_bits(), 0x7FC0_0000);
assert_eq!(canonical_f32(signaling_payload).to_bits(), 0x7FC0_0000);
assert_eq!(canonical_ulp_distance(quiet_payload, signaling_payload), 0);
}
#[test]
fn canonical_ulp_distance_handles_zero_and_neighbors() {
assert_eq!(canonical_ulp_distance(0.0, -0.0), 0);
assert_eq!(
canonical_ulp_distance(1.0, f32::from_bits(1.0f32.to_bits() + 1)),
1
);
}
}