lib.rs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. //! Numeric traits for generic mathematics
  11. #![doc(html_logo_url = "https://rust-num.github.io/num/rust-logo-128x128-blk-v2.png",
  12. html_favicon_url = "https://rust-num.github.io/num/favicon.ico",
  13. html_root_url = "https://rust-num.github.io/num/",
  14. html_playground_url = "http://play.integer32.com/")]
  15. use std::ops::{Add, Sub, Mul, Div, Rem};
  16. pub use bounds::Bounded;
  17. pub use float::{Float, FloatConst};
  18. pub use identities::{Zero, One, zero, one};
  19. pub use ops::checked::*;
  20. pub use ops::saturating::Saturating;
  21. pub use sign::{Signed, Unsigned, abs, abs_sub, signum};
  22. pub use cast::*;
  23. pub use int::PrimInt;
  24. pub use pow::{pow, checked_pow};
  25. pub mod identities;
  26. pub mod sign;
  27. pub mod ops;
  28. pub mod bounds;
  29. pub mod float;
  30. pub mod cast;
  31. pub mod int;
  32. pub mod pow;
  33. /// The base trait for numeric types
  34. pub trait Num: PartialEq + Zero + One
  35. + Add<Output = Self> + Sub<Output = Self>
  36. + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
  37. {
  38. type FromStrRadixErr;
  39. /// Convert from a string and radix <= 36.
  40. fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
  41. }
  42. macro_rules! int_trait_impl {
  43. ($name:ident for $($t:ty)*) => ($(
  44. impl $name for $t {
  45. type FromStrRadixErr = ::std::num::ParseIntError;
  46. #[inline]
  47. fn from_str_radix(s: &str, radix: u32)
  48. -> Result<Self, ::std::num::ParseIntError>
  49. {
  50. <$t>::from_str_radix(s, radix)
  51. }
  52. }
  53. )*)
  54. }
  55. int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
  56. #[derive(Debug)]
  57. pub enum FloatErrorKind {
  58. Empty,
  59. Invalid,
  60. }
  61. // FIXME: std::num::ParseFloatError is stable in 1.0, but opaque to us,
  62. // so there's not really any way for us to reuse it.
  63. #[derive(Debug)]
  64. pub struct ParseFloatError {
  65. pub kind: FloatErrorKind,
  66. }
  67. // FIXME: The standard library from_str_radix on floats was deprecated, so we're stuck
  68. // with this implementation ourselves until we want to make a breaking change.
  69. // (would have to drop it from `Num` though)
  70. macro_rules! float_trait_impl {
  71. ($name:ident for $($t:ty)*) => ($(
  72. impl $name for $t {
  73. type FromStrRadixErr = ParseFloatError;
  74. fn from_str_radix(src: &str, radix: u32)
  75. -> Result<Self, Self::FromStrRadixErr>
  76. {
  77. use self::FloatErrorKind::*;
  78. use self::ParseFloatError as PFE;
  79. // Special values
  80. match src {
  81. "inf" => return Ok(Float::infinity()),
  82. "-inf" => return Ok(Float::neg_infinity()),
  83. "NaN" => return Ok(Float::nan()),
  84. _ => {},
  85. }
  86. fn slice_shift_char(src: &str) -> Option<(char, &str)> {
  87. src.chars().nth(0).map(|ch| (ch, &src[1..]))
  88. }
  89. let (is_positive, src) = match slice_shift_char(src) {
  90. None => return Err(PFE { kind: Empty }),
  91. Some(('-', "")) => return Err(PFE { kind: Empty }),
  92. Some(('-', src)) => (false, src),
  93. Some((_, _)) => (true, src),
  94. };
  95. // The significand to accumulate
  96. let mut sig = if is_positive { 0.0 } else { -0.0 };
  97. // Necessary to detect overflow
  98. let mut prev_sig = sig;
  99. let mut cs = src.chars().enumerate();
  100. // Exponent prefix and exponent index offset
  101. let mut exp_info = None::<(char, usize)>;
  102. // Parse the integer part of the significand
  103. for (i, c) in cs.by_ref() {
  104. match c.to_digit(radix) {
  105. Some(digit) => {
  106. // shift significand one digit left
  107. sig = sig * (radix as $t);
  108. // add/subtract current digit depending on sign
  109. if is_positive {
  110. sig = sig + ((digit as isize) as $t);
  111. } else {
  112. sig = sig - ((digit as isize) as $t);
  113. }
  114. // Detect overflow by comparing to last value, except
  115. // if we've not seen any non-zero digits.
  116. if prev_sig != 0.0 {
  117. if is_positive && sig <= prev_sig
  118. { return Ok(Float::infinity()); }
  119. if !is_positive && sig >= prev_sig
  120. { return Ok(Float::neg_infinity()); }
  121. // Detect overflow by reversing the shift-and-add process
  122. if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
  123. { return Ok(Float::infinity()); }
  124. if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
  125. { return Ok(Float::neg_infinity()); }
  126. }
  127. prev_sig = sig;
  128. },
  129. None => match c {
  130. 'e' | 'E' | 'p' | 'P' => {
  131. exp_info = Some((c, i + 1));
  132. break; // start of exponent
  133. },
  134. '.' => {
  135. break; // start of fractional part
  136. },
  137. _ => {
  138. return Err(PFE { kind: Invalid });
  139. },
  140. },
  141. }
  142. }
  143. // If we are not yet at the exponent parse the fractional
  144. // part of the significand
  145. if exp_info.is_none() {
  146. let mut power = 1.0;
  147. for (i, c) in cs.by_ref() {
  148. match c.to_digit(radix) {
  149. Some(digit) => {
  150. // Decrease power one order of magnitude
  151. power = power / (radix as $t);
  152. // add/subtract current digit depending on sign
  153. sig = if is_positive {
  154. sig + (digit as $t) * power
  155. } else {
  156. sig - (digit as $t) * power
  157. };
  158. // Detect overflow by comparing to last value
  159. if is_positive && sig < prev_sig
  160. { return Ok(Float::infinity()); }
  161. if !is_positive && sig > prev_sig
  162. { return Ok(Float::neg_infinity()); }
  163. prev_sig = sig;
  164. },
  165. None => match c {
  166. 'e' | 'E' | 'p' | 'P' => {
  167. exp_info = Some((c, i + 1));
  168. break; // start of exponent
  169. },
  170. _ => {
  171. return Err(PFE { kind: Invalid });
  172. },
  173. },
  174. }
  175. }
  176. }
  177. // Parse and calculate the exponent
  178. let exp = match exp_info {
  179. Some((c, offset)) => {
  180. let base = match c {
  181. 'E' | 'e' if radix == 10 => 10.0,
  182. 'P' | 'p' if radix == 16 => 2.0,
  183. _ => return Err(PFE { kind: Invalid }),
  184. };
  185. // Parse the exponent as decimal integer
  186. let src = &src[offset..];
  187. let (is_positive, exp) = match slice_shift_char(src) {
  188. Some(('-', src)) => (false, src.parse::<usize>()),
  189. Some(('+', src)) => (true, src.parse::<usize>()),
  190. Some((_, _)) => (true, src.parse::<usize>()),
  191. None => return Err(PFE { kind: Invalid }),
  192. };
  193. match (is_positive, exp) {
  194. (true, Ok(exp)) => base.powi(exp as i32),
  195. (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
  196. (_, Err(_)) => return Err(PFE { kind: Invalid }),
  197. }
  198. },
  199. None => 1.0, // no exponent
  200. };
  201. Ok(sig * exp)
  202. }
  203. }
  204. )*)
  205. }
  206. float_trait_impl!(Num for f32 f64);
  207. #[test]
  208. fn from_str_radix_unwrap() {
  209. // The Result error must impl Debug to allow unwrap()
  210. let i: i32 = Num::from_str_radix("0", 10).unwrap();
  211. assert_eq!(i, 0);
  212. let f: f32 = Num::from_str_radix("0.0", 10).unwrap();
  213. assert_eq!(f, 0.0);
  214. }