【libm】 18 泛型绝对值函数 fabs(fabs.rs)

发布于:2025-07-11 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、源码

这段代码实现了一系列浮点数绝对值函数,支持不同精度的浮点类型(f16、f32、f64、f128)。

/// Absolute value (magnitude) (f16)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {
    super::generic::fabs(x)
}

/// Absolute value (magnitude) (f32)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {
    select_implementation! {
        name: fabsf,
        use_arch: all(target_arch = "wasm32", intrinsics_enabled),
        args: x,
    }

    super::generic::fabs(x)
}

/// Absolute value (magnitude) (f64)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabs(x: f64) -> f64 {
    select_implementation! {
        name: fabs,
        use_arch: all(target_arch = "wasm32", intrinsics_enabled),
        args: x,
    }

    super::generic::fabs(x)
}

/// Absolute value (magnitude) (f128)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {
    super::generic::fabs(x)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::support::Float;

    /// Based on https://en.cppreference.com/w/cpp/numeric/math/fabs
    fn spec_test<F: Float>(f: impl Fn(F) -> F) {
        assert_biteq!(f(F::ZERO), F::ZERO);
        assert_biteq!(f(F::NEG_ZERO), F::ZERO);
        assert_biteq!(f(F::INFINITY), F::INFINITY);
        assert_biteq!(f(F::NEG_INFINITY), F::INFINITY);
        assert!(f(F::NAN).is_nan());

        // Not spec rewquired but we expect it
        assert!(f(F::NAN).is_sign_positive());
        assert!(f(F::from_bits(F::NAN.to_bits() | F::SIGN_MASK)).is_sign_positive());
    }

    #[test]
    #[cfg(f16_enabled)]
    fn sanity_check_f16() {
        assert_eq!(fabsf16(-1.0f16), 1.0);
        assert_eq!(fabsf16(2.8f16), 2.8);
    }

    #[test]
    #[cfg(f16_enabled)]
    fn spec_tests_f16() {
        spec_test::<f16>(fabsf16);
    }

    #[test]
    fn sanity_check_f32() {
        assert_eq!(fabsf(-1.0f32), 1.0);
        assert_eq!(fabsf(2.8f32), 2.8);
    }

    #[test]
    fn spec_tests_f32() {
        spec_test::<f32>(fabsf);
    }

    #[test]
    fn sanity_check_f64() {
        assert_eq!(fabs(-1.0f64), 1.0);
        assert_eq!(fabs(2.8f64), 2.8);
    }

    #[test]
    fn spec_tests_f64() {
        spec_test::<f64>(fabs);
    }

    #[test]
    #[cfg(f128_enabled)]
    fn sanity_check_f128() {
        assert_eq!(fabsf128(-1.0f128), 1.0);
        assert_eq!(fabsf128(2.8f128), 2.8);
    }

    #[test]
    #[cfg(f128_enabled)]
    fn spec_tests_f128() {
        spec_test::<f128>(fabsf128);
    }
}

二、核心实现

  1. 泛型绝对值函数(底层)

所有函数最终调用 super::generic::fabs,其核心逻辑为:


let abs_mask = !F::SIGN_MASK;  // 符号位掩码取反(如 f32 的 0x7fffffff)
F::from_bits(x.to_bits() & abs_mask)  // 清除符号位后转换回浮点数
  • 原理:通过位操作直接清除符号位,无需条件判断。

  • 优点:无分支、可内联、跨平台一致。

  1. 类型特化函数

为每种浮点类型提供独立函数,例如:


// f32 版本
pub fn fabsf(x: f32) -> f32 {
    select_implementation!(...);  // 条件选择优化实现
    super::generic::fabs(x)
}
  • 宏优化:select_implementation! 在特定平台(如 WASM)可能选择硬件指令。

  • 条件编译:f16 和 f128 需启用 f16_enabled/f128_enabled 特性。

三、关键设计

  1. 位操作保证精度:
  • 直接操作浮点数的二进制表示,避免舍入误差。
  • 正确处理特殊值(±0.0、±∞、NaN)。
  1. 测试验证:
  • 规范测试(spec_test):验证符合 C++ 标准行为:

    • fabs(±0.0) = +0.0

    • fabs(±∞) = +∞

    • fabs(NaN) 保持 NaN 且符号位为正。

  • 数值测试:检查常规值(如 -1.0 → 1.0)。

  1. 平台适配:
  • 通过宏在支持硬件加速时(如 WASM)选择更优实现。
  • 泛型回退确保无硬件支持时的正确性。

四、特殊值处理

输入 输出 二进制操作示例(f32)
+0.0 +0.0 0x00000000 & 0x7fffffff = 0x00000000
-0.0 +0.0 0x80000000 & 0x7fffffff = 0x00000000
NaN NaN(符号位正) 0x7fc00000 & 0x7fffffff = 0x7fc00000
-∞ +∞ 0xff800000 & 0x7fffffff = 0x7f800000

五、性能优化

  • 内联提示:#[inline] 减少函数调用开销。

  • 单态化:泛型函数为每种类型生成独立代码,避免运行时开销。

  • 硬件加速:如 WASM 可能使用 f32.abs 指令。

六、使用场景

  • 数学库基础函数:为 log、pow 等提供依赖。

  • 跨平台科学计算:确保不同硬件下结果一致。

  • 嵌入式系统:无浮点硬件时软件实现。

七、测试覆盖

  • 边界值:零、无穷、NaN。

  • 常规值:正/负数。

  • 位精确校验:assert_biteq! 验证二进制结果。

通过结合位操作、泛型和条件编译,此代码在保证精度的同时兼顾性能和可移植性。


网站公告

今日签到

点亮在社区的每一天
去签到