num_traits/
lib.rs

1// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Numeric traits for generic mathematics
12//!
13//! ## Compatibility
14//!
15//! The `num-traits` crate is tested for rustc 1.8 and greater.
16
17#![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// Only `no_std` builds actually use `libm`.
24#[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;
36// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
37pub 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
63/// The base trait for numeric types, covering `0` and `1` values,
64/// comparisons, basic numeric operations, and string conversion.
65pub trait Num: PartialEq + Zero + One + NumOps {
66    type FromStrRadixErr;
67
68    /// Convert from a string and radix <= 36.
69    ///
70    /// # Examples
71    ///
72    /// ```rust
73    /// use num_traits::Num;
74    ///
75    /// let result = <i32 as Num>::from_str_radix("27", 10);
76    /// assert_eq!(result, Ok(27));
77    ///
78    /// let result = <i32 as Num>::from_str_radix("foo", 10);
79    /// assert!(result.is_err());
80    /// ```
81    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
82}
83
84/// The trait for types implementing basic numeric operations
85///
86/// This is automatically implemented for types which implement the operators.
87pub 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
105/// The trait for `Num` types which also implement numeric operations taking
106/// the second operand by reference.
107///
108/// This is automatically implemented for types which implement the operators.
109pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
110impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
111
112/// The trait for references which implement numeric operations, taking the
113/// second operand either by value or by reference.
114///
115/// This is automatically implemented for types which implement the operators.
116pub 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
119/// The trait for types implementing numeric assignment operators (like `+=`).
120///
121/// This is automatically implemented for types which implement the operators.
122pub 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
132/// The trait for `Num` types which also implement assignment operators.
133///
134/// This is automatically implemented for types which implement the operators.
135pub trait NumAssign: Num + NumAssignOps {}
136impl<T> NumAssign for T where T: Num + NumAssignOps {}
137
138/// The trait for `NumAssign` types which also implement assignment operations
139/// taking the second operand by reference.
140///
141/// This is automatically implemented for types which implement the operators.
142pub 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// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
182// so there's not really any way for us to reuse it.
183#[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
199// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
200// with this implementation ourselves until we want to make a breaking change.
201// (would have to drop it from `Num` though)
202macro_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                // Special values
214                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                // The significand to accumulate
238                let mut sig = if is_positive { 0.0 } else { -0.0 };
239                // Necessary to detect overflow
240                let mut prev_sig = sig;
241                let mut cs = src.chars().enumerate();
242                // Exponent prefix and exponent index offset
243                let mut exp_info = None::<(char, usize)>;
244
245                // Parse the integer part of the significand
246                for (i, c) in cs.by_ref() {
247                    match c.to_digit(radix) {
248                        Some(digit) => {
249                            // shift significand one digit left
250                            sig = sig * (radix as $t);
251
252                            // add/subtract current digit depending on sign
253                            if is_positive {
254                                sig = sig + ((digit as isize) as $t);
255                            } else {
256                                sig = sig - ((digit as isize) as $t);
257                            }
258
259                            // Detect overflow by comparing to last value, except
260                            // if we've not seen any non-zero digits.
261                            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                                // Detect overflow by reversing the shift-and-add process
268                                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;  // start of exponent
279                            },
280                            '.' => {
281                                break;  // start of fractional part
282                            },
283                            _ => {
284                                return Err(PFE { kind: Invalid });
285                            },
286                        },
287                    }
288                }
289
290                // If we are not yet at the exponent parse the fractional
291                // part of the significand
292                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                                // Decrease power one order of magnitude
298                                power = power / (radix as $t);
299                                // add/subtract current digit depending on sign
300                                sig = if is_positive {
301                                    sig + (digit as $t) * power
302                                } else {
303                                    sig - (digit as $t) * power
304                                };
305                                // Detect overflow by comparing to last value
306                                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; // start of exponent
316                                },
317                                _ => {
318                                    return Err(PFE { kind: Invalid });
319                                },
320                            },
321                        }
322                    }
323                }
324
325                // Parse and calculate the exponent
326                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                        // Parse the exponent as decimal integer
335                        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                        // otherwise uses the generic `pow` from the root
348
349                        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, // no exponent
356                };
357
358                Ok(sig * exp)
359            }
360        }
361    )*)
362}
363float_trait_impl!(Num for f32 f64);
364
365/// A value bounded by a minimum and a maximum
366///
367///  If input is less than min then this returns min.
368///  If input is greater than max then this returns max.
369///  Otherwise this returns input.
370///
371/// **Panics** in debug mode if `!(min <= max)`.
372#[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/// A value bounded by a minimum value
385///
386///  If input is less than min then this returns min.
387///  Otherwise this returns input.
388///  `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
389///
390/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
391#[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/// A value bounded by a maximum value
402///
403///  If input is greater than max then this returns max.
404///  Otherwise this returns input.
405///  `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
406///
407/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
408#[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    // Int test
421    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    // Float test
430    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    // The Result error must impl Debug to allow unwrap()
480
481    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    // Ensure parsing doesn't panic, even on invalid sign characters
491    assert!(f32::from_str_radix("™0.2", 10).is_err());
492
493    // Even when parsing the exponent sign
494    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// TODO test `NumAssignRef`, but even the standard numeric types don't
572// implement this yet. (see rust pr41336)