num_traits/
sign.rs

1use core::num::Wrapping;
2use core::ops::Neg;
3
4use crate::float::FloatCore;
5use crate::Num;
6
7/// Useful functions for signed numbers (i.e. numbers that can be negative).
8pub trait Signed: Sized + Num + Neg<Output = Self> {
9    /// Computes the absolute value.
10    ///
11    /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
12    ///
13    /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
14    fn abs(&self) -> Self;
15
16    /// The positive difference of two numbers.
17    ///
18    /// Returns `zero` if the number is less than or equal to `other`, otherwise the difference
19    /// between `self` and `other` is returned.
20    fn abs_sub(&self, other: &Self) -> Self;
21
22    /// Returns the sign of the number.
23    ///
24    /// For `f32` and `f64`:
25    ///
26    /// * `1.0` if the number is positive, `+0.0` or `INFINITY`
27    /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
28    /// * `NaN` if the number is `NaN`
29    ///
30    /// For signed integers:
31    ///
32    /// * `0` if the number is zero
33    /// * `1` if the number is positive
34    /// * `-1` if the number is negative
35    fn signum(&self) -> Self;
36
37    /// Returns true if the number is positive and false if the number is zero or negative.
38    fn is_positive(&self) -> bool;
39
40    /// Returns true if the number is negative and false if the number is zero or positive.
41    fn is_negative(&self) -> bool;
42}
43
44macro_rules! signed_impl {
45    ($($t:ty)*) => ($(
46        impl Signed for $t {
47            #[inline]
48            fn abs(&self) -> $t {
49                if self.is_negative() { -*self } else { *self }
50            }
51
52            #[inline]
53            fn abs_sub(&self, other: &$t) -> $t {
54                if *self <= *other { 0 } else { *self - *other }
55            }
56
57            #[inline]
58            fn signum(&self) -> $t {
59                match *self {
60                    n if n > 0 => 1,
61                    0 => 0,
62                    _ => -1,
63                }
64            }
65
66            #[inline]
67            fn is_positive(&self) -> bool { *self > 0 }
68
69            #[inline]
70            fn is_negative(&self) -> bool { *self < 0 }
71        }
72    )*)
73}
74
75signed_impl!(isize i8 i16 i32 i64 i128);
76
77impl<T: Signed> Signed for Wrapping<T>
78where
79    Wrapping<T>: Num + Neg<Output = Wrapping<T>>,
80{
81    #[inline]
82    fn abs(&self) -> Self {
83        Wrapping(self.0.abs())
84    }
85
86    #[inline]
87    fn abs_sub(&self, other: &Self) -> Self {
88        Wrapping(self.0.abs_sub(&other.0))
89    }
90
91    #[inline]
92    fn signum(&self) -> Self {
93        Wrapping(self.0.signum())
94    }
95
96    #[inline]
97    fn is_positive(&self) -> bool {
98        self.0.is_positive()
99    }
100
101    #[inline]
102    fn is_negative(&self) -> bool {
103        self.0.is_negative()
104    }
105}
106
107macro_rules! signed_float_impl {
108    ($t:ty) => {
109        impl Signed for $t {
110            /// Computes the absolute value. Returns `NAN` if the number is `NAN`.
111            #[inline]
112            fn abs(&self) -> $t {
113                FloatCore::abs(*self)
114            }
115
116            /// The positive difference of two numbers. Returns `0.0` if the number is
117            /// less than or equal to `other`, otherwise the difference between`self`
118            /// and `other` is returned.
119            #[inline]
120            fn abs_sub(&self, other: &$t) -> $t {
121                if *self <= *other {
122                    0.
123                } else {
124                    *self - *other
125                }
126            }
127
128            /// # Returns
129            ///
130            /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
131            /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
132            /// - `NAN` if the number is NaN
133            #[inline]
134            fn signum(&self) -> $t {
135                FloatCore::signum(*self)
136            }
137
138            /// Returns `true` if the number is positive, including `+0.0` and `INFINITY`
139            #[inline]
140            fn is_positive(&self) -> bool {
141                FloatCore::is_sign_positive(*self)
142            }
143
144            /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY`
145            #[inline]
146            fn is_negative(&self) -> bool {
147                FloatCore::is_sign_negative(*self)
148            }
149        }
150    };
151}
152
153signed_float_impl!(f32);
154signed_float_impl!(f64);
155
156/// Computes the absolute value.
157///
158/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
159///
160/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
161#[inline(always)]
162pub fn abs<T: Signed>(value: T) -> T {
163    value.abs()
164}
165
166/// The positive difference of two numbers.
167///
168/// Returns zero if `x` is less than or equal to `y`, otherwise the difference
169/// between `x` and `y` is returned.
170#[inline(always)]
171pub fn abs_sub<T: Signed>(x: T, y: T) -> T {
172    x.abs_sub(&y)
173}
174
175/// Returns the sign of the number.
176///
177/// For `f32` and `f64`:
178///
179/// * `1.0` if the number is positive, `+0.0` or `INFINITY`
180/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
181/// * `NaN` if the number is `NaN`
182///
183/// For signed integers:
184///
185/// * `0` if the number is zero
186/// * `1` if the number is positive
187/// * `-1` if the number is negative
188#[inline(always)]
189pub fn signum<T: Signed>(value: T) -> T {
190    value.signum()
191}
192
193/// A trait for values which cannot be negative
194pub trait Unsigned: Num {}
195
196macro_rules! empty_trait_impl {
197    ($name:ident for $($t:ty)*) => ($(
198        impl $name for $t {}
199    )*)
200}
201
202empty_trait_impl!(Unsigned for usize u8 u16 u32 u64 u128);
203
204impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {}
205
206#[test]
207fn unsigned_wrapping_is_unsigned() {
208    fn require_unsigned<T: Unsigned>(_: &T) {}
209    require_unsigned(&Wrapping(42_u32));
210}
211
212#[test]
213fn signed_wrapping_is_signed() {
214    fn require_signed<T: Signed>(_: &T) {}
215    require_signed(&Wrapping(-42));
216}