Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cdaf880

Browse files
committedApr 20, 2015
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 10a6f77 commit cdaf880

33 files changed

+575
-1235
lines changed
 

‎src/doc/trpl/traits.md

+2-77
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ it won't affect you, unless you `use` that trait.
268268
There's one more restriction on implementing traits. Either the trait or the
269269
type you're writing the `impl` for must be inside your crate. So, we could
270270
implement the `HasArea` type for `i32`, because `HasArea` is in our crate. But
271-
if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could
272-
not, because both the trait and the type aren't in our crate.
271+
if we tried to implement `Iterator`, a trait provided by Rust, for `i32`, we
272+
could not, because both the trait and the type aren't in our crate.
273273

274274
One last thing about traits: generic functions with a trait bound use
275275
*monomorphization* (*mono*: one, *morph*: form), so they are statically
@@ -389,81 +389,6 @@ This shows off the additional feature of `where` clauses: they allow bounds
389389
where the left-hand side is an arbitrary type (`i32` in this case), not just a
390390
plain type parameter (like `T`).
391391

392-
## Our `inverse` Example
393-
394-
Back in [Generics](generics.html), we were trying to write code like this:
395-
396-
```{rust,ignore}
397-
fn inverse<T>(x: T) -> Result<T, String> {
398-
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
399-
400-
Ok(1.0 / x)
401-
}
402-
```
403-
404-
If we try to compile it, we get this error:
405-
406-
```text
407-
error: binary operation `==` cannot be applied to type `T`
408-
```
409-
410-
This is because `T` is too generic: we don't know if a random `T` can be
411-
compared. For that, we can use trait bounds. It doesn't quite work, but try
412-
this:
413-
414-
```{rust,ignore}
415-
fn inverse<T: PartialEq>(x: T) -> Result<T, String> {
416-
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
417-
418-
Ok(1.0 / x)
419-
}
420-
```
421-
422-
You should get this error:
423-
424-
```text
425-
error: mismatched types:
426-
expected `T`,
427-
found `_`
428-
(expected type parameter,
429-
found floating-point variable)
430-
```
431-
432-
So this won't work. While our `T` is `PartialEq`, we expected to have another `T`,
433-
but instead, we found a floating-point variable. We need a different bound. `Float`
434-
to the rescue:
435-
436-
```
437-
# #![feature(std_misc)]
438-
use std::num::Float;
439-
440-
fn inverse<T: Float>(x: T) -> Result<T, String> {
441-
if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
442-
443-
let one: T = Float::one();
444-
Ok(one / x)
445-
}
446-
```
447-
448-
We've had to replace our generic `0.0` and `1.0` with the appropriate methods
449-
from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
450-
works just fine:
451-
452-
```
453-
# #![feature(std_misc)]
454-
# use std::num::Float;
455-
# fn inverse<T: Float>(x: T) -> Result<T, String> {
456-
# if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
457-
# let one: T = Float::one();
458-
# Ok(one / x)
459-
# }
460-
println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32));
461-
println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
462-
463-
println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
464-
println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
465-
```
466-
467392
## Default methods
468393

469394
There's one last feature of traits we should cover: default methods. It's

‎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;

‎src/libcollections/fmt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@
177177
//! # #![feature(core, std_misc)]
178178
//! use std::fmt;
179179
//! use std::f64;
180-
//! use std::num::Float;
181180
//!
182181
//! #[derive(Debug)]
183182
//! struct Vector2D {
@@ -202,10 +201,11 @@
202201
//! let magnitude = magnitude.sqrt();
203202
//!
204203
//! // Respect the formatting flags by using the helper method
205-
//! // `pad_integral` on the Formatter object. See the method documentation
206-
//! // for details, and the function `pad` can be used to pad strings.
204+
//! // `pad_integral` on the Formatter object. See the method
205+
//! // documentation for details, and the function `pad` can be used
206+
//! // to pad strings.
207207
//! let decimals = f.precision().unwrap_or(3);
208-
//! let string = f64::to_str_exact(magnitude, decimals);
208+
//! let string = format!("{:.*}", decimals, magnitude);
209209
//! f.pad_integral(true, "", &string)
210210
//! }
211211
//! }

‎src/libcore/iter.rs

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

‎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 */

‎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
/// ```

‎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
/// ```

‎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)
Please sign in to comment.