Skip to content

Commit

Permalink
std: Bring back f32::from_str_radix as an unstable API
Browse files Browse the repository at this point in the history
This API was exercised in a few tests and mirrors the `from_str_radix`
functionality of the integer types.
  • Loading branch information
alexcrichton committed Apr 21, 2015
1 parent 435639c commit c1da532
Show file tree
Hide file tree
Showing 33 changed files with 574 additions and 1,159 deletions.
2 changes: 1 addition & 1 deletion src/doc/trpl/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ This shows off the additional feature of `where` clauses: they allow bounds
where the left-hand side is an arbitrary type (`i32` in this case), not just a
plain type parameter (like `T`).

# Default methods
## Default methods

There’s one last feature of traits we should cover: default methods. It’s
easiest just to show an example:
Expand Down
1 change: 0 additions & 1 deletion src/libcollections/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
//! ```
//! # #![feature(collections, core, step_by)]
//! use std::collections::{BitSet, BitVec};
//! use std::num::Float;
//! use std::iter;
//!
//! let max_prime = 10000;
Expand Down
8 changes: 4 additions & 4 deletions src/libcollections/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@
//! # #![feature(core, std_misc)]
//! use std::fmt;
//! use std::f64;
//! use std::num::Float;
//!
//! #[derive(Debug)]
//! struct Vector2D {
Expand All @@ -202,10 +201,11 @@
//! let magnitude = magnitude.sqrt();
//!
//! // Respect the formatting flags by using the helper method
//! // `pad_integral` on the Formatter object. See the method documentation
//! // for details, and the function `pad` can be used to pad strings.
//! // `pad_integral` on the Formatter object. See the method
//! // documentation for details, and the function `pad` can be used
//! // to pad strings.
//! let decimals = f.precision().unwrap_or(3);
//! let string = f64::to_str_exact(magnitude, decimals);
//! let string = format!("{:.*}", decimals, magnitude);
//! f.pad_integral(true, "", &string)
//! }
//! }
Expand Down
3 changes: 1 addition & 2 deletions src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2327,9 +2327,8 @@ impl<I: RandomAccessIterator, F> RandomAccessIterator for Inspect<I, F>
/// An iterator that yields sequential Fibonacci numbers, and stops on overflow.
///
/// ```
/// # #![feature(core)]
/// #![feature(core)]
/// use std::iter::Unfold;
/// use std::num::Int; // For `.checked_add()`
///
/// // This iterator will yield up to the last Fibonacci number before the max
/// // value of `u32`. You can simply change `u32` to `u64` in this line if
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ mod uint_macros;
#[path = "num/f32.rs"] pub mod f32;
#[path = "num/f64.rs"] pub mod f64;

#[macro_use]
pub mod num;

/* The libcore prelude, not as all-encompassing as the libstd prelude */
Expand Down
9 changes: 5 additions & 4 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@

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

use prelude::*;

use intrinsics;
use mem;
use num::Float;
use num::{Float, ParseFloatError};
use num::FpCategory as Fp;

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

from_str_radix_float_impl! { f32 }

/// Returns `true` if the number is NaN.
#[inline]
fn is_nan(self) -> bool { self != self }
Expand Down Expand Up @@ -234,9 +238,6 @@ impl Float for f32 {
/// The fractional part of the number, satisfying:
///
/// ```
/// # #![feature(core)]
/// use std::num::Float;
///
/// let x = 1.65f32;
/// assert!(x == x.trunc() + x.fract())
/// ```
Expand Down
9 changes: 5 additions & 4 deletions src/libcore/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@

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

use prelude::*;

use intrinsics;
use mem;
use num::Float;
use num::FpCategory as Fp;
use num::{Float, ParseFloatError};

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

from_str_radix_float_impl! { f64 }

/// Returns `true` if the number is NaN.
#[inline]
fn is_nan(self) -> bool { self != self }
Expand Down Expand Up @@ -234,9 +238,6 @@ impl Float for f64 {
/// The fractional part of the number, satisfying:
///
/// ```
/// # #![feature(core)]
/// use std::num::Float;
///
/// let x = 1.65f64;
/// assert!(x == x.trunc() + x.fract())
/// ```
Expand Down
142 changes: 142 additions & 0 deletions src/libcore/num/float_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,145 @@ macro_rules! assert_approx_eq {
"{} is not approximately equal to {}", *a, *b);
})
}

macro_rules! from_str_radix_float_impl {
($T:ty) => {
fn from_str_radix(src: &str, radix: u32)
-> Result<$T, ParseFloatError> {
use num::FloatErrorKind::*;
use num::ParseFloatError as PFE;

// Special values
match src {
"inf" => return Ok(Float::infinity()),
"-inf" => return Ok(Float::neg_infinity()),
"NaN" => return Ok(Float::nan()),
_ => {},
}

let (is_positive, src) = match src.slice_shift_char() {
None => return Err(PFE { kind: Empty }),
Some(('-', "")) => return Err(PFE { kind: Empty }),
Some(('-', src)) => (false, src),
Some((_, _)) => (true, src),
};

// The significand to accumulate
let mut sig = if is_positive { 0.0 } else { -0.0 };
// Necessary to detect overflow
let mut prev_sig = sig;
let mut cs = src.chars().enumerate();
// Exponent prefix and exponent index offset
let mut exp_info = None::<(char, usize)>;

// Parse the integer part of the significand
for (i, c) in cs.by_ref() {
match c.to_digit(radix) {
Some(digit) => {
// shift significand one digit left
sig = sig * (radix as $T);

// add/subtract current digit depending on sign
if is_positive {
sig = sig + ((digit as isize) as $T);
} else {
sig = sig - ((digit as isize) as $T);
}

// Detect overflow by comparing to last value, except
// if we've not seen any non-zero digits.
if prev_sig != 0.0 {
if is_positive && sig <= prev_sig
{ return Ok(Float::infinity()); }
if !is_positive && sig >= prev_sig
{ return Ok(Float::neg_infinity()); }

// Detect overflow by reversing the shift-and-add process
if is_positive && (prev_sig != (sig - digit as $T) / radix as $T)
{ return Ok(Float::infinity()); }
if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T)
{ return Ok(Float::neg_infinity()); }
}
prev_sig = sig;
},
None => match c {
'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1));
break; // start of exponent
},
'.' => {
break; // start of fractional part
},
_ => {
return Err(PFE { kind: Invalid });
},
},
}
}

// If we are not yet at the exponent parse the fractional
// part of the significand
if exp_info.is_none() {
let mut power = 1.0;
for (i, c) in cs.by_ref() {
match c.to_digit(radix) {
Some(digit) => {
// Decrease power one order of magnitude
power = power / (radix as $T);
// add/subtract current digit depending on sign
sig = if is_positive {
sig + (digit as $T) * power
} else {
sig - (digit as $T) * power
};
// Detect overflow by comparing to last value
if is_positive && sig < prev_sig
{ return Ok(Float::infinity()); }
if !is_positive && sig > prev_sig
{ return Ok(Float::neg_infinity()); }
prev_sig = sig;
},
None => match c {
'e' | 'E' | 'p' | 'P' => {
exp_info = Some((c, i + 1));
break; // start of exponent
},
_ => {
return Err(PFE { kind: Invalid });
},
},
}
}
}

// Parse and calculate the exponent
let exp = match exp_info {
Some((c, offset)) => {
let base = match c {
'E' | 'e' if radix == 10 => 10.0,
'P' | 'p' if radix == 16 => 2.0,
_ => return Err(PFE { kind: Invalid }),
};

// Parse the exponent as decimal integer
let src = &src[offset..];
let (is_positive, exp) = match src.slice_shift_char() {
Some(('-', src)) => (false, src.parse::<usize>()),
Some(('+', src)) => (true, src.parse::<usize>()),
Some((_, _)) => (true, src.parse::<usize>()),
None => return Err(PFE { kind: Invalid }),
};

match (is_positive, exp) {
(true, Ok(exp)) => base.powi(exp as i32),
(false, Ok(exp)) => 1.0 / base.powi(exp as i32),
(_, Err(_)) => return Err(PFE { kind: Invalid }),
}
},
None => 1.0, // no exponent
};

Ok(sig * exp)
}
}
}
Loading

0 comments on commit c1da532

Please # to comment.