]>
Commit | Line | Data |
---|---|---|
0531ce1d | 1 | use core::num::Wrapping; |
0731742a | 2 | use core::ops::Neg; |
8bb4bdeb | 3 | |
0531ce1d | 4 | use float::FloatCore; |
0731742a | 5 | use Num; |
8bb4bdeb XL |
6 | |
7 | /// Useful functions for signed numbers (i.e. numbers that can be negative). | |
8 | pub 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 | ||
44 | macro_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 | ||
75 | signed_impl!(isize i8 i16 i32 i64); | |
76 | ||
8faf50e0 XL |
77 | #[cfg(has_i128)] |
78 | signed_impl!(i128); | |
79 | ||
0731742a XL |
80 | impl<T: Signed> Signed for Wrapping<T> |
81 | where | |
82 | Wrapping<T>: Num + Neg<Output = Wrapping<T>>, | |
041b39d2 XL |
83 | { |
84 | #[inline] | |
85 | fn abs(&self) -> Self { | |
86 | Wrapping(self.0.abs()) | |
87 | } | |
88 | ||
89 | #[inline] | |
90 | fn abs_sub(&self, other: &Self) -> Self { | |
91 | Wrapping(self.0.abs_sub(&other.0)) | |
92 | } | |
93 | ||
94 | #[inline] | |
95 | fn signum(&self) -> Self { | |
96 | Wrapping(self.0.signum()) | |
97 | } | |
98 | ||
99 | #[inline] | |
0731742a XL |
100 | fn is_positive(&self) -> bool { |
101 | self.0.is_positive() | |
102 | } | |
041b39d2 XL |
103 | |
104 | #[inline] | |
0731742a XL |
105 | fn is_negative(&self) -> bool { |
106 | self.0.is_negative() | |
107 | } | |
041b39d2 XL |
108 | } |
109 | ||
8bb4bdeb | 110 | macro_rules! signed_float_impl { |
0531ce1d | 111 | ($t:ty) => { |
8bb4bdeb XL |
112 | impl Signed for $t { |
113 | /// Computes the absolute value. Returns `NAN` if the number is `NAN`. | |
114 | #[inline] | |
115 | fn abs(&self) -> $t { | |
0531ce1d | 116 | FloatCore::abs(*self) |
8bb4bdeb XL |
117 | } |
118 | ||
119 | /// The positive difference of two numbers. Returns `0.0` if the number is | |
120 | /// less than or equal to `other`, otherwise the difference between`self` | |
121 | /// and `other` is returned. | |
122 | #[inline] | |
8bb4bdeb | 123 | fn abs_sub(&self, other: &$t) -> $t { |
0731742a XL |
124 | if *self <= *other { |
125 | 0. | |
126 | } else { | |
127 | *self - *other | |
128 | } | |
8bb4bdeb XL |
129 | } |
130 | ||
131 | /// # Returns | |
132 | /// | |
133 | /// - `1.0` if the number is positive, `+0.0` or `INFINITY` | |
134 | /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` | |
135 | /// - `NAN` if the number is NaN | |
136 | #[inline] | |
137 | fn signum(&self) -> $t { | |
0531ce1d | 138 | FloatCore::signum(*self) |
8bb4bdeb XL |
139 | } |
140 | ||
141 | /// Returns `true` if the number is positive, including `+0.0` and `INFINITY` | |
142 | #[inline] | |
0731742a XL |
143 | fn is_positive(&self) -> bool { |
144 | FloatCore::is_sign_positive(*self) | |
145 | } | |
8bb4bdeb XL |
146 | |
147 | /// Returns `true` if the number is negative, including `-0.0` and `NEG_INFINITY` | |
148 | #[inline] | |
0731742a XL |
149 | fn is_negative(&self) -> bool { |
150 | FloatCore::is_sign_negative(*self) | |
151 | } | |
8bb4bdeb | 152 | } |
0731742a | 153 | }; |
8bb4bdeb XL |
154 | } |
155 | ||
0531ce1d XL |
156 | signed_float_impl!(f32); |
157 | signed_float_impl!(f64); | |
8bb4bdeb XL |
158 | |
159 | /// Computes the absolute value. | |
160 | /// | |
161 | /// For `f32` and `f64`, `NaN` will be returned if the number is `NaN` | |
162 | /// | |
163 | /// For signed integers, `::MIN` will be returned if the number is `::MIN`. | |
164 | #[inline(always)] | |
165 | pub fn abs<T: Signed>(value: T) -> T { | |
166 | value.abs() | |
167 | } | |
168 | ||
169 | /// The positive difference of two numbers. | |
170 | /// | |
171 | /// Returns zero if `x` is less than or equal to `y`, otherwise the difference | |
172 | /// between `x` and `y` is returned. | |
173 | #[inline(always)] | |
174 | pub fn abs_sub<T: Signed>(x: T, y: T) -> T { | |
175 | x.abs_sub(&y) | |
176 | } | |
177 | ||
178 | /// Returns the sign of the number. | |
179 | /// | |
180 | /// For `f32` and `f64`: | |
181 | /// | |
182 | /// * `1.0` if the number is positive, `+0.0` or `INFINITY` | |
183 | /// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` | |
184 | /// * `NaN` if the number is `NaN` | |
185 | /// | |
186 | /// For signed integers: | |
187 | /// | |
188 | /// * `0` if the number is zero | |
189 | /// * `1` if the number is positive | |
190 | /// * `-1` if the number is negative | |
0731742a XL |
191 | #[inline(always)] |
192 | pub fn signum<T: Signed>(value: T) -> T { | |
193 | value.signum() | |
194 | } | |
8bb4bdeb XL |
195 | |
196 | /// A trait for values which cannot be negative | |
197 | pub trait Unsigned: Num {} | |
198 | ||
199 | macro_rules! empty_trait_impl { | |
200 | ($name:ident for $($t:ty)*) => ($( | |
201 | impl $name for $t {} | |
202 | )*) | |
203 | } | |
204 | ||
205 | empty_trait_impl!(Unsigned for usize u8 u16 u32 u64); | |
8faf50e0 XL |
206 | #[cfg(has_i128)] |
207 | empty_trait_impl!(Unsigned for u128); | |
041b39d2 | 208 | |
f035d41b | 209 | impl<T: Unsigned> Unsigned for Wrapping<T> where Wrapping<T>: Num {} |
041b39d2 XL |
210 | |
211 | #[test] | |
212 | fn unsigned_wrapping_is_unsigned() { | |
213 | fn require_unsigned<T: Unsigned>(_: &T) {} | |
214 | require_unsigned(&Wrapping(42_u32)); | |
215 | } | |
5869c6ff | 216 | |
041b39d2 XL |
217 | // Commenting this out since it doesn't compile on Rust 1.8, |
218 | // because on this version Wrapping doesn't implement Neg and therefore can't | |
219 | // implement Signed. | |
5869c6ff XL |
220 | // #[test] |
221 | // fn signed_wrapping_is_signed() { | |
222 | // fn require_signed<T: Signed>(_: &T) {} | |
223 | // require_signed(&Wrapping(-42)); | |
224 | // } |