Skip to content

Commit

Permalink
update Floating and FloatOps
Browse files Browse the repository at this point in the history
- new `Floating` fns: `const_abs`, `flip_sign`.
- make `Floating::abs` fn const if possible.
- new `FloatOps` fn `flip_sign`.
- minor fixes.
- update docs.
  • Loading branch information
joseluis committed Dec 19, 2023
1 parent 76d331c commit af40515
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
14 changes: 12 additions & 2 deletions src/math/num/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,18 @@ mod _no_std_no_libm {
(trunc, x - trunc)
}

/// The absolute value.
#[must_use] #[inline]
/// The absolute value of `x`.
///
/// # Features
/// This function will only be `const` if either the `unsafe_data`
/// or `unsafe_math` feature is enabled,
/// and the `std` and `libm` features are disabled.
///
/// See also [`const_abs`][Self::const_abs].
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn abs(x: $f) -> $f { Self::const_abs(x) }
#[inline] #[must_use] #[allow(missing_docs)]
#[cfg(not(any(feature = "unsafe_data", feature = "unsafe_math")))]
pub fn abs(x: $f) -> $f {
let mask = <$ub>::MAX / 2;
let bits: $ub = x.to_bits() & mask;
Expand Down
73 changes: 54 additions & 19 deletions src/math/num/float/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use crate::code::iif;
// Implements methods independently of any features
//
// $f: the floating-point type.
// $ue: unsigned int type with the same bit-size.
// $ie: the integer type for integer exponentiation.
// $uf: unsigned int type with the same bit-size.
// $ue: unsigned int type used for integer exponentiation and number of terms (u32).
macro_rules! custom_impls {
($( ($f:ty, $ue:ty, $ie:ty) ),+) => { $( custom_impls![@$f, $ue, $ie]; )+ };
(@$f:ty, $ue:ty, $ie:ty) => { $crate::code::paste! {
($( ($f:ty:$uf:ty, $ue:ty) ),+) => { $( custom_impls![@$f:$uf, $ue]; )+ };
(@$f:ty:$uf:ty, $ue:ty) => { $crate::code::paste! {
/// # *Common implementations with or without `std` or `libm`*.
///
/// Total order const fns will only be `const` if the `unsafe_math` feature is enabled.
/// # Features
/// There are a few functions that can be *const* but only if either the
/// `unsafe_math` or `unsafe_data` feature is enabled.
impl Floating<$f> {
/// Returns the nearest integer to `x`, rounding ties to the nearest even integer.
// WAIT: https://github.com/rust-lang/rust/issues/96710
Expand Down Expand Up @@ -710,38 +711,72 @@ macro_rules! custom_impls {
}
}

/// The absolute value of `x` in constant-time.
///
/// This is a separate function from [`abs`][Self::abs] because we also want to have
/// the possibly more efficient `std` and `libm` implementations.
#[cfg_attr(feature = "nightly",
doc(cfg(any(feature = "unsafe_data", feature = "unsafe_math"))))]
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn const_abs(x: $f) -> $f {
let mask = <$uf>::MAX / 2;
unsafe {
let bits: $uf = core::mem::transmute(x);
core::mem::transmute(bits & mask)
}
}

/// Flips the sign of `x`.
/// # Features
/// This function will only be `const` if either the `unsafe_data`
/// or `unsafe_math` feature is enabled.
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn flip_sign(x: $f) -> $f {
let mask = <$uf>::MAX / 2 + 1;
unsafe {
let bits: $uf = core::mem::transmute(x);
core::mem::transmute(bits ^ mask)
}
}
#[inline] #[must_use] #[allow(missing_docs)]
#[cfg(not(any(feature = "unsafe_data", feature = "unsafe_math")))]
pub fn flip_sign(x: $f) -> $f {
let mask = <$uf>::MAX / 2 + 1;
<$f>::from_bits(x.to_bits() ^ mask)
}

/// Returns the clamped value, ignoring `NaN`.
#[must_use] #[inline(always)]
pub fn clamp(value: $f, min: $f, max: $f) -> $f {
Self::min(Self::max(value, min), max)
}

/// Returns the clamped value, using total order.
#[must_use] #[inline(always)]
#[cfg(feature = "unsafe_math")]
/// # Features
/// This function will only be `const` if either the `unsafe_data`
/// or `unsafe_math` feature is enabled.
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn clamp_total(value: $f, min: $f, max: $f) -> $f {
$crate::data::Comparing(value).clamp(min, max)
}
#[must_use] #[inline(always)] #[allow(missing_docs)]
#[cfg(not(feature = "unsafe_math"))]
#[inline] #[must_use] #[allow(missing_docs)]
#[cfg(not(any(feature = "unsafe_data", feature = "unsafe_math")))]
pub fn clamp_total(value: $f, min: $f, max: $f) -> $f {
$crate::data::Comparing(value).clamp(min, max)
}

/// Returns the maximum of two numbers using total order.
#[must_use] #[inline(always)]
#[cfg(feature = "unsafe_math")]
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn max_total(x: $f, y: $f) -> $f { $crate::data::Comparing(x).max(y) }
#[must_use] #[inline(always)] #[allow(missing_docs)]
#[cfg(not(feature = "unsafe_math"))]
#[inline] #[must_use] #[allow(missing_docs)]
#[cfg(not(any(feature = "unsafe_data", feature = "unsafe_math")))]
pub fn max_total(x: $f, y: $f) -> $f { $crate::data::Comparing(x).max(y) }

/// Returns the minimum of two numbers using total order.
#[must_use] #[inline(always)]
#[cfg(feature = "unsafe_math")]
#[inline] #[must_use] #[cfg(any(feature = "unsafe_data", feature = "unsafe_math"))]
pub const fn min_total(x: $f, y: $f) -> $f { $crate::data::Comparing(x).min(y) }
#[must_use] #[inline(always)] #[allow(missing_docs)]
#[cfg(not(feature = "unsafe_math"))]
#[inline] #[must_use] #[allow(missing_docs)]
#[cfg(not(any(feature = "unsafe_data", feature = "unsafe_math")))]
pub fn min_total(x: $f, y: $f) -> $f { $crate::data::Comparing(x).min(y) }

/// Returns the clamped `x` value, propagating `NaN`.
Expand Down Expand Up @@ -782,7 +817,7 @@ macro_rules! custom_impls {
}
}};
}
custom_impls![(f32, u32, i32), (f64, u32, i32)];
custom_impls![(f32:u32, u32), (f64:u64, u32)];

/* private helpers */

Expand Down
9 changes: 8 additions & 1 deletion src/math/num/float/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,14 @@ pub trait FloatOps: Sized {
#[must_use]
fn split(self) -> (Self, Self);

/// The absolute value.
/// The absolute value of `self`.
#[must_use]
fn abs(self) -> Self;

/// Flips the sign of `self`.
#[must_use]
fn flip_sign(self) -> Self;

/// Returns `true` if `self` has a positive sign.
#[must_use]
fn is_sign_positive(self) -> bool;
Expand Down Expand Up @@ -412,6 +416,9 @@ macro_rules! impl_float_ext {
#[inline(always)]
fn abs(self) -> Self { Floating::<$f>::abs(self) }

#[inline(always)]
fn flip_sign(self) -> Self { Floating::<$f>::flip_sign(self) }

#[inline(always)]
fn is_sign_positive(self) -> bool { <$f>::is_sign_positive(self) }

Expand Down

0 comments on commit af40515

Please sign in to comment.