1#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
18#![deny(unconditional_recursion)]
19#![no_std]
20#[cfg(feature = "std")]
21extern crate std;
22
23#[cfg(all(not(feature = "std"), feature = "libm"))]
25extern crate libm;
26
27use core::fmt;
28use core::num::Wrapping;
29use core::ops::{Add, Div, Mul, Rem, Sub};
30use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
31
32pub use bounds::Bounded;
33#[cfg(any(feature = "std", feature = "libm"))]
34pub use float::Float;
35pub use float::FloatConst;
36pub use cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
38pub use identities::{one, zero, One, Zero};
39pub use int::PrimInt;
40pub use ops::checked::{
41 CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
42};
43pub use ops::inv::Inv;
44pub use ops::mul_add::{MulAdd, MulAddAssign};
45pub use ops::saturating::Saturating;
46pub use ops::wrapping::{WrappingAdd, WrappingMul, WrappingShl, WrappingShr, WrappingSub};
47pub use pow::{checked_pow, pow, Pow};
48pub use sign::{abs, abs_sub, signum, Signed, Unsigned};
49
50#[macro_use]
51mod macros;
52
53pub mod bounds;
54pub mod cast;
55pub mod float;
56pub mod identities;
57pub mod int;
58pub mod ops;
59pub mod pow;
60pub mod real;
61pub mod sign;
62
63pub trait Num: PartialEq + Zero + One + NumOps {
66 type FromStrRadixErr;
67
68 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
82}
83
84pub trait NumOps<Rhs = Self, Output = Self>:
88 Add<Rhs, Output = Output>
89 + Sub<Rhs, Output = Output>
90 + Mul<Rhs, Output = Output>
91 + Div<Rhs, Output = Output>
92 + Rem<Rhs, Output = Output>
93{
94}
95
96impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
97 T: Add<Rhs, Output = Output>
98 + Sub<Rhs, Output = Output>
99 + Mul<Rhs, Output = Output>
100 + Div<Rhs, Output = Output>
101 + Rem<Rhs, Output = Output>
102{
103}
104
105pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
110impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
111
112pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
117impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
118
119pub trait NumAssignOps<Rhs = Self>:
123 AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
124{
125}
126
127impl<T, Rhs> NumAssignOps<Rhs> for T where
128 T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
129{
130}
131
132pub trait NumAssign: Num + NumAssignOps {}
136impl<T> NumAssign for T where T: Num + NumAssignOps {}
137
138pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
143impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
144
145macro_rules! int_trait_impl {
146 ($name:ident for $($t:ty)*) => ($(
147 impl $name for $t {
148 type FromStrRadixErr = ::core::num::ParseIntError;
149 #[inline]
150 fn from_str_radix(s: &str, radix: u32)
151 -> Result<Self, ::core::num::ParseIntError>
152 {
153 <$t>::from_str_radix(s, radix)
154 }
155 }
156 )*)
157}
158int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
159#[cfg(has_i128)]
160int_trait_impl!(Num for u128 i128);
161
162impl<T: Num> Num for Wrapping<T>
163where
164 Wrapping<T>: Add<Output = Wrapping<T>>
165 + Sub<Output = Wrapping<T>>
166 + Mul<Output = Wrapping<T>>
167 + Div<Output = Wrapping<T>>
168 + Rem<Output = Wrapping<T>>,
169{
170 type FromStrRadixErr = T::FromStrRadixErr;
171 fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
172 T::from_str_radix(str, radix).map(Wrapping)
173 }
174}
175
176#[derive(Debug)]
177pub enum FloatErrorKind {
178 Empty,
179 Invalid,
180}
181#[derive(Debug)]
184pub struct ParseFloatError {
185 pub kind: FloatErrorKind,
186}
187
188impl fmt::Display for ParseFloatError {
189 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190 let description = match self.kind {
191 FloatErrorKind::Empty => "cannot parse float from empty string",
192 FloatErrorKind::Invalid => "invalid float literal",
193 };
194
195 description.fmt(f)
196 }
197}
198
199macro_rules! float_trait_impl {
203 ($name:ident for $($t:ident)*) => ($(
204 impl $name for $t {
205 type FromStrRadixErr = ParseFloatError;
206
207 fn from_str_radix(src: &str, radix: u32)
208 -> Result<Self, Self::FromStrRadixErr>
209 {
210 use self::FloatErrorKind::*;
211 use self::ParseFloatError as PFE;
212
213 match src {
215 "inf" => return Ok(core::$t::INFINITY),
216 "-inf" => return Ok(core::$t::NEG_INFINITY),
217 "NaN" => return Ok(core::$t::NAN),
218 _ => {},
219 }
220
221 fn slice_shift_char(src: &str) -> Option<(char, &str)> {
222 let mut chars = src.chars();
223 if let Some(ch) = chars.next() {
224 Some((ch, chars.as_str()))
225 } else {
226 None
227 }
228 }
229
230 let (is_positive, src) = match slice_shift_char(src) {
231 None => return Err(PFE { kind: Empty }),
232 Some(('-', "")) => return Err(PFE { kind: Empty }),
233 Some(('-', src)) => (false, src),
234 Some((_, _)) => (true, src),
235 };
236
237 let mut sig = if is_positive { 0.0 } else { -0.0 };
239 let mut prev_sig = sig;
241 let mut cs = src.chars().enumerate();
242 let mut exp_info = None::<(char, usize)>;
244
245 for (i, c) in cs.by_ref() {
247 match c.to_digit(radix) {
248 Some(digit) => {
249 sig = sig * (radix as $t);
251
252 if is_positive {
254 sig = sig + ((digit as isize) as $t);
255 } else {
256 sig = sig - ((digit as isize) as $t);
257 }
258
259 if prev_sig != 0.0 {
262 if is_positive && sig <= prev_sig
263 { return Ok(core::$t::INFINITY); }
264 if !is_positive && sig >= prev_sig
265 { return Ok(core::$t::NEG_INFINITY); }
266
267 if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
269 { return Ok(core::$t::INFINITY); }
270 if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
271 { return Ok(core::$t::NEG_INFINITY); }
272 }
273 prev_sig = sig;
274 },
275 None => match c {
276 'e' | 'E' | 'p' | 'P' => {
277 exp_info = Some((c, i + 1));
278 break; },
280 '.' => {
281 break; },
283 _ => {
284 return Err(PFE { kind: Invalid });
285 },
286 },
287 }
288 }
289
290 if exp_info.is_none() {
293 let mut power = 1.0;
294 for (i, c) in cs.by_ref() {
295 match c.to_digit(radix) {
296 Some(digit) => {
297 power = power / (radix as $t);
299 sig = if is_positive {
301 sig + (digit as $t) * power
302 } else {
303 sig - (digit as $t) * power
304 };
305 if is_positive && sig < prev_sig
307 { return Ok(core::$t::INFINITY); }
308 if !is_positive && sig > prev_sig
309 { return Ok(core::$t::NEG_INFINITY); }
310 prev_sig = sig;
311 },
312 None => match c {
313 'e' | 'E' | 'p' | 'P' => {
314 exp_info = Some((c, i + 1));
315 break; },
317 _ => {
318 return Err(PFE { kind: Invalid });
319 },
320 },
321 }
322 }
323 }
324
325 let exp = match exp_info {
327 Some((c, offset)) => {
328 let base = match c {
329 'E' | 'e' if radix == 10 => 10.0,
330 'P' | 'p' if radix == 16 => 2.0,
331 _ => return Err(PFE { kind: Invalid }),
332 };
333
334 let src = &src[offset..];
336 let (is_positive, exp) = match slice_shift_char(src) {
337 Some(('-', src)) => (false, src.parse::<usize>()),
338 Some(('+', src)) => (true, src.parse::<usize>()),
339 Some((_, _)) => (true, src.parse::<usize>()),
340 None => return Err(PFE { kind: Invalid }),
341 };
342
343 #[cfg(feature = "std")]
344 fn pow(base: $t, exp: usize) -> $t {
345 Float::powi(base, exp as i32)
346 }
347 match (is_positive, exp) {
350 (true, Ok(exp)) => pow(base, exp),
351 (false, Ok(exp)) => 1.0 / pow(base, exp),
352 (_, Err(_)) => return Err(PFE { kind: Invalid }),
353 }
354 },
355 None => 1.0, };
357
358 Ok(sig * exp)
359 }
360 }
361 )*)
362}
363float_trait_impl!(Num for f32 f64);
364
365#[inline]
373pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
374 debug_assert!(min <= max, "min must be less than or equal to max");
375 if input < min {
376 min
377 } else if input > max {
378 max
379 } else {
380 input
381 }
382}
383
384#[inline]
392pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
393 debug_assert!(min == min, "min must not be NAN");
394 if input < min {
395 min
396 } else {
397 input
398 }
399}
400
401#[inline]
409pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
410 debug_assert!(max == max, "max must not be NAN");
411 if input > max {
412 max
413 } else {
414 input
415 }
416}
417
418#[test]
419fn clamp_test() {
420 assert_eq!(1, clamp(1, -1, 2));
422 assert_eq!(-1, clamp(-2, -1, 2));
423 assert_eq!(2, clamp(3, -1, 2));
424 assert_eq!(1, clamp_min(1, -1));
425 assert_eq!(-1, clamp_min(-2, -1));
426 assert_eq!(-1, clamp_max(1, -1));
427 assert_eq!(-2, clamp_max(-2, -1));
428
429 assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
431 assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
432 assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
433 assert_eq!(1.0, clamp_min(1.0, -1.0));
434 assert_eq!(-1.0, clamp_min(-2.0, -1.0));
435 assert_eq!(-1.0, clamp_max(1.0, -1.0));
436 assert_eq!(-2.0, clamp_max(-2.0, -1.0));
437 assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
438 assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
439 assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
440}
441
442#[test]
443#[should_panic]
444#[cfg(debug_assertions)]
445fn clamp_nan_min() {
446 clamp(0., ::core::f32::NAN, 1.);
447}
448
449#[test]
450#[should_panic]
451#[cfg(debug_assertions)]
452fn clamp_nan_max() {
453 clamp(0., -1., ::core::f32::NAN);
454}
455
456#[test]
457#[should_panic]
458#[cfg(debug_assertions)]
459fn clamp_nan_min_max() {
460 clamp(0., ::core::f32::NAN, ::core::f32::NAN);
461}
462
463#[test]
464#[should_panic]
465#[cfg(debug_assertions)]
466fn clamp_min_nan_min() {
467 clamp_min(0., ::core::f32::NAN);
468}
469
470#[test]
471#[should_panic]
472#[cfg(debug_assertions)]
473fn clamp_max_nan_max() {
474 clamp_max(0., ::core::f32::NAN);
475}
476
477#[test]
478fn from_str_radix_unwrap() {
479 let i: i32 = Num::from_str_radix("0", 10).unwrap();
482 assert_eq!(i, 0);
483
484 let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
485 assert_eq!(f, 0.0);
486}
487
488#[test]
489fn from_str_radix_multi_byte_fail() {
490 assert!(f32::from_str_radix("™0.2", 10).is_err());
492
493 assert!(f32::from_str_radix("0.2E™1", 10).is_err());
495}
496
497#[test]
498fn wrapping_is_num() {
499 fn require_num<T: Num>(_: &T) {}
500 require_num(&Wrapping(42_u32));
501 require_num(&Wrapping(-42));
502}
503
504#[test]
505fn wrapping_from_str_radix() {
506 macro_rules! test_wrapping_from_str_radix {
507 ($($t:ty)+) => {
508 $(
509 for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
510 let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0);
511 assert_eq!(w, <$t as Num>::from_str_radix(s, r));
512 }
513 )+
514 };
515 }
516
517 test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
518}
519
520#[test]
521fn check_num_ops() {
522 fn compute<T: Num + Copy>(x: T, y: T) -> T {
523 x * y / y % y + y - y
524 }
525 assert_eq!(compute(1, 2), 1)
526}
527
528#[test]
529fn check_numref_ops() {
530 fn compute<T: NumRef>(x: T, y: &T) -> T {
531 x * y / y % y + y - y
532 }
533 assert_eq!(compute(1, &2), 1)
534}
535
536#[test]
537fn check_refnum_ops() {
538 fn compute<T: Copy>(x: &T, y: T) -> T
539 where
540 for<'a> &'a T: RefNum<T>,
541 {
542 &(&(&(&(x * y) / y) % y) + y) - y
543 }
544 assert_eq!(compute(&1, 2), 1)
545}
546
547#[test]
548fn check_refref_ops() {
549 fn compute<T>(x: &T, y: &T) -> T
550 where
551 for<'a> &'a T: RefNum<T>,
552 {
553 &(&(&(&(x * y) / y) % y) + y) - y
554 }
555 assert_eq!(compute(&1, &2), 1)
556}
557
558#[test]
559fn check_numassign_ops() {
560 fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
561 x *= y;
562 x /= y;
563 x %= y;
564 x += y;
565 x -= y;
566 x
567 }
568 assert_eq!(compute(1, 2), 1)
569}
570
571