Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the exponential notation for floats #11611

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/libstd/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ The current mapping of types to traits is:
* `p` ⇒ `Pointer`
* `t` ⇒ `Binary`
* `f` ⇒ `Float`
* `e` ⇒ `LowerExp`
* `E` ⇒ `UpperExp`
* *nothing* ⇒ `Default`

What this means is that any type of argument which implements the
Expand Down Expand Up @@ -578,6 +580,12 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `f` character
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `e` character
#[allow(missing_doc)]
pub trait LowerExp { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `E` character
#[allow(missing_doc)]
pub trait UpperExp { fn fmt(&Self, &mut Formatter); }

/// The `write` function takes an output stream, a precompiled format string,
/// and a list of arguments. The arguments will be formatted according to the
Expand Down Expand Up @@ -1085,6 +1093,28 @@ macro_rules! floating(($ty:ident) => {
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
}
}

impl LowerExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
// XXX: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false),
None => ::$ty::to_str_exp_digits(f.abs(), 6, false)
};
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
}
}

impl UpperExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
// XXX: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true),
None => ::$ty::to_str_exp_digits(f.abs(), 6, true)
};
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
}
}
})
floating!(f32)
floating!(f64)
Expand Down
78 changes: 36 additions & 42 deletions src/libstd/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,20 +285,16 @@ impl Signed for f32 {
#[inline]
fn abs(&self) -> f32 { abs(*self) }

///
/// The positive difference of two numbers. Returns `0.0` if the number is less than or
/// equal to `other`, otherwise the difference between`self` and `other` is returned.
///
#[inline]
fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) }

///
/// # Returns
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is NaN
///
#[inline]
fn signum(&self) -> f32 {
if self.is_nan() { NAN } else { copysign(1.0, *self) }
Expand Down Expand Up @@ -330,14 +326,12 @@ impl Round for f32 {
#[inline]
fn trunc(&self) -> f32 { trunc(*self) }

///
/// The fractional part of the number, satisfying:
///
/// ```rust
/// let x = 1.65f32;
/// assert!(x == x.trunc() + x.fract())
/// ```
///
#[inline]
fn fract(&self) -> f32 { *self - self.trunc() }
}
Expand Down Expand Up @@ -490,15 +484,13 @@ impl Real for f32 {
#[inline]
fn tanh(&self) -> f32 { tanh(*self) }

///
/// Inverse hyperbolic sine
///
/// # Returns
///
/// - on success, the inverse hyperbolic sine of `self` will be returned
/// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY`
/// - `NAN` if `self` is `NAN`
///
#[inline]
fn asinh(&self) -> f32 {
match *self {
Expand All @@ -507,15 +499,13 @@ impl Real for f32 {
}
}

///
/// Inverse hyperbolic cosine
///
/// # Returns
///
/// - on success, the inverse hyperbolic cosine of `self` will be returned
/// - `INFINITY` if `self` is `INFINITY`
/// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`)
///
#[inline]
fn acosh(&self) -> f32 {
match *self {
Expand All @@ -524,7 +514,6 @@ impl Real for f32 {
}
}

///
/// Inverse hyperbolic tangent
///
/// # Returns
Expand All @@ -535,7 +524,6 @@ impl Real for f32 {
/// - `NEG_INFINITY` if `self` is `-1.0`
/// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0`
/// (including `INFINITY` and `NEG_INFINITY`)
///
#[inline]
fn atanh(&self) -> f32 {
0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p()
Expand Down Expand Up @@ -643,38 +631,30 @@ impl Float for f32 {
ldexp(x, exp as c_int)
}

///
/// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
///
/// - `self = x * pow(2, exp)`
/// - `0.5 <= abs(x) < 1.0`
///
#[inline]
fn frexp(&self) -> (f32, int) {
let mut exp = 0;
let x = frexp(*self, &mut exp);
(x, exp as int)
}

///
/// Returns the exponential of the number, minus `1`, in a way that is accurate
/// even if the number is close to zero
///
#[inline]
fn exp_m1(&self) -> f32 { exp_m1(*self) }

///
/// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
/// than if the operations were performed separately
///
#[inline]
fn ln_1p(&self) -> f32 { ln_1p(*self) }

///
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
/// produces a more accurate result with better performance than a separate multiplication
/// operation followed by an add.
///
#[inline]
fn mul_add(&self, a: f32, b: f32) -> f32 {
mul_add(*self, a, b)
Expand Down Expand Up @@ -708,78 +688,98 @@ impl Float for f32 {
// Section: String Conversions
//

///
/// Converts a float to a string
///
/// # Arguments
///
/// * num - The float value
///
#[inline]
pub fn to_str(num: f32) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 10u, true, strconv::SignNeg, strconv::DigAll);
num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
r
}

///
/// Converts a float to a string in hexadecimal format
///
/// # Arguments
///
/// * num - The float value
///
#[inline]
pub fn to_str_hex(num: f32) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 16u, true, strconv::SignNeg, strconv::DigAll);
num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
r
}

///
/// Converts a float to a string in a given radix, and a flag indicating
/// whether it's a special value
///
/// # Arguments
///
/// * num - The float value
/// * radix - The base to use
///
#[inline]
pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
strconv::float_to_str_common(num, rdx, true,
strconv::SignNeg, strconv::DigAll)
strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
}

///
/// Converts a float to a string with exactly the number of
/// provided significant digits
///
/// # Arguments
///
/// * num - The float value
/// * digits - The number of significant digits
///
#[inline]
pub fn to_str_exact(num: f32, dig: uint) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false);
r
}

///
/// Converts a float to a string with a maximum number of
/// significant digits
///
/// # Arguments
///
/// * num - The float value
/// * digits - The number of significant digits
///
#[inline]
pub fn to_str_digits(num: f32, dig: uint) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false);
r
}

/// Converts a float to a string using the exponential notation with exactly the number of
/// provided digits after the decimal point in the significand
///
/// # Arguments
///
/// * num - The float value
/// * digits - The number of digits after the decimal point
/// * upper - Use `E` instead of `e` for the exponent sign
#[inline]
pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper);
r
}

/// Converts a float to a string using the exponential notation with the maximum number of
/// digits after the decimal point in the significand
///
/// # Arguments
///
/// * num - The float value
/// * digits - The number of digits after the decimal point
/// * upper - Use `E` instead of `e` for the exponent sign
#[inline]
pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> ~str {
let (r, _) = strconv::float_to_str_common(
num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
r
}

Expand All @@ -804,14 +804,13 @@ impl num::ToStrRadix for f32 {
#[inline]
fn to_str_radix(&self, rdx: uint) -> ~str {
let (r, special) = strconv::float_to_str_common(
*self, rdx, true, strconv::SignNeg, strconv::DigAll);
*self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
if special { fail!("number has a special value, \
try to_str_radix_special() if those are expected") }
r
}
}

///
/// Convert a string in base 16 to a float.
/// Accepts a optional binary exponent.
///
Expand All @@ -837,15 +836,13 @@ impl num::ToStrRadix for f32 {
///
/// `None` if the string did not represent a valid number. Otherwise,
/// `Some(n)` where `n` is the floating-point number represented by `[num]`.
///
#[inline]
pub fn from_str_hex(num: &str) -> Option<f32> {
strconv::from_str_common(num, 16u, true, true, true,
strconv::ExpBin, false, false)
}

impl FromStr for f32 {
///
/// Convert a string in base 10 to a float.
/// Accepts a optional decimal exponent.
///
Expand All @@ -871,7 +868,6 @@ impl FromStr for f32 {
///
/// `None` if the string did not represent a valid number. Otherwise,
/// `Some(n)` where `n` is the floating-point number represented by `num`.
///
#[inline]
fn from_str(val: &str) -> Option<f32> {
strconv::from_str_common(val, 10u, true, true, true,
Expand All @@ -880,7 +876,6 @@ impl FromStr for f32 {
}

impl num::FromStrRadix for f32 {
///
/// Convert a string in an given base to a float.
///
/// Due to possible conflicts, this function does **not** accept
Expand All @@ -898,7 +893,6 @@ impl num::FromStrRadix for f32 {
///
/// `None` if the string did not represent a valid number. Otherwise,
/// `Some(n)` where `n` is the floating-point number represented by `num`.
///
#[inline]
fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
strconv::from_str_common(val, rdx, true, true, false,
Expand Down
Loading