1 // Copyright 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.
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.
13 macro_rules! assert_approx_eq {
14 ($a:expr, $b:expr) => ({
16 let (a, b) = (&$a, &$b);
17 assert!((*a - *b).abs() < 1.0e-6,
18 "{} is not approximately equal to {}", *a, *b);
22 macro_rules! from_str_radix_float_impl {
24 fn from_str_radix(src: &str, radix: u32)
25 -> Result<$T, ParseFloatError> {
26 use num::FloatErrorKind::*;
27 use num::ParseFloatError as PFE;
31 "inf" => return Ok(Float::infinity()),
32 "-inf" => return Ok(Float::neg_infinity()),
33 "NaN" => return Ok(Float::nan()),
37 let (is_positive, src) = match src.slice_shift_char() {
38 None => return Err(PFE { __kind: Empty }),
39 Some(('-', "")) => return Err(PFE { __kind: Empty }),
40 Some(('-', src)) => (false, src),
41 Some((_, _)) => (true, src),
44 // The significand to accumulate
45 let mut sig = if is_positive { 0.0 } else { -0.0 };
46 // Necessary to detect overflow
47 let mut prev_sig = sig;
48 let mut cs = src.chars().enumerate();
49 // Exponent prefix and exponent index offset
50 let mut exp_info = None::<(char, usize)>;
52 // Parse the integer part of the significand
53 for (i, c) in cs.by_ref() {
54 match c.to_digit(radix) {
56 // shift significand one digit left
57 sig = sig * (radix as $T);
59 // add/subtract current digit depending on sign
61 sig = sig + ((digit as isize) as $T);
63 sig = sig - ((digit as isize) as $T);
66 // Detect overflow by comparing to last value, except
67 // if we've not seen any non-zero digits.
69 if is_positive && sig <= prev_sig
70 { return Ok(Float::infinity()); }
71 if !is_positive && sig >= prev_sig
72 { return Ok(Float::neg_infinity()); }
74 // Detect overflow by reversing the shift-and-add process
75 if is_positive && (prev_sig != (sig - digit as $T) / radix as $T)
76 { return Ok(Float::infinity()); }
77 if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T)
78 { return Ok(Float::neg_infinity()); }
83 'e' | 'E' | 'p' | 'P' => {
84 exp_info = Some((c, i + 1));
85 break; // start of exponent
88 break; // start of fractional part
91 return Err(PFE { __kind: Invalid });
97 // If we are not yet at the exponent parse the fractional
98 // part of the significand
99 if exp_info.is_none() {
101 for (i, c) in cs.by_ref() {
102 match c.to_digit(radix) {
104 // Decrease power one order of magnitude
105 power = power / (radix as $T);
106 // add/subtract current digit depending on sign
107 sig = if is_positive {
108 sig + (digit as $T) * power
110 sig - (digit as $T) * power
112 // Detect overflow by comparing to last value
113 if is_positive && sig < prev_sig
114 { return Ok(Float::infinity()); }
115 if !is_positive && sig > prev_sig
116 { return Ok(Float::neg_infinity()); }
120 'e' | 'E' | 'p' | 'P' => {
121 exp_info = Some((c, i + 1));
122 break; // start of exponent
125 return Err(PFE { __kind: Invalid });
132 // Parse and calculate the exponent
133 let exp = match exp_info {
134 Some((c, offset)) => {
136 'E' | 'e' if radix == 10 => 10.0,
137 'P' | 'p' if radix == 16 => 2.0,
138 _ => return Err(PFE { __kind: Invalid }),
141 // Parse the exponent as decimal integer
142 let src = &src[offset..];
143 let (is_positive, exp) = match src.slice_shift_char() {
144 Some(('-', src)) => (false, src.parse::<usize>()),
145 Some(('+', src)) => (true, src.parse::<usize>()),
146 Some((_, _)) => (true, src.parse::<usize>()),
147 None => return Err(PFE { __kind: Invalid }),
150 match (is_positive, exp) {
151 (true, Ok(exp)) => base.powi(exp as i32),
152 (false, Ok(exp)) => 1.0 / base.powi(exp as i32),
153 (_, Err(_)) => return Err(PFE { __kind: Invalid }),
156 None => 1.0, // no exponent