lib.rs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. use std::ops::{Add, Sub, Mul, Div, Rem};
  12. pub use bounds::Bounded;
  13. pub use float::Float;
  14. pub use identities::{Zero, One};
  15. pub use ops::checked::*;
  16. pub use ops::saturating::Saturating;
  17. pub use sign::{Signed, Unsigned};
  18. pub use int::PrimInt;
  19. pub use cast::*;
  20. pub mod identities;
  21. pub mod sign;
  22. pub mod ops;
  23. pub mod bounds;
  24. pub mod float;
  25. pub mod int;
  26. pub mod cast;
  27. /// The base trait for numeric types
  28. pub trait Num: PartialEq + Zero + One
  29. + Add<Output = Self> + Sub<Output = Self>
  30. + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
  31. {
  32. type FromStrRadixErr;
  33. /// Convert from a string and radix <= 36.
  34. fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
  35. }
  36. macro_rules! int_trait_impl {
  37. ($name:ident for $($t:ty)*) => ($(
  38. impl $name for $t {
  39. type FromStrRadixErr = ::std::num::ParseIntError;
  40. fn from_str_radix(s: &str, radix: u32)
  41. -> Result<Self, ::std::num::ParseIntError>
  42. {
  43. <$t>::from_str_radix(s, radix)
  44. }
  45. }
  46. )*)
  47. }
  48. int_trait_impl!(Num for usize u8 u16 u32 u64 isize i8 i16 i32 i64);
  49. pub enum FloatErrorKind {
  50. Empty,
  51. Invalid,
  52. }
  53. pub struct ParseFloatError {
  54. pub kind: FloatErrorKind,
  55. }
  56. macro_rules! float_trait_impl {
  57. ($name:ident for $($t:ty)*) => ($(
  58. impl $name for $t {
  59. type FromStrRadixErr = ParseFloatError;
  60. fn from_str_radix(src: &str, radix: u32)
  61. -> Result<Self, Self::FromStrRadixErr>
  62. {
  63. use self::FloatErrorKind::*;
  64. use self::ParseFloatError as PFE;
  65. // Special values
  66. match src {
  67. "inf" => return Ok(Float::infinity()),
  68. "-inf" => return Ok(Float::neg_infinity()),
  69. "NaN" => return Ok(Float::nan()),
  70. _ => {},
  71. }
  72. fn slice_shift_char(src: &str) -> Option<(char, &str)> {
  73. src.chars().nth(0).map(|ch| (ch, &src[1..]))
  74. }
  75. let (is_positive, src) = match slice_shift_char(src) {
  76. None => return Err(PFE { kind: Empty }),
  77. Some(('-', "")) => return Err(PFE { kind: Empty }),
  78. Some(('-', src)) => (false, src),
  79. Some((_, _)) => (true, src),
  80. };
  81. // The significand to accumulate
  82. let mut sig = if is_positive { 0.0 } else { -0.0 };
  83. // Necessary to detect overflow
  84. let mut prev_sig = sig;
  85. let mut cs = src.chars().enumerate();
  86. // Exponent prefix and exponent index offset
  87. let mut exp_info = None::<(char, usize)>;
  88. // Parse the integer part of the significand
  89. for (i, c) in cs.by_ref() {
  90. match c.to_digit(radix) {
  91. Some(digit) => {
  92. // shift significand one digit left
  93. sig = sig * (radix as $t);
  94. // add/subtract current digit depending on sign
  95. if is_positive {
  96. sig = sig + ((digit as isize) as $t);
  97. } else {
  98. sig = sig - ((digit as isize) as $t);
  99. }
  100. // Detect overflow by comparing to last value, except
  101. // if we've not seen any non-zero digits.
  102. if prev_sig != 0.0 {
  103. if is_positive && sig <= prev_sig
  104. { return Ok(Float::infinity()); }
  105. if !is_positive && sig >= prev_sig
  106. { return Ok(Float::neg_infinity()); }
  107. // Detect overflow by reversing the shift-and-add process
  108. if is_positive && (prev_sig != (sig - digit as $t) / radix as $t)
  109. { return Ok(Float::infinity()); }
  110. if !is_positive && (prev_sig != (sig + digit as $t) / radix as $t)
  111. { return Ok(Float::neg_infinity()); }
  112. }
  113. prev_sig = sig;
  114. },
  115. None => match c {
  116. 'e' | 'E' | 'p' | 'P' => {
  117. exp_info = Some((c, i + 1));
  118. break; // start of exponent
  119. },
  120. '.' => {
  121. break; // start of fractional part
  122. },
  123. _ => {
  124. return Err(PFE { kind: Invalid });
  125. },
  126. },
  127. }
  128. }
  129. // If we are not yet at the exponent parse the fractional
  130. // part of the significand
  131. if exp_info.is_none() {
  132. let mut power = 1.0;
  133. for (i, c) in cs.by_ref() {
  134. match c.to_digit(radix) {
  135. Some(digit) => {
  136. // Decrease power one order of magnitude
  137. power = power / (radix as $t);
  138. // add/subtract current digit depending on sign
  139. sig = if is_positive {
  140. sig + (digit as $t) * power
  141. } else {
  142. sig - (digit as $t) * power
  143. };
  144. // Detect overflow by comparing to last value
  145. if is_positive && sig < prev_sig
  146. { return Ok(Float::infinity()); }
  147. if !is_positive && sig > prev_sig
  148. { return Ok(Float::neg_infinity()); }
  149. prev_sig = sig;
  150. },
  151. None => match c {
  152. 'e' | 'E' | 'p' | 'P' => {
  153. exp_info = Some((c, i + 1));
  154. break; // start of exponent
  155. },
  156. _ => {
  157. return Err(PFE { kind: Invalid });
  158. },
  159. },
  160. }
  161. }
  162. }
  163. // Parse and calculate the exponent
  164. let exp = match exp_info {
  165. Some((c, offset)) => {
  166. let base = match c {
  167. 'E' | 'e' if radix == 10 => 10.0,
  168. 'P' | 'p' if radix == 16 => 2.0,
  169. _ => return Err(PFE { kind: Invalid }),
  170. };
  171. // Parse the exponent as decimal integer
  172. let src = &src[offset..];
  173. let (is_positive, exp) = match slice_shift_char(src) {
  174. Some(('-', src)) => (false, src.parse::<usize>()),
  175. Some(('+', src)) => (true, src.parse::<usize>()),
  176. Some((_, _)) => (true, src.parse::<usize>()),
  177. None => return Err(PFE { kind: Invalid }),
  178. };
  179. match (is_positive, exp) {
  180. (true, Ok(exp)) => base.powi(exp as i32),
  181. (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
  182. (_, Err(_)) => return Err(PFE { kind: Invalid }),
  183. }
  184. },
  185. None => 1.0, // no exponent
  186. };
  187. Ok(sig * exp)
  188. }
  189. }
  190. )*)
  191. }
  192. float_trait_impl!(Num for f32 f64);