| 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" )] |
| 23 | extern crate std; |
| 24 | |
| 25 | use core::fmt; |
| 26 | use core::num::Wrapping; |
| 27 | use core::ops::{Add, Div, Mul, Rem, Sub}; |
| 28 | use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; |
| 29 | |
| 30 | pub use crate::bounds::Bounded; |
| 31 | #[cfg (any(feature = "std" , feature = "libm" ))] |
| 32 | pub use crate::float::Float; |
| 33 | pub use crate::float::FloatConst; |
| 34 | // pub use real::{FloatCore, Real}; // NOTE: Don't do this, it breaks `use num_traits::*;`. |
| 35 | pub use crate::cast::{cast, AsPrimitive, FromPrimitive, NumCast, ToPrimitive}; |
| 36 | pub use crate::identities::{one, zero, ConstOne, ConstZero, One, Zero}; |
| 37 | pub use crate::int::PrimInt; |
| 38 | pub use crate::ops::bytes::{FromBytes, ToBytes}; |
| 39 | pub use crate::ops::checked::{ |
| 40 | CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, |
| 41 | }; |
| 42 | pub use crate::ops::euclid::{CheckedEuclid, Euclid}; |
| 43 | pub use crate::ops::inv::Inv; |
| 44 | pub use crate::ops::mul_add::{MulAdd, MulAddAssign}; |
| 45 | pub use crate::ops::saturating::{Saturating, SaturatingAdd, SaturatingMul, SaturatingSub}; |
| 46 | pub use crate::ops::wrapping::{ |
| 47 | WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, |
| 48 | }; |
| 49 | pub use crate::pow::{checked_pow, pow, Pow}; |
| 50 | pub use crate::sign::{abs, abs_sub, signum, Signed, Unsigned}; |
| 51 | |
| 52 | #[macro_use ] |
| 53 | mod macros; |
| 54 | |
| 55 | pub mod bounds; |
| 56 | pub mod cast; |
| 57 | pub mod float; |
| 58 | pub mod identities; |
| 59 | pub mod int; |
| 60 | pub mod ops; |
| 61 | pub mod pow; |
| 62 | pub mod real; |
| 63 | pub mod sign; |
| 64 | |
| 65 | /// The base trait for numeric types, covering `0` and `1` values, |
| 66 | /// comparisons, basic numeric operations, and string conversion. |
| 67 | pub 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. |
| 101 | pub 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 | |
| 110 | impl<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. |
| 123 | pub trait NumRef: Num + for<'r> dynNumOps<&'r Self> {} |
| 124 | impl<T> NumRef for T where T: Num + for<'r> dynNumOps<&'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`. |
| 132 | pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> dynNumOps<&'r Base, Base> {} |
| 133 | impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> dynNumOps<&'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. |
| 138 | pub trait NumAssignOps<Rhs = Self>: |
| 139 | AddAssign<Rhs> + SubAssign<Rhs> + MulAssign<Rhs> + DivAssign<Rhs> + RemAssign<Rhs> |
| 140 | { |
| 141 | } |
| 142 | |
| 143 | impl<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. |
| 151 | pub trait NumAssign: Num + NumAssignOps {} |
| 152 | impl<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. |
| 158 | pub trait NumAssignRef: NumAssign + for<'r> dynNumAssignOps<&'r Self> {} |
| 159 | impl<T> NumAssignRef for T where T: NumAssign + for<'r> dynNumAssignOps<&'r T> {} |
| 160 | |
| 161 | macro_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 | } |
| 174 | int_trait_impl!(Num for usize u8 u16 u32 u64 u128); |
| 175 | int_trait_impl!(Num for isize i8 i16 i32 i64 i128); |
| 176 | |
| 177 | impl<T: Num> Num for Wrapping<T> |
| 178 | where |
| 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(op:Wrapping) |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | #[derive (Debug)] |
| 188 | pub 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)] |
| 195 | pub struct ParseFloatError { |
| 196 | pub kind: FloatErrorKind, |
| 197 | } |
| 198 | |
| 199 | impl fmt::Display for ParseFloatError { |
| 200 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 201 | let description: &'static str = 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 | |
| 210 | fn str_to_ascii_lower_eq_str(a: &str, b: &str) -> bool { |
| 211 | a.len() == b.len() |
| 212 | && a.bytes().zip(b.bytes()).all(|(a: u8, b: u8)| { |
| 213 | let a_to_ascii_lower: u8 = 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) |
| 221 | macro_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 | } |
| 392 | float_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 ] |
| 402 | pub 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)] |
| 422 | pub 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)] |
| 440 | pub 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 ] |
| 450 | fn 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)] |
| 476 | fn clamp_nan_min() { |
| 477 | clamp(0., ::core::f32::NAN, 1.); |
| 478 | } |
| 479 | |
| 480 | #[test ] |
| 481 | #[should_panic ] |
| 482 | #[cfg (debug_assertions)] |
| 483 | fn clamp_nan_max() { |
| 484 | clamp(0., -1., ::core::f32::NAN); |
| 485 | } |
| 486 | |
| 487 | #[test ] |
| 488 | #[should_panic ] |
| 489 | #[cfg (debug_assertions)] |
| 490 | fn clamp_nan_min_max() { |
| 491 | clamp(0., ::core::f32::NAN, ::core::f32::NAN); |
| 492 | } |
| 493 | |
| 494 | #[test ] |
| 495 | #[should_panic ] |
| 496 | #[cfg (debug_assertions)] |
| 497 | fn clamp_min_nan_min() { |
| 498 | clamp_min(0., ::core::f32::NAN); |
| 499 | } |
| 500 | |
| 501 | #[test ] |
| 502 | #[should_panic ] |
| 503 | #[cfg (debug_assertions)] |
| 504 | fn clamp_max_nan_max() { |
| 505 | clamp_max(0., ::core::f32::NAN); |
| 506 | } |
| 507 | |
| 508 | #[test ] |
| 509 | fn 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 ] |
| 520 | fn 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 ] |
| 529 | fn 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 ] |
| 551 | fn 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 ] |
| 558 | fn 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 ] |
| 574 | fn 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 ] |
| 582 | fn 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 ] |
| 590 | fn 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 ] |
| 601 | fn 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 ] |
| 612 | fn 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 ] |
| 625 | fn 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 | } |
| 636 | |