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.60 and greater.
16
17#![doc(html_root_url = "https://docs.rs/num-traits/0.2")]
18#![deny(unconditional_recursion)]
19#![no_std]
20
21// Need to explicitly bring the crate in for inherent float methods
22#[cfg(feature = "std")]
23extern crate std;
24
25use core::fmt;
26use core::num::Wrapping;
27use core::ops::{Add, Div, Mul, Rem, Sub};
28use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
29
30pub use crate::bounds::Bounded;
31#[cfg(any(feature = "std", feature = "libm"))]
32pub use crate::float::Float;
33pub use crate::float::FloatConst;
34// pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`.
35pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive};
36pub use crate::identities::{one, zero, ConstOne, ConstZero, One, Zero};
37pub use crate::int::PrimInt;
38pub use crate::ops::bytes::{FromBytes, ToBytes};
39pub use crate::ops::checked::{
40    CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub,
41};
42pub use crate::ops::euclid::{CheckedEuclid, Euclid};
43pub use crate::ops::inv::Inv;
44pub use crate::ops::mul_add::{MulAdd, MulAddAssign};
45pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub};
46pub use crate::ops::wrapping::{
47    WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
48};
49pub use crate::pow::{checked_pow, pow, Pow};
50pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned};
51
52#[macro_use]
53mod macros;
54
55pub mod bounds;
56pub mod cast;
57pub mod float;
58pub mod identities;
59pub mod int;
60pub mod ops;
61pub mod pow;
62pub mod real;
63pub mod sign;
64
65/// The base trait for numeric types, covering `0` and `1` values,
66/// comparisons, basic numeric operations, and string conversion.
67pub trait Num: PartialEq + Zero + One + NumOps {
68    type FromStrRadixErr;
69
70    /// Convert from a string and radix (typically `2..=36`).
71    ///
72    /// # Examples
73    ///
74    /// ```rust
75    /// use num_traits::Num;
76    ///
77    /// let result = <i32 as Num>::from_str_radix("27", 10);
78    /// assert_eq!(result, Ok(27));
79    ///
80    /// let result = <i32 as Num>::from_str_radix("foo", 10);
81    /// assert!(result.is_err());
82    /// ```
83    ///
84    /// # Supported radices
85    ///
86    /// The exact range of supported radices is at the discretion of each type implementation. For
87    /// primitive integers, this is implemented by the inherent `from_str_radix` methods in the
88    /// standard library, which **panic** if the radix is not in the range from 2 to 36. The
89    /// implementation in this crate for primitive floats is similar.
90    ///
91    /// For third-party types, it is suggested that implementations should follow suit and at least
92    /// accept `2..=36` without panicking, but an `Err` may be returned for any unsupported radix.
93    /// It's possible that a type might not even support the common radix 10, nor any, if string
94    /// parsing doesn't make sense for that type.
95    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
96}
97
98/// Generic trait for types implementing basic numeric operations
99///
100/// This is automatically implemented for types which implement the operators.
101pub trait NumOps<Rhs = Self, Output = Self>:
102    Add<Rhs, Output = Output>
103    + Sub<Rhs, Output = Output>
104    + Mul<Rhs, Output = Output>
105    + Div<Rhs, Output = Output>
106    + Rem<Rhs, Output = Output>
107{
108}
109
110impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
111    T: Add<Rhs, Output = Output>
112        + Sub<Rhs, Output = Output>
113        + Mul<Rhs, Output = Output>
114        + Div<Rhs, Output = Output>
115        + Rem<Rhs, Output = Output>
116{
117}
118
119/// The trait for `Num` types which also implement numeric operations taking
120/// the second operand by reference.
121///
122/// This is automatically implemented for types which implement the operators.
123pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
124impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
125
126/// The trait for `Num` references which implement numeric operations, taking the
127/// second operand either by value or by reference.
128///
129/// This is automatically implemented for all types which implement the operators. It covers
130/// every type implementing the operations though, regardless of it being a reference or
131/// related to `Num`.
132pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
133impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
134
135/// Generic trait for types implementing numeric assignment operators (like `+=`).
136///
137/// This is automatically implemented for types which implement the operators.
138pub trait NumAssignOps<Rhs = Self>:
139    AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
140{
141}
142
143impl<T, Rhs> NumAssignOps<Rhs> for T where
144    T: AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs>
145{
146}
147
148/// The trait for `Num` types which also implement assignment operators.
149///
150/// This is automatically implemented for types which implement the operators.
151pub trait NumAssign: Num + NumAssignOps {}
152impl<T> NumAssign for T where T: Num + NumAssignOps {}
153
154/// The trait for `NumAssign` types which also implement assignment operations
155/// taking the second operand by reference.
156///
157/// This is automatically implemented for types which implement the operators.
158pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
159impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
160
161macro_rules! int_trait_impl {
162    ($name:ident for $($t:ty)*) => ($(
163        impl $name for $t {
164            type FromStrRadixErr = ::core::num::ParseIntError;
165            #[inline]
166            fn from_str_radix(s: &str, radix: u32)
167                              -> Result<Self, ::core::num::ParseIntError>
168            {
169                <$t>::from_str_radix(s, radix)
170            }
171        }
172    )*)
173}
174int_trait_impl!(Num for usize u8 u16 u32 u64 u128);
175int_trait_impl!(Num for isize i8 i16 i32 i64 i128);
176
177impl<T: Num> Num for Wrapping<T>
178where
179    Wrapping<T>: NumOps,
180{
181    type FromStrRadixErr = T::FromStrRadixErr;
182    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
183        T::from_str_radix(str, radix).map(Wrapping)
184    }
185}
186
187#[derive(Debug)]
188pub enum FloatErrorKind {
189    Empty,
190    Invalid,
191}
192// FIXME: core::num::ParseFloatError is stable in 1.0, but opaque to us,
193// so there's not really any way for us to reuse it.
194#[derive(Debug)]
195pub struct ParseFloatError {
196    pub kind: FloatErrorKind,
197}
198
199impl fmt::Display for ParseFloatError {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        let description = match self.kind {
202            FloatErrorKind::Empty => "cannot parse float from empty string",
203            FloatErrorKind::Invalid => "invalid float literal",
204        };
205
206        description.fmt(f)
207    }
208}
209
210fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool {
211    a.len() == b.len()
212        && a.bytes().zip(b.bytes()).all(|(a, b)| {
213            let a_to_ascii_lower = a | (((b'A' <= a && a <= b'Z') as u8) << 5);
214            a_to_ascii_lower == b
215        })
216}
217
218// FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
219// with this implementation ourselves until we want to make a breaking change.
220// (would have to drop it from `Num` though)
221macro_rules! float_trait_impl {
222    ($name:ident for $($t:ident)*) => ($(
223        impl $name for $t {
224            type FromStrRadixErr = ParseFloatError;
225
226            fn from_str_radix(src: &str, radix: u32)
227                              -> Result<Self, Self::FromStrRadixErr>
228            {
229                use self::FloatErrorKind::*;
230                use self::ParseFloatError as PFE;
231
232                // Special case radix 10 to use more accurate standard library implementation
233                if radix == 10 {
234                    return src.parse().map_err(|_| PFE {
235                        kind: if src.is_empty() { Empty } else { Invalid },
236                    });
237                }
238
239                // Special values
240                if str_to_ascii_lower_eq_str(src, "inf")
241                    || str_to_ascii_lower_eq_str(src, "infinity")
242                {
243                    return Ok(core::$t::INFINITY);
244                } else if str_to_ascii_lower_eq_str(src, "-inf")
245                    || str_to_ascii_lower_eq_str(src, "-infinity")
246                {
247                    return Ok(core::$t::NEG_INFINITY);
248                } else if str_to_ascii_lower_eq_str(src, "nan") {
249                    return Ok(core::$t::NAN);
250                } else if str_to_ascii_lower_eq_str(src, "-nan") {
251                    return Ok(-core::$t::NAN);
252                }
253
254                fn slice_shift_char(src: &str) -> Option<(char, &str)> {
255                    let mut chars = src.chars();
256                    Some((chars.next()?, chars.as_str()))
257                }
258
259                let (is_positive, src) =  match slice_shift_char(src) {
260                    None             => return Err(PFE { kind: Empty }),
261                    Some(('-', ""))  => return Err(PFE { kind: Empty }),
262                    Some(('-', src)) => (false, src),
263                    Some((_, _))     => (true,  src),
264                };
265
266                // The significand to accumulate
267                let mut sig = if is_positive { 0.0 } else { -0.0 };
268                // Necessary to detect overflow
269                let mut prev_sig = sig;
270                let mut cs = src.chars().enumerate();
271                // Exponent prefix and exponent index offset
272                let mut exp_info = None::<(char, usize)>;
273
274                // Parse the integer part of the significand
275                for (i, c) in cs.by_ref() {
276                    match c.to_digit(radix) {
277                        Some(digit) => {
278                            // shift significand one digit left
279                            sig *= radix as $t;
280
281                            // add/subtract current digit depending on sign
282                            if is_positive {
283                                sig += (digit as isize) as $t;
284                            } else {
285                                sig -= (digit as isize) as $t;
286                            }
287
288                            // Detect overflow by comparing to last value, except
289                            // if we've not seen any non-zero digits.
290                            if prev_sig != 0.0 {
291                                if is_positive && sig <= prev_sig
292                                    { return Ok(core::$t::INFINITY); }
293                                if !is_positive && sig >= prev_sig
294                                    { return Ok(core::$t::NEG_INFINITY); }
295
296                                // Detect overflow by reversing the shift-and-add process
297                                if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
298                                    { return Ok(core::$t::INFINITY); }
299                                if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
300                                    { return Ok(core::$t::NEG_INFINITY); }
301                            }
302                            prev_sig = sig;
303                        },
304                        None => match c {
305                            'e' | 'E' | 'p' | 'P' => {
306                                exp_info = Some((c, i + 1));
307                                break;  // start of exponent
308                            },
309                            '.' => {
310                                break;  // start of fractional part
311                            },
312                            _ => {
313                                return Err(PFE { kind: Invalid });
314                            },
315                        },
316                    }
317                }
318
319                // If we are not yet at the exponent parse the fractional
320                // part of the significand
321                if exp_info.is_none() {
322                    let mut power = 1.0;
323                    for (i, c) in cs.by_ref() {
324                        match c.to_digit(radix) {
325                            Some(digit) => {
326                                // Decrease power one order of magnitude
327                                power /= radix as $t;
328                                // add/subtract current digit depending on sign
329                                sig = if is_positive {
330                                    sig + (digit as $t) * power
331                                } else {
332                                    sig - (digit as $t) * power
333                                };
334                                // Detect overflow by comparing to last value
335                                if is_positive && sig < prev_sig
336                                    { return Ok(core::$t::INFINITY); }
337                                if !is_positive && sig > prev_sig
338                                    { return Ok(core::$t::NEG_INFINITY); }
339                                prev_sig = sig;
340                            },
341                            None => match c {
342                                'e' | 'E' | 'p' | 'P' => {
343                                    exp_info = Some((c, i + 1));
344                                    break; // start of exponent
345                                },
346                                _ => {
347                                    return Err(PFE { kind: Invalid });
348                                },
349                            },
350                        }
351                    }
352                }
353
354                // Parse and calculate the exponent
355                let exp = match exp_info {
356                    Some((c, offset)) => {
357                        let base = match c {
358                            'E' | 'e' if radix == 10 => 10.0,
359                            'P' | 'p' if radix == 16 => 2.0,
360                            _ => return Err(PFE { kind: Invalid }),
361                        };
362
363                        // Parse the exponent as decimal integer
364                        let src = &src[offset..];
365                        let (is_positive, exp) = match slice_shift_char(src) {
366                            Some(('-', src)) => (false, src.parse::<usize>()),
367                            Some(('+', src)) => (true,  src.parse::<usize>()),
368                            Some((_, _))     => (true,  src.parse::<usize>()),
369                            None             => return Err(PFE { kind: Invalid }),
370                        };
371
372                        #[cfg(feature = "std")]
373                        fn pow(base: $t, exp: usize) -> $t {
374                            Float::powi(base, exp as i32)
375                        }
376                        // otherwise uses the generic `pow` from the root
377
378                        match (is_positive, exp) {
379                            (true,  Ok(exp)) => pow(base, exp),
380                            (false, Ok(exp)) => 1.0 / pow(base, exp),
381                            (_, Err(_))      => return Err(PFE { kind: Invalid }),
382                        }
383                    },
384                    None => 1.0, // no exponent
385                };
386
387                Ok(sig * exp)
388            }
389        }
390    )*)
391}
392float_trait_impl!(Num for f32 f64);
393
394/// A value bounded by a minimum and a maximum
395///
396///  If input is less than min then this returns min.
397///  If input is greater than max then this returns max.
398///  Otherwise this returns input.
399///
400/// **Panics** in debug mode if `!(min <= max)`.
401#[inline]
402pub fn clamp<T: PartialOrd>(input: T, min: T, max: T) -> T {
403    debug_assert!(min <= max, "min must be less than or equal to max");
404    if input < min {
405        min
406    } else if input > max {
407        max
408    } else {
409        input
410    }
411}
412
413/// A value bounded by a minimum value
414///
415///  If input is less than min then this returns min.
416///  Otherwise this returns input.
417///  `clamp_min(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::min(std::f32::NAN, 1.0)`.
418///
419/// **Panics** in debug mode if `!(min == min)`. (This occurs if `min` is `NAN`.)
420#[inline]
421#[allow(clippy::eq_op)]
422pub fn clamp_min<T: PartialOrd>(input: T, min: T) -> T {
423    debug_assert!(min == min, "min must not be NAN");
424    if input < min {
425        min
426    } else {
427        input
428    }
429}
430
431/// A value bounded by a maximum value
432///
433///  If input is greater than max then this returns max.
434///  Otherwise this returns input.
435///  `clamp_max(std::f32::NAN, 1.0)` preserves `NAN` different from `f32::max(std::f32::NAN, 1.0)`.
436///
437/// **Panics** in debug mode if `!(max == max)`. (This occurs if `max` is `NAN`.)
438#[inline]
439#[allow(clippy::eq_op)]
440pub fn clamp_max<T: PartialOrd>(input: T, max: T) -> T {
441    debug_assert!(max == max, "max must not be NAN");
442    if input > max {
443        max
444    } else {
445        input
446    }
447}
448
449#[test]
450fn clamp_test() {
451    // Int test
452    assert_eq!(1, clamp(1, -1, 2));
453    assert_eq!(-1, clamp(-2, -1, 2));
454    assert_eq!(2, clamp(3, -1, 2));
455    assert_eq!(1, clamp_min(1, -1));
456    assert_eq!(-1, clamp_min(-2, -1));
457    assert_eq!(-1, clamp_max(1, -1));
458    assert_eq!(-2, clamp_max(-2, -1));
459
460    // Float test
461    assert_eq!(1.0, clamp(1.0, -1.0, 2.0));
462    assert_eq!(-1.0, clamp(-2.0, -1.0, 2.0));
463    assert_eq!(2.0, clamp(3.0, -1.0, 2.0));
464    assert_eq!(1.0, clamp_min(1.0, -1.0));
465    assert_eq!(-1.0, clamp_min(-2.0, -1.0));
466    assert_eq!(-1.0, clamp_max(1.0, -1.0));
467    assert_eq!(-2.0, clamp_max(-2.0, -1.0));
468    assert!(clamp(::core::f32::NAN, -1.0, 1.0).is_nan());
469    assert!(clamp_min(::core::f32::NAN, 1.0).is_nan());
470    assert!(clamp_max(::core::f32::NAN, 1.0).is_nan());
471}
472
473#[test]
474#[should_panic]
475#[cfg(debug_assertions)]
476fn clamp_nan_min() {
477    clamp(0., ::core::f32::NAN, 1.);
478}
479
480#[test]
481#[should_panic]
482#[cfg(debug_assertions)]
483fn clamp_nan_max() {
484    clamp(0., -1., ::core::f32::NAN);
485}
486
487#[test]
488#[should_panic]
489#[cfg(debug_assertions)]
490fn clamp_nan_min_max() {
491    clamp(0., ::core::f32::NAN, ::core::f32::NAN);
492}
493
494#[test]
495#[should_panic]
496#[cfg(debug_assertions)]
497fn clamp_min_nan_min() {
498    clamp_min(0., ::core::f32::NAN);
499}
500
501#[test]
502#[should_panic]
503#[cfg(debug_assertions)]
504fn clamp_max_nan_max() {
505    clamp_max(0., ::core::f32::NAN);
506}
507
508#[test]
509fn from_str_radix_unwrap() {
510    // The Result error must impl Debug to allow unwrap()
511
512    let i: i32 = Num::from_str_radix("0", 10).unwrap();
513    assert_eq!(i, 0);
514
515    let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
516    assert_eq!(f, 0.0);
517}
518
519#[test]
520fn from_str_radix_multi_byte_fail() {
521    // Ensure parsing doesn't panic, even on invalid sign characters
522    assert!(f32::from_str_radix("™0.2", 10).is_err());
523
524    // Even when parsing the exponent sign
525    assert!(f32::from_str_radix("0.2E™1", 10).is_err());
526}
527
528#[test]
529fn from_str_radix_ignore_case() {
530    assert_eq!(
531        f32::from_str_radix("InF", 16).unwrap(),
532        ::core::f32::INFINITY
533    );
534    assert_eq!(
535        f32::from_str_radix("InfinitY", 16).unwrap(),
536        ::core::f32::INFINITY
537    );
538    assert_eq!(
539        f32::from_str_radix("-InF", 8).unwrap(),
540        ::core::f32::NEG_INFINITY
541    );
542    assert_eq!(
543        f32::from_str_radix("-InfinitY", 8).unwrap(),
544        ::core::f32::NEG_INFINITY
545    );
546    assert!(f32::from_str_radix("nAn", 4).unwrap().is_nan());
547    assert!(f32::from_str_radix("-nAn", 4).unwrap().is_nan());
548}
549
550#[test]
551fn wrapping_is_num() {
552    fn require_num<T: Num>(_: &T) {}
553    require_num(&Wrapping(42_u32));
554    require_num(&Wrapping(-42));
555}
556
557#[test]
558fn wrapping_from_str_radix() {
559    macro_rules! test_wrapping_from_str_radix {
560        ($($t:ty)+) => {
561            $(
562                for &(s, r) in &[("42", 10), ("42", 2), ("-13.0", 10), ("foo", 10)] {
563                    let w = Wrapping::<$t>::from_str_radix(s, r).map(|w| w.0);
564                    assert_eq!(w, <$t as Num>::from_str_radix(s, r));
565                }
566            )+
567        };
568    }
569
570    test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
571}
572
573#[test]
574fn check_num_ops() {
575    fn compute<T: Num + Copy>(x: T, y: T) -> T {
576        x * y / y % y + y - y
577    }
578    assert_eq!(compute(1, 2), 1)
579}
580
581#[test]
582fn check_numref_ops() {
583    fn compute<T: NumRef>(x: T, y: &T) -> T {
584        x * y / y % y + y - y
585    }
586    assert_eq!(compute(1, &2), 1)
587}
588
589#[test]
590fn check_refnum_ops() {
591    fn compute<T: Copy>(x: &T, y: T) -> T
592    where
593        for<'a> &'a T: RefNum<T>,
594    {
595        &(&(&(&(x * y) / y) % y) + y) - y
596    }
597    assert_eq!(compute(&1, 2), 1)
598}
599
600#[test]
601fn check_refref_ops() {
602    fn compute<T>(x: &T, y: &T) -> T
603    where
604        for<'a> &'a T: RefNum<T>,
605    {
606        &(&(&(&(x * y) / y) % y) + y) - y
607    }
608    assert_eq!(compute(&1, &2), 1)
609}
610
611#[test]
612fn check_numassign_ops() {
613    fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
614        x *= y;
615        x /= y;
616        x %= y;
617        x += y;
618        x -= y;
619        x
620    }
621    assert_eq!(compute(1, 2), 1)
622}
623
624#[test]
625fn check_numassignref_ops() {
626    fn compute<T: NumAssignRef + Copy>(mut x: T, y: &T) -> T {
627        x *= y;
628        x /= y;
629        x %= y;
630        x += y;
631        x -= y;
632        x
633    }
634    assert_eq!(compute(1, &2), 1)
635}