#[cfg(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
))]
#[inline(always)]
#[allow(unused)]
pub(crate) fn fmla(a: f32, b: f32, c: f32) -> f32 {
f32::mul_add(a, b, c)
}
#[cfg(not(any(
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "fma"
),
target_arch = "aarch64"
)))]
#[inline(always)]
#[allow(unused)]
pub(crate) fn fmla(a: f32, b: f32, c: f32) -> f32 {
a * b + c
}
pub(crate) trait FastRound {
fn fast_round(self) -> Self;
}
impl FastRound for f32 {
#[inline(always)]
fn fast_round(self) -> Self {
#[cfg(all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "sse4.1"
))]
{
const MAGIC: f32 = ((1u32 << 23) + (1u32 << 22)) as f32;
(f32::from_bits(self.to_bits() + 1) + MAGIC) - MAGIC
}
#[cfg(target_arch = "aarch64")]
{
self.round()
}
#[cfg(not(any(
target_arch = "aarch64",
all(
any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "sse4.1"
)
)))]
{
const MAGIC: f32 = ((1u32 << 23) + (1u32 << 22)) as f32;
(f32::from_bits(self.to_bits() + 1) + MAGIC) - MAGIC
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fast_round_matches_round_for_aq_values() {
for value in -4096..=4096 {
let value = value as f32 / 256.0;
assert_eq!(value.fast_round(), value.round(), "value={value}");
}
}
}