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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy