Skip to content

Commit 1a10133

Browse files
committed
std: Bring back f32::from_str_radix as an unstable API
This API was exercised in a few tests and mirrors the `from_str_radix` functionality of the integer types.
1 parent 0791f9f commit 1a10133

35 files changed

+555
-1141
lines changed

Diff for: src/doc/trpl/traits.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ This shows off the additional feature of `where` clauses: they allow bounds
336336
where the left-hand side is an arbitrary type (`i32` in this case), not just a
337337
plain type parameter (like `T`).
338338

339-
# Default methods
339+
## Default methods
340340

341341
There’s one last feature of traits we should cover: default methods. It’s
342342
easiest just to show an example:

Diff for: src/libcollections/bit.rs

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
//! ```
4141
//! # #![feature(collections, core, step_by)]
4242
//! use std::collections::{BitSet, BitVec};
43-
//! use std::num::Float;
4443
//! use std::iter;
4544
//!
4645
//! let max_prime = 10000;

Diff for: src/libcollections/fmt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@
175175
//! # #![feature(core, std_misc)]
176176
//! use std::fmt;
177177
//! use std::f64;
178-
//! use std::num::Float;
179178
//!
180179
//! #[derive(Debug)]
181180
//! struct Vector2D {
@@ -200,10 +199,11 @@
200199
//! let magnitude = magnitude.sqrt();
201200
//!
202201
//! // Respect the formatting flags by using the helper method
203-
//! // `pad_integral` on the Formatter object. See the method documentation
204-
//! // for details, and the function `pad` can be used to pad strings.
202+
//! // `pad_integral` on the Formatter object. See the method
203+
//! // documentation for details, and the function `pad` can be used
204+
//! // to pad strings.
205205
//! let decimals = f.precision().unwrap_or(3);
206-
//! let string = f64::to_str_exact(magnitude, decimals);
206+
//! let string = format!("{:.*}", decimals, magnitude);
207207
//! f.pad_integral(true, "", &string)
208208
//! }
209209
//! }

Diff for: src/libcore/iter.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2327,9 +2327,8 @@ impl<I: RandomAccessIterator, F> RandomAccessIterator for Inspect<I, F>
23272327
/// An iterator that yields sequential Fibonacci numbers, and stops on overflow.
23282328
///
23292329
/// ```
2330-
/// # #![feature(core)]
2330+
/// #![feature(core)]
23312331
/// use std::iter::Unfold;
2332-
/// use std::num::Int; // For `.checked_add()`
23332332
///
23342333
/// // This iterator will yield up to the last Fibonacci number before the max
23352334
/// // value of `u32`. You can simply change `u32` to `u64` in this line if

Diff for: src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ mod uint_macros;
108108
#[path = "num/f32.rs"] pub mod f32;
109109
#[path = "num/f64.rs"] pub mod f64;
110110

111+
#[macro_use]
111112
pub mod num;
112113

113114
/* The libcore prelude, not as all-encompassing as the libstd prelude */

Diff for: src/libcore/num/f32.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
#![stable(feature = "rust1", since = "1.0.0")]
1818

19+
use prelude::*;
20+
1921
use intrinsics;
2022
use mem;
21-
use num::Float;
23+
use num::{Float, ParseFloatError};
2224
use num::FpCategory as Fp;
2325

2426
#[stable(feature = "rust1", since = "1.0.0")]
@@ -153,6 +155,8 @@ impl Float for f32 {
153155
#[inline]
154156
fn one() -> f32 { 1.0 }
155157

158+
from_str_radix_float_impl! { f32 }
159+
156160
/// Returns `true` if the number is NaN.
157161
#[inline]
158162
fn is_nan(self) -> bool { self != self }
@@ -234,9 +238,6 @@ impl Float for f32 {
234238
/// The fractional part of the number, satisfying:
235239
///
236240
/// ```
237-
/// # #![feature(core)]
238-
/// use std::num::Float;
239-
///
240241
/// let x = 1.65f32;
241242
/// assert!(x == x.trunc() + x.fract())
242243
/// ```

Diff for: src/libcore/num/f64.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
#![stable(feature = "rust1", since = "1.0.0")]
1818

19+
use prelude::*;
20+
1921
use intrinsics;
2022
use mem;
21-
use num::Float;
2223
use num::FpCategory as Fp;
24+
use num::{Float, ParseFloatError};
2325

2426
#[stable(feature = "rust1", since = "1.0.0")]
2527
pub const RADIX: u32 = 2;
@@ -153,6 +155,8 @@ impl Float for f64 {
153155
#[inline]
154156
fn one() -> f64 { 1.0 }
155157

158+
from_str_radix_float_impl! { f64 }
159+
156160
/// Returns `true` if the number is NaN.
157161
#[inline]
158162
fn is_nan(self) -> bool { self != self }
@@ -234,9 +238,6 @@ impl Float for f64 {
234238
/// The fractional part of the number, satisfying:
235239
///
236240
/// ```
237-
/// # #![feature(core)]
238-
/// use std::num::Float;
239-
///
240241
/// let x = 1.65f64;
241242
/// assert!(x == x.trunc() + x.fract())
242243
/// ```

Diff for: src/libcore/num/float_macros.rs

+142
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,145 @@ macro_rules! assert_approx_eq {
1818
"{} is not approximately equal to {}", *a, *b);
1919
})
2020
}
21+
22+
macro_rules! from_str_radix_float_impl {
23+
($T:ty) => {
24+
fn from_str_radix(src: &str, radix: u32)
25+
-> Result<$T, ParseFloatError> {
26+
use num::FloatErrorKind::*;
27+
use num::ParseFloatError as PFE;
28+
29+
// Special values
30+
match src {
31+
"inf" => return Ok(Float::infinity()),
32+
"-inf" => return Ok(Float::neg_infinity()),
33+
"NaN" => return Ok(Float::nan()),
34+
_ => {},
35+
}
36+
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),
42+
};
43+
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)>;
51+
52+
// Parse the integer part of the significand
53+
for (i, c) in cs.by_ref() {
54+
match c.to_digit(radix) {
55+
Some(digit) => {
56+
// shift significand one digit left
57+
sig = sig * (radix as $T);
58+
59+
// add/subtract current digit depending on sign
60+
if is_positive {
61+
sig = sig + ((digit as isize) as $T);
62+
} else {
63+
sig = sig - ((digit as isize) as $T);
64+
}
65+
66+
// Detect overflow by comparing to last value, except
67+
// if we've not seen any non-zero digits.
68+
if prev_sig != 0.0 {
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()); }
73+
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()); }
79+
}
80+
prev_sig = sig;
81+
},
82+
None => match c {
83+
'e' | 'E' | 'p' | 'P' => {
84+
exp_info = Some((c, i + 1));
85+
break; // start of exponent
86+
},
87+
'.' => {
88+
break; // start of fractional part
89+
},
90+
_ => {
91+
return Err(PFE { kind: Invalid });
92+
},
93+
},
94+
}
95+
}
96+
97+
// If we are not yet at the exponent parse the fractional
98+
// part of the significand
99+
if exp_info.is_none() {
100+
let mut power = 1.0;
101+
for (i, c) in cs.by_ref() {
102+
match c.to_digit(radix) {
103+
Some(digit) => {
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
109+
} else {
110+
sig - (digit as $T) * power
111+
};
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()); }
117+
prev_sig = sig;
118+
},
119+
None => match c {
120+
'e' | 'E' | 'p' | 'P' => {
121+
exp_info = Some((c, i + 1));
122+
break; // start of exponent
123+
},
124+
_ => {
125+
return Err(PFE { kind: Invalid });
126+
},
127+
},
128+
}
129+
}
130+
}
131+
132+
// Parse and calculate the exponent
133+
let exp = match exp_info {
134+
Some((c, offset)) => {
135+
let base = match c {
136+
'E' | 'e' if radix == 10 => 10.0,
137+
'P' | 'p' if radix == 16 => 2.0,
138+
_ => return Err(PFE { kind: Invalid }),
139+
};
140+
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 }),
148+
};
149+
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 }),
154+
}
155+
},
156+
None => 1.0, // no exponent
157+
};
158+
159+
Ok(sig * exp)
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)