]> git.lizzy.rs Git - rust.git/commitdiff
Make Debug include the - in -0.0
authorRobin Kruppe <robin.kruppe@gmail.com>
Sun, 12 Apr 2015 16:07:15 +0000 (18:07 +0200)
committerRobin Kruppe <robin.kruppe@gmail.com>
Sun, 12 Apr 2015 21:39:03 +0000 (23:39 +0200)
src/libcore/fmt/float.rs
src/libcore/fmt/mod.rs
src/test/run-pass/ifmt.rs

index 5f19bc5be98cc95a838e0c7cdd9f42006f696164..72c25c68040222ffd48913bf88c41b5b23b18332 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,14 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![allow(missing_docs)]
-
 pub use self::ExponentFormat::*;
 pub use self::SignificantDigits::*;
-pub use self::SignFormat::*;
 
-use char;
-use char::CharExt;
+use char::{self, CharExt};
 use fmt;
 use iter::Iterator;
 use num::{cast, Float, ToPrimitive};
@@ -46,50 +42,29 @@ pub enum SignificantDigits {
     DigExact(usize)
 }
 
-/// How to emit the sign of a number.
-pub enum SignFormat {
-    /// `-` will be printed for negative values, but no sign will be emitted
-    /// for positive numbers.
-    SignNeg
-}
-
-const DIGIT_E_RADIX: u32 = ('e' as u32) - ('a' as u32) + 11;
-
-/// Converts a number to its string representation as a byte vector.
-/// This is meant to be a common base implementation for all numeric string
-/// conversion functions like `to_string()` or `to_str_radix()`.
+/// Converts a float number to its string representation.
+/// This is meant to be a common base implementation for various formatting styles.
+/// The number is assumed to be non-negative, callers use `Formatter::pad_integral`
+/// to add the right sign, if any.
 ///
 /// # Arguments
 ///
-/// - `num`           - The number to convert. Accepts any number that
+/// - `num`           - The number to convert (non-negative). Accepts any number that
 ///                     implements the numeric traits.
-/// - `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. See `SignFormat`.
 /// - `digits`        - The amount of digits to use for emitting the fractional
 ///                     part, if any. See `SignificantDigits`.
 /// - `exp_format`   - Whether or not to use the exponential (scientific) notation.
 ///                    See `ExponentFormat`.
 /// - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
 ///                     exponential notation is desired.
-/// - `f`             - A closure to invoke with the bytes representing the
+/// - `f`             - A closure to invoke with the string representing the
 ///                     float.
 ///
 /// # Panics
 ///
-/// - Panics if `radix` < 2 or `radix` > 36.
-/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
-///   between digit and exponent sign `'e'`.
-/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
-///   between digit and exponent sign `'p'`.
+/// - Panics if `num` is negative.
 pub fn float_to_str_bytes_common<T: Float, U, F>(
     num: T,
-    radix: u32,
-    negative_zero: bool,
-    sign: SignFormat,
     digits: SignificantDigits,
     exp_format: ExponentFormat,
     exp_upper: bool,
@@ -97,16 +72,12 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
 ) -> U where
     F: FnOnce(&str) -> U,
 {
-    assert!(2 <= radix && radix <= 36);
-    match exp_format {
-        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
-          => panic!("float_to_str_bytes_common: radix {} incompatible with \
-                    use of 'e' as decimal exponent", radix),
-        _ => ()
-    }
-
     let _0: T = Float::zero();
     let _1: T = Float::one();
+    let radix: u32 = 10;
+    let radix_f: T = cast(radix).unwrap();
+
+    assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative");
 
     match num.classify() {
         Fp::Nan => return f("NaN"),
@@ -119,41 +90,28 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
         _ => {}
     }
 
-    let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
-    // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so
-    // we may have up to that many digits. Give ourselves some extra wiggle room
-    // otherwise as well.
-    let mut buf = [0; 1536];
+    // For an f64 the (decimal) exponent is roughly in the range of [-307, 308], so
+    // we may have up to that many digits. We err on the side of caution and
+    // add 50% extra wiggle room.
+    let mut buf = [0; 462];
     let mut end = 0;
-    let radix_gen: T = cast(radix as isize).unwrap();
 
     let (num, exp) = match exp_format {
-        ExpNone => (num, 0),
-        ExpDec if num == _0 => (num, 0),
-        ExpDec => {
-            let (exp, exp_base) = match exp_format {
-                ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
-                ExpNone => panic!("unreachable"),
-            };
-
-            (num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
+        ExpDec if num != _0 => {
+            let exp = num.log10().floor();
+            (num / radix_f.powf(exp), cast::<T, i32>(exp).unwrap())
         }
+        _ => (num, 0)
     };
 
     // First emit the non-fractional part, looping at least once to make
     // sure at least a `0` gets emitted.
     let mut deccum = num.trunc();
     loop {
-        // Calculate the absolute value of each digit instead of only
-        // doing it once for the whole number because a
-        // representable negative number doesn't necessary have an
-        // representable additive inverse of the same type
-        // (See twos complement). But we assume that for the
-        // numbers [-35 .. 0] we always have [0 .. 35].
-        let current_digit = (deccum % radix_gen).abs();
+        let current_digit = deccum % radix_f;
 
         // Decrease the deccumulator one digit at a time
-        deccum = deccum / radix_gen;
+        deccum = deccum / radix_f;
         deccum = deccum.trunc();
 
         let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix);
@@ -170,15 +128,6 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
         DigExact(count) => (true, count + 1, true)
     };
 
-    // Decide what sign to put in front
-    match sign {
-        SignNeg if neg => {
-            buf[end] = b'-';
-            end += 1;
-        }
-        _ => ()
-    }
-
     buf[..end].reverse();
 
     // Remember start of the fractional digits.
@@ -205,14 +154,11 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
               )
         ) {
             // Shift first fractional digit into the integer part
-            deccum = deccum * radix_gen;
+            deccum = deccum * radix_f;
 
-            // Calculate the absolute value of each digit.
-            // See note in first loop.
-            let current_digit = deccum.trunc().abs();
+            let current_digit = deccum.trunc();
 
-            let c = char::from_digit(current_digit.to_isize().unwrap() as u32,
-                                     radix);
+            let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix);
             buf[end] = c.unwrap() as u8;
             end += 1;
 
@@ -301,12 +247,8 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
 
     match exp_format {
         ExpNone => {},
-        _ => {
-            buf[end] = match exp_format {
-                ExpDec if exp_upper => 'E',
-                ExpDec if !exp_upper => 'e',
-                _ => panic!("unreachable"),
-            } as u8;
+        ExpDec => {
+            buf[end] = if exp_upper { b'E' } else { b'e' };
             end += 1;
 
             struct Filler<'a> {
@@ -324,11 +266,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result {
             }
 
             let mut filler = Filler { buf: &mut buf, end: &mut end };
-            match sign {
-                SignNeg => {
-                    let _ = fmt::write(&mut filler, format_args!("{:-}", exp));
-                }
-            }
+            let _ = fmt::write(&mut filler, format_args!("{:-}", exp));
         }
     }
 
index 67781b73ae23c8b76e8941aa33dc84034a6d2182..b945e2a73e2f911f9fa006364a863ea586c35802 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -18,6 +18,7 @@
 use iter::Iterator;
 use marker::{Copy, PhantomData, Sized};
 use mem;
+use num::Float;
 use option::Option;
 use option::Option::{Some, None};
 use result::Result::Ok;
@@ -904,33 +905,38 @@ fn fmt(&self, f: &mut Formatter) -> Result {
     }
 }
 
+// Common code of floating point Debug and Display.
+fn float_to_str_common<T: Float, F>(num: &T, precision: Option<usize>, post: F) -> Result
+        where F : FnOnce(&str) -> Result {
+    let digits = match precision {
+        Some(i) => float::DigExact(i),
+        None => float::DigMax(6),
+    };
+    float::float_to_str_bytes_common(num.abs(),
+                                     digits,
+                                     float::ExpNone,
+                                     false,
+                                     post)
+}
+
 macro_rules! floating { ($ty:ident) => {
 
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Debug for $ty {
         fn fmt(&self, fmt: &mut Formatter) -> Result {
-            Display::fmt(self, fmt)
+            float_to_str_common(self, fmt.precision, |absolute| {
+                // is_positive() counts -0.0 as negative
+                fmt.pad_integral(self.is_nan() || self.is_positive(), "", absolute)
+            })
         }
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
     impl Display for $ty {
         fn fmt(&self, fmt: &mut Formatter) -> Result {
-            use num::Float;
-
-            let digits = match fmt.precision {
-                Some(i) => float::DigExact(i),
-                None => float::DigMax(6),
-            };
-            float::float_to_str_bytes_common(self.abs(),
-                                             10,
-                                             true,
-                                             float::SignNeg,
-                                             digits,
-                                             float::ExpNone,
-                                             false,
-                                             |bytes| {
-                fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes)
+            float_to_str_common(self, fmt.precision, |absolute| {
+                // simple comparison counts -0.0 as positive
+                fmt.pad_integral(self.is_nan() || *self >= 0.0, "", absolute)
             })
         }
     }
@@ -945,9 +951,6 @@ fn fmt(&self, fmt: &mut Formatter) -> Result {
                 None => float::DigMax(6),
             };
             float::float_to_str_bytes_common(self.abs(),
-                                             10,
-                                             true,
-                                             float::SignNeg,
                                              digits,
                                              float::ExpDec,
                                              false,
@@ -967,9 +970,6 @@ fn fmt(&self, fmt: &mut Formatter) -> Result {
                 None => float::DigMax(6),
             };
             float::float_to_str_bytes_common(self.abs(),
-                                             10,
-                                             true,
-                                             float::SignNeg,
                                              digits,
                                              float::ExpDec,
                                              true,
index 3a7af0976441927fe03799d32ce185bb6bd16b40..ea9db9b1e1f8d91aabb86d5628b4c727f9af657f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -144,6 +144,12 @@ pub fn main() {
     t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
     t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
 
+    // Float edge cases
+    t!(format!("{}", -0.0), "0");
+    t!(format!("{:?}", -0.0), "-0");
+    t!(format!("{:?}", 0.0), "0");
+
+
     // Test that pointers don't get truncated.
     {
         let val = usize::MAX;