Skip to content

Commit

Permalink
float_to_str_bytes_common can now handle exponential notation
Browse files Browse the repository at this point in the history
  • Loading branch information
SiegeLord committed Jan 23, 2014
1 parent fce7922 commit 2b4bd07
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 17 deletions.
12 changes: 6 additions & 6 deletions src/libstd/num/f32.rs
Expand Up @@ -718,7 +718,7 @@ impl Float for f32 {
#[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
}

Expand All @@ -732,7 +732,7 @@ pub fn to_str(num: f32) -> ~str {
#[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
}

Expand All @@ -748,7 +748,7 @@ pub fn to_str_hex(num: f32) -> ~str {
#[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)
}

///
Expand All @@ -763,7 +763,7 @@ pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
#[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
}

Expand All @@ -779,7 +779,7 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str {
#[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
}

Expand All @@ -804,7 +804,7 @@ 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
Expand Down
12 changes: 6 additions & 6 deletions src/libstd/num/f64.rs
Expand Up @@ -720,7 +720,7 @@ impl Float for f64 {
#[inline]
pub fn to_str(num: f64) -> ~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
}

Expand All @@ -734,7 +734,7 @@ pub fn to_str(num: f64) -> ~str {
#[inline]
pub fn to_str_hex(num: f64) -> ~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
}

Expand All @@ -750,7 +750,7 @@ pub fn to_str_hex(num: f64) -> ~str {
#[inline]
pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
strconv::float_to_str_common(num, rdx, true,
strconv::SignNeg, strconv::DigAll)
strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
}

///
Expand All @@ -765,7 +765,7 @@ pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
#[inline]
pub fn to_str_exact(num: f64, 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
}

Expand All @@ -781,7 +781,7 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str {
#[inline]
pub fn to_str_digits(num: f64, 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
}

Expand All @@ -806,7 +806,7 @@ impl num::ToStrRadix for f64 {
#[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
Expand Down
70 changes: 65 additions & 5 deletions src/libstd/num/strconv.rs
Expand Up @@ -207,11 +207,13 @@ pub fn int_to_str_bytes_common<T:NumCast
* # Arguments
* - `num` - The number to convert. Accepts any number that
* implements the numeric traits.
* - `radix` - Base to use. Accepts only the values 2-36.
* - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation
* is used, then this base is only used for the significand. The exponent
* itself always printed using a base of 10.
* - `negative_zero` - Whether to treat the special value `-0` as
* `-0` or as `+0`.
* - `sign` - How to emit the sign. Options are:
* - `SignNone`: No sign at all. Basically emits `abs(num)`.
* - `SignNone`: No sign at all. The exponent sign is also omitted.
* - `SignNeg`: Only `-` on negative values.
* - `SignAll`: Both `+` on positive, and `-` on negative numbers.
* - `digits` - The amount of digits to use for emitting the
Expand All @@ -220,6 +222,17 @@ pub fn int_to_str_bytes_common<T:NumCast
* fractions!
* - `DigMax(uint)`: Maximum N digits, truncating any trailing zeros.
* - `DigExact(uint)`: Exactly N digits.
* - `exp_format` - Whether or not to use the exponential (scientific) notation.
* Options are:
* - `ExpNone`: Do not use the exponential notation.
* - `ExpDec`: Use the exponential notation with the exponent having a base of 10,
* and exponent sign being `'e'` or `'E'` depending on the value of
* the `exp_upper` argument. E.g. the number 1000 would be printed as 1e3.
* - `ExpBin`: Use the exponential notation with the exponent having a base of 2,
* and exponent sign being `'p'` or `'P'` depending on the value of
* the `exp_upper` argument. E.g. the number 8 would be printed as 1p3.
* - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if
* exponential notation is desired.
*
* # Return value
* A tuple containing the byte vector, and a boolean flag indicating
Expand All @@ -229,12 +242,26 @@ pub fn int_to_str_bytes_common<T:NumCast
*
* # Failure
* - Fails if `radix` < 2 or `radix` > 36.
* - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
* between digit and exponent sign `'e'`.
* - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
* between digit and exponent sign `'p'`.
*/
pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
num: T, radix: uint, negative_zero: bool,
sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
) -> (~[u8], bool) {
assert!(2 <= radix && radix <= 36);
match exp_format {
ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
=> fail!("float_to_str_bytes_common: radix {} incompatible with \
use of 'e' as decimal exponent", radix),
ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
=> fail!("float_to_str_bytes_common: radix {} incompatible with \
use of 'p' as binary exponent", radix),
_ => ()
}

let _0: T = Zero::zero();
let _1: T = One::one();
Expand All @@ -260,6 +287,23 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
let mut buf: ~[u8] = ~[];
let radix_gen: T = cast(radix as int).unwrap();

let (num, exp) = match exp_format {
ExpNone => (num, 0i32),
ExpDec | ExpBin => {
if num == _0 {
(num, 0i32)
} else {
let (exp, exp_base) = match exp_format {
ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
ExpNone => unreachable!()
};

(num / exp_base.powf(&exp), cast::<T, i32>(exp).unwrap())
}
}
};

// First emit the non-fractional part, looping at least once to make
// sure at least a `0` gets emitted.
let mut deccum = num.trunc();
Expand Down Expand Up @@ -413,6 +457,21 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
}
}

match exp_format {
ExpNone => (),
_ => {
buf.push(match exp_format {
ExpDec if exp_upper => 'E',
ExpDec if !exp_upper => 'e',
ExpBin if exp_upper => 'P',
ExpBin if !exp_upper => 'p',
_ => unreachable!()
} as u8);

int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
}
}

(buf, false)
}

Expand All @@ -424,9 +483,10 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
num: T, radix: uint, negative_zero: bool,
sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
) -> (~str, bool) {
let (bytes, special) = float_to_str_bytes_common(num, radix,
negative_zero, sign, digits);
negative_zero, sign, digits, exp_format, exp_capital);
(str::from_utf8_owned(bytes).unwrap(), special)
}

Expand Down

0 comments on commit 2b4bd07

Please sign in to comment.