about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/extfmt.rs2
-rw-r--r--src/libcore/num/f32.rs194
-rw-r--r--src/libcore/num/f64.rs194
-rw-r--r--src/libcore/num/float.rs427
-rw-r--r--src/libcore/repr.rs8
-rw-r--r--src/libcore/to_str.rs12
-rw-r--r--src/libstd/json.rs4
7 files changed, 616 insertions, 225 deletions
diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs
index 4627c048015..ed0625624d8 100644
--- a/src/libcore/extfmt.rs
+++ b/src/libcore/extfmt.rs
@@ -563,7 +563,7 @@ pub mod rt {
     pub pure fn conv_float(cv: Conv, f: float) -> ~str {
         let (to_str, digits) = match cv.precision {
               CountIs(c) => (float::to_str_exact, c as uint),
-              CountImplied => (float::to_str, 6u)
+              CountImplied => (float::to_str_digits, 6u)
         };
         let mut s = unsafe { to_str(f, digits) };
         if 0.0 <= f {
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 43b68c5fc4f..a33a46192fd 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -18,6 +18,9 @@ use cmath;
 use cmp;
 use libc::{c_float, c_int};
 use num;
+use option::Option;
+use from_str;
+use to_str;
 
 pub use cmath::c_float_targ_consts::*;
 
@@ -333,6 +336,197 @@ impl f32: num::Round {
     }
 }
 
+/**
+ * Section: String Conversions
+ */
+
+/**
+ * Converts a float to a string
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ */
+#[inline(always)]
+pub pure fn to_str(num: f32) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * Converts a float to a string in hexadecimal format
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ */
+#[inline(always)]
+pub pure fn to_str_hex(num: f32) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 16u, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * Converts a float to a string in a given radix
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ * * radix - The base to use
+ */
+#[inline(always)]
+pub pure fn to_str_radix(num: f32, rdx: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, rdx, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * 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(always)]
+pub pure fn to_str_exact(num: f32, dig: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigExact(dig));
+    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(always)]
+pub pure fn to_str_digits(num: f32, dig: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigMax(dig));
+    r
+}
+
+impl f32: to_str::ToStr {
+    #[inline(always)]
+    pure fn to_str() -> ~str { to_str_digits(self, 8) }
+}
+
+impl f32: num::ToStrRadix {
+    #[inline(always)]
+    pure fn to_str_radix(&self, rdx: uint) -> ~str {
+        to_str_radix(*self, rdx)
+    }
+}
+
+/**
+ * Convert a string in base 10 to a float.
+ * Accepts a optional decimal exponent.
+ *
+ * This function accepts strings such as
+ *
+ * * '3.14'
+ * * '+3.14', equivalent to '3.14'
+ * * '-3.14'
+ * * '2.5E10', or equivalently, '2.5e10'
+ * * '2.5E-10'
+ * * '.' (understood as 0)
+ * * '5.'
+ * * '.5', or, equivalently,  '0.5'
+ * * '+inf', 'inf', '-inf', 'NaN'
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number.  Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
+ */
+#[inline(always)]
+pub pure fn from_str(num: &str) -> Option<f32> {
+    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+}
+
+/**
+ * Convert a string in base 16 to a float.
+ * Accepts a optional binary exponent.
+ *
+ * This function accepts strings such as
+ *
+ * * 'a4.fe'
+ * * '+a4.fe', equivalent to 'a4.fe'
+ * * '-a4.fe'
+ * * '2b.aP128', or equivalently, '2b.ap128'
+ * * '2b.aP-128'
+ * * '.' (understood as 0)
+ * * 'c.'
+ * * '.c', or, equivalently,  '0.c'
+ * * '+inf', 'inf', '-inf', 'NaN'
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number.  Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `[num]`.
+ */
+#[inline(always)]
+pub pure fn from_str_hex(num: &str) -> Option<f32> {
+    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+}
+
+/**
+ * Convert a string in an given base to a float.
+ *
+ * Due to possible conflicts, this function does **not** accept
+ * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ * does it recognize exponents of any kind.
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ * * radix - The base to use. Must lie in the range [2 .. 36]
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number. Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
+ */
+#[inline(always)]
+pub pure fn from_str_radix(num: &str, rdx: uint) -> Option<f32> {
+    num::from_str_common(num, rdx, true, true, false, num::ExpNone, false)
+}
+
+impl f32: from_str::FromStr {
+    #[inline(always)]
+    static pure fn from_str(val: &str) -> Option<f32> { from_str(val) }
+}
+
+impl f32: num::FromStrRadix {
+    #[inline(always)]
+    static pure fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
+        from_str_radix(val, rdx)
+    }
+}
+
 //
 // Local Variables:
 // mode: rust
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 851697012fc..276aa13da71 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -19,6 +19,9 @@ use cmp;
 use libc::{c_double, c_int};
 use libc;
 use num;
+use option::Option;
+use to_str;
+use from_str;
 
 pub use cmath::c_double_targ_consts::*;
 
@@ -357,6 +360,197 @@ impl f64: num::Round {
     }
 }
 
+/**
+ * Section: String Conversions
+ */
+
+/**
+ * Converts a float to a string
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ */
+#[inline(always)]
+pub pure fn to_str(num: f64) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * Converts a float to a string in hexadecimal format
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ */
+#[inline(always)]
+pub pure fn to_str_hex(num: f64) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 16u, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * Converts a float to a string in a given radix
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ * * radix - The base to use
+ */
+#[inline(always)]
+pub pure fn to_str_radix(num: f64, rdx: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, rdx, true, true, num::SignNeg, num::DigAll);
+    r
+}
+
+/**
+ * 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(always)]
+pub pure fn to_str_exact(num: f64, dig: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigExact(dig));
+    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(always)]
+pub pure fn to_str_digits(num: f64, dig: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigMax(dig));
+    r
+}
+
+impl f64: to_str::ToStr {
+    #[inline(always)]
+    pure fn to_str() -> ~str { to_str_digits(self, 8) }
+}
+
+impl f64: num::ToStrRadix {
+    #[inline(always)]
+    pure fn to_str_radix(&self, rdx: uint) -> ~str {
+        to_str_radix(*self, rdx)
+    }
+}
+
+/**
+ * Convert a string in base 10 to a float.
+ * Accepts a optional decimal exponent.
+ *
+ * This function accepts strings such as
+ *
+ * * '3.14'
+ * * '+3.14', equivalent to '3.14'
+ * * '-3.14'
+ * * '2.5E10', or equivalently, '2.5e10'
+ * * '2.5E-10'
+ * * '.' (understood as 0)
+ * * '5.'
+ * * '.5', or, equivalently,  '0.5'
+ * * '+inf', 'inf', '-inf', 'NaN'
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number.  Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
+ */
+#[inline(always)]
+pub pure fn from_str(num: &str) -> Option<f64> {
+    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+}
+
+/**
+ * Convert a string in base 16 to a float.
+ * Accepts a optional binary exponent.
+ *
+ * This function accepts strings such as
+ *
+ * * 'a4.fe'
+ * * '+a4.fe', equivalent to 'a4.fe'
+ * * '-a4.fe'
+ * * '2b.aP128', or equivalently, '2b.ap128'
+ * * '2b.aP-128'
+ * * '.' (understood as 0)
+ * * 'c.'
+ * * '.c', or, equivalently,  '0.c'
+ * * '+inf', 'inf', '-inf', 'NaN'
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number.  Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `[num]`.
+ */
+#[inline(always)]
+pub pure fn from_str_hex(num: &str) -> Option<f64> {
+    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+}
+
+/**
+ * Convert a string in an given base to a float.
+ *
+ * Due to possible conflicts, this function does **not** accept
+ * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ * does it recognize exponents of any kind.
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ * * radix - The base to use. Must lie in the range [2 .. 36]
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number. Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
+ */
+#[inline(always)]
+pub pure fn from_str_radix(num: &str, rdx: uint) -> Option<f64> {
+    num::from_str_common(num, rdx, true, true, false, num::ExpNone, false)
+}
+
+impl f64: from_str::FromStr {
+    #[inline(always)]
+    static pure fn from_str(val: &str) -> Option<f64> { from_str(val) }
+}
+
+impl f64: num::FromStrRadix {
+    #[inline(always)]
+    static pure fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
+        from_str_radix(val, rdx)
+    }
+}
+
 //
 // Local Variables:
 // mode: rust
diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs
index 1d1be6df87a..4f683ed14f7 100644
--- a/src/libcore/num/float.rs
+++ b/src/libcore/num/float.rs
@@ -34,6 +34,8 @@ use num::Num::from_int;
 use option::{None, Option, Some};
 use str;
 use uint;
+use to_str;
+use from_str;
 
 pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt};
 pub use f64::logarithm;
@@ -95,7 +97,7 @@ pub mod consts {
     pub const ln_10: float = 2.30258509299404568401799145468436421;
 }
 
-/**
+/*
  * Section: String Conversions
  */
 
@@ -105,85 +107,41 @@ pub mod consts {
  * # Arguments
  *
  * * num - The float value
- * * digits - The number of significant digits
- * * exact - Whether to enforce the exact number of significant digits
  */
-pub pure fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
-    if is_NaN(num) { return ~"NaN"; }
-    if num == infinity { return ~"inf"; }
-    if num == neg_infinity { return ~"-inf"; }
-
-    let mut (num, sign) = if num < 0.0 { (-num, ~"-") } else { (num, ~"") };
-
-    // truncated integer
-    let trunc = num as uint;
-
-    // decimal remainder
-    let mut frac = num - (trunc as float);
-
-    // stack of digits
-    let mut fractionalParts = ~[];
-
-    // FIXME: (#2608)
-    // This used to return right away without rounding, as "~[-]num",
-    // but given epsilon like in f64.rs, I don't see how the comparison
-    // to epsilon did much when only used there.
-    //    if (frac < epsilon && !exact) || digits == 0u { return accum; }
-    //
-    // With something better, possibly weird results like this can be avoided:
-    //     assert "3.14158999999999988262" == my_to_str_exact(3.14159, 20u);
-
-    let mut ii = digits;
-    let mut epsilon_prime = 1.0 / pow_with_uint(10u, ii);
-
-    // while we still need digits
-    // build stack of digits
-    while ii > 0 && (frac >= epsilon_prime || exact) {
-        // store the next digit
-        frac *= 10.0;
-        let digit = frac as uint;
-        // Bleh: not really unsafe.
-        unsafe { fractionalParts.push(digit); }
-
-        // calculate the next frac
-        frac -= digit as float;
-        epsilon_prime *= 10.0;
-        ii -= 1u;
-    }
-
-    let mut acc;
-    let mut racc = ~"";
-    let mut carry = if frac * 10.0 as uint >= 5 { 1 } else { 0 };
-
-    // turn digits into string
-    // using stack of digits
-    while !fractionalParts.is_empty() {
-        // Bleh; shouldn't need to be unsafe
-        let mut adjusted_digit = carry + unsafe { fractionalParts.pop() };
-
-        if adjusted_digit == 10 {
-            carry = 1;
-            adjusted_digit %= 10
-        } else {
-            carry = 0;
-        };
-
-        racc = uint::str(adjusted_digit) + racc;
-    }
+#[inline(always)]
+pub pure fn to_str(num: float) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    r
+}
 
-    // pad decimals with trailing zeroes
-    while racc.len() < digits && exact {
-        racc += ~"0"
-    }
+/**
+ * Converts a float to a string in hexadecimal format
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ */
+#[inline(always)]
+pub pure fn to_str_hex(num: float) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 16u, true, true, num::SignNeg, num::DigAll);
+    r
+}
 
-    // combine ints and decimals
-    let mut ones = uint::str(trunc + carry);
-    if racc == ~"" {
-        acc = sign + ones;
-    } else {
-        acc = sign + ones + ~"." + racc;
-    }
-    move acc
+/**
+ * Converts a float to a string in a given radix
+ *
+ * # Arguments
+ *
+ * * num - The float value
+ * * radix - The base to use
+ */
+#[inline(always)]
+pub pure fn to_str_radix(num: float, radix: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, radix, true, true, num::SignNeg, num::DigAll);
+    r
 }
 
 /**
@@ -197,7 +155,9 @@ pub pure fn to_str_common(num: float, digits: uint, exact: bool) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_exact(num: float, digits: uint) -> ~str {
-    to_str_common(num, digits, true)
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigExact(digits));
+    r
 }
 
 #[test]
@@ -206,7 +166,6 @@ pub fn test_to_str_exact_do_decimal() {
     assert s == ~"5.0000";
 }
 
-
 /**
  * Converts a float to a string with a maximum number of
  * significant digits
@@ -217,12 +176,27 @@ pub fn test_to_str_exact_do_decimal() {
  * * digits - The number of significant digits
  */
 #[inline(always)]
-pub pure fn to_str(num: float, digits: uint) -> ~str {
-    to_str_common(num, digits, false)
+pub pure fn to_str_digits(num: float, digits: uint) -> ~str {
+    let (r, _) = num::to_str_common(
+        &num, 10u, true, true, num::SignNeg, num::DigMax(digits));
+    r
+}
+
+impl float: to_str::ToStr {
+    #[inline(always)]
+    pure fn to_str() -> ~str { to_str_digits(self, 8) }
+}
+
+impl float: num::ToStrRadix {
+    #[inline(always)]
+    pure fn to_str_radix(&self, radix: uint) -> ~str {
+        to_str_radix(*self, radix)
+    }
 }
 
 /**
- * Convert a string to a float
+ * Convert a string in base 10 to a float.
+ * Accepts a optional decimal exponent.
  *
  * This function accepts strings such as
  *
@@ -231,12 +205,12 @@ pub pure fn to_str(num: float, digits: uint) -> ~str {
  * * '-3.14'
  * * '2.5E10', or equivalently, '2.5e10'
  * * '2.5E-10'
- * * '', or, equivalently, '.' (understood as 0)
+ * * '.' (understood as 0)
  * * '5.'
  * * '.5', or, equivalently,  '0.5'
- * * 'inf', '-inf', 'NaN'
+ * * '+inf', 'inf', '-inf', 'NaN'
  *
- * Leading and trailing whitespace are ignored.
+ * Leading and trailing whitespace represent an error.
  *
  * # Arguments
  *
@@ -245,125 +219,79 @@ pub pure fn to_str(num: float, digits: uint) -> ~str {
  * # Return value
  *
  * `none` if the string did not represent a valid number.  Otherwise,
- * `Some(n)` where `n` is the floating-point number represented by `[num]`.
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
  */
+#[inline(always)]
 pub pure fn from_str(num: &str) -> Option<float> {
-   if num == "inf" {
-       return Some(infinity as float);
-   } else if num == "-inf" {
-       return Some(neg_infinity as float);
-   } else if num == "NaN" {
-       return Some(NaN as float);
-   }
-
-   let mut pos = 0u;               //Current byte position in the string.
-                                   //Used to walk the string in O(n).
-   let len = str::len(num);        //Length of the string, in bytes.
-
-   if len == 0u { return None; }
-   let mut total = 0f;             //Accumulated result
-   let mut c     = 'z';            //Latest char.
-
-   //The string must start with one of the following characters.
-   match str::char_at(num, 0u) {
-      '-' | '+' | '0' .. '9' | '.' => (),
-      _ => return None
-   }
-
-   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
-   let mut neg = false;               //Sign of the result
-   match str::char_at(num, 0u) {
-      '-' => {
-          neg = true;
-          pos = 1u;
-      }
-      '+' => {
-          pos = 1u;
-      }
-      _ => ()
-   }
+    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+}
 
-   //Examine the following chars until '.', 'e', 'E'
-   while(pos < len) {
-       let char_range = str::char_range_at(num, pos);
-       c   = char_range.ch;
-       pos = char_range.next;
-       match c {
-         '0' .. '9' => {
-           total = total * 10f;
-           total += ((c as int) - ('0' as int)) as float;
-         }
-         '.' | 'e' | 'E' => break,
-         _ => return None
-       }
-   }
+/**
+ * Convert a string in base 16 to a float.
+ * Accepts a optional binary exponent.
+ *
+ * This function accepts strings such as
+ *
+ * * 'a4.fe'
+ * * '+a4.fe', equivalent to 'a4.fe'
+ * * '-a4.fe'
+ * * '2b.aP128', or equivalently, '2b.ap128'
+ * * '2b.aP-128'
+ * * '.' (understood as 0)
+ * * 'c.'
+ * * '.c', or, equivalently,  '0.c'
+ * * '+inf', 'inf', '-inf', 'NaN'
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number.  Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `[num]`.
+ */
+#[inline(always)]
+pub pure fn from_str_hex(num: &str) -> Option<float> {
+    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+}
 
-   if c == '.' {//Examine decimal part
-      let mut decimal = 1f;
-      while(pos < len) {
-         let char_range = str::char_range_at(num, pos);
-         c = char_range.ch;
-         pos = char_range.next;
-         match c {
-            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  => {
-                 decimal /= 10f;
-                 total += (((c as int) - ('0' as int)) as float)*decimal;
-             }
-             'e' | 'E' => break,
-             _ => return None
-         }
-      }
-   }
+/**
+ * Convert a string in an given base to a float.
+ *
+ * Due to possible conflicts, this function does **not** accept
+ * the special values `inf`, `-inf`, `+inf` and `NaN`, **nor**
+ * does it recognize exponents of any kind.
+ *
+ * Leading and trailing whitespace represent an error.
+ *
+ * # Arguments
+ *
+ * * num - A string
+ * * radix - The base to use. Must lie in the range [2 .. 36]
+ *
+ * # Return value
+ *
+ * `none` if the string did not represent a valid number. Otherwise,
+ * `Some(n)` where `n` is the floating-point number represented by `num`.
+ */
+#[inline(always)]
+pub pure fn from_str_radix(num: &str, radix: uint) -> Option<float> {
+    num::from_str_common(num, radix, true, true, false, num::ExpNone, false)
+}
 
-   if (c == 'e') || (c == 'E') { //Examine exponent
-      let mut exponent = 0u;
-      let mut neg_exponent = false;
-      if(pos < len) {
-          let char_range = str::char_range_at(num, pos);
-          c   = char_range.ch;
-          match c  {
-             '+' => {
-                pos = char_range.next;
-             }
-             '-' => {
-                pos = char_range.next;
-                neg_exponent = true;
-             }
-             _ => ()
-          }
-          while(pos < len) {
-             let char_range = str::char_range_at(num, pos);
-             c = char_range.ch;
-             match c {
-                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' => {
-                     exponent *= 10u;
-                     exponent += ((c as uint) - ('0' as uint));
-                 }
-                 _ => break
-             }
-             pos = char_range.next;
-          }
-          let multiplier = pow_with_uint(10u, exponent);
-              //Note: not ~[int::pow], otherwise, we'll quickly
-              //end up with a nice overflow
-          if neg_exponent {
-             total = total / multiplier;
-          } else {
-             total = total * multiplier;
-          }
-      } else {
-         return None;
-      }
-   }
+impl float: from_str::FromStr {
+    #[inline(always)]
+    static pure fn from_str(val: &str) -> Option<float> { from_str(val) }
+}
 
-   if(pos < len) {
-     return None;
-   } else {
-     if(neg) {
-        total *= -1f;
-     }
-     return Some(total);
-   }
+impl float: num::FromStrRadix {
+    #[inline(always)]
+    static pure fn from_str_radix(val: &str, radix: uint) -> Option<float> {
+        from_str_radix(val, radix)
+    }
 }
 
 /**
@@ -524,7 +452,6 @@ impl float: num::Round {
 #[test]
 pub fn test_from_str() {
    assert from_str(~"3") == Some(3.);
-   assert from_str(~"3") == Some(3.);
    assert from_str(~"3.14") == Some(3.14);
    assert from_str(~"+3.14") == Some(3.14);
    assert from_str(~"-3.14") == Some(-3.14);
@@ -537,20 +464,25 @@ pub fn test_from_str() {
    assert from_str(~"5.") == Some(5.);
    assert from_str(~".5") == Some(0.5);
    assert from_str(~"0.5") == Some(0.5);
-   assert from_str(~"0.5") == Some(0.5);
-   assert from_str(~"0.5") == Some(0.5);
-   assert from_str(~"-.5") == Some(-0.5);
    assert from_str(~"-.5") == Some(-0.5);
    assert from_str(~"-5") == Some(-5.);
-   assert from_str(~"-0") == Some(-0.);
-   assert from_str(~"0") == Some(0.);
    assert from_str(~"inf") == Some(infinity);
+   assert from_str(~"+inf") == Some(infinity);
    assert from_str(~"-inf") == Some(neg_infinity);
    // note: NaN != NaN, hence this slightly complex test
    match from_str(~"NaN") {
        Some(f) => assert is_NaN(f),
        None => die!()
    }
+   // note: -0 == 0, hence these slightly more complex tests
+   match from_str(~"-0") {
+       Some(v) if is_zero(v) => assert is_negative(v),
+       _ => fail
+   }
+   match from_str(~"0") {
+       Some(v) if is_zero(v) => assert is_positive(v),
+       _ => fail
+   }
 
    assert from_str(~"").is_none();
    assert from_str(~"x").is_none();
@@ -565,6 +497,89 @@ pub fn test_from_str() {
 }
 
 #[test]
+pub fn test_from_str_hex() {
+   assert from_str_hex(~"a4") == Some(164.);
+   assert from_str_hex(~"a4.fe") == Some(164.9921875);
+   assert from_str_hex(~"-a4.fe") == Some(-164.9921875);
+   assert from_str_hex(~"+a4.fe") == Some(164.9921875);
+   assert from_str_hex(~"ff0P4") == Some(0xff00 as float);
+   assert from_str_hex(~"ff0p4") == Some(0xff00 as float);
+   assert from_str_hex(~"ff0p-4") == Some(0xff as float);
+   assert from_str_hex(~".") == Some(0.);
+   assert from_str_hex(~".p1") == Some(0.);
+   assert from_str_hex(~".p-1") == Some(0.);
+   assert from_str_hex(~"f.") == Some(15.);
+   assert from_str_hex(~".f") == Some(0.9375);
+   assert from_str_hex(~"0.f") == Some(0.9375);
+   assert from_str_hex(~"-.f") == Some(-0.9375);
+   assert from_str_hex(~"-f") == Some(-15.);
+   assert from_str_hex(~"inf") == Some(infinity);
+   assert from_str_hex(~"+inf") == Some(infinity);
+   assert from_str_hex(~"-inf") == Some(neg_infinity);
+   // note: NaN != NaN, hence this slightly complex test
+   match from_str_hex(~"NaN") {
+       Some(f) => assert is_NaN(f),
+       None => fail
+   }
+   // note: -0 == 0, hence these slightly more complex tests
+   match from_str_hex(~"-0") {
+       Some(v) if is_zero(v) => assert is_negative(v),
+       _ => fail
+   }
+   match from_str_hex(~"0") {
+       Some(v) if is_zero(v) => assert is_positive(v),
+       _ => fail
+   }
+   assert from_str_hex(~"e") == Some(14.);
+   assert from_str_hex(~"E") == Some(14.);
+   assert from_str_hex(~"E1") == Some(225.);
+   assert from_str_hex(~"1e1e1") == Some(123361.);
+   assert from_str_hex(~"1e1.1") == Some(481.0625);
+
+   assert from_str_hex(~"").is_none();
+   assert from_str_hex(~"x").is_none();
+   assert from_str_hex(~" ").is_none();
+   assert from_str_hex(~"   ").is_none();
+   assert from_str_hex(~"p").is_none();
+   assert from_str_hex(~"P").is_none();
+   assert from_str_hex(~"P1").is_none();
+   assert from_str_hex(~"1p1p1").is_none();
+   assert from_str_hex(~"1p1.1").is_none();
+   assert from_str_hex(~"1p1-1").is_none();
+}
+
+#[test]
+pub fn test_to_str_hex() {
+   assert to_str_hex(164.) == ~"a4";
+   assert to_str_hex(164.9921875) == ~"a4.fe";
+   assert to_str_hex(-164.9921875) == ~"-a4.fe";
+   assert to_str_hex(0xff00 as float) == ~"ff00";
+   assert to_str_hex(-(0xff00 as float)) == ~"-ff00";
+   assert to_str_hex(0.) == ~"0";
+   assert to_str_hex(15.) == ~"f";
+   assert to_str_hex(-15.) == ~"-f";
+   assert to_str_hex(0.9375) == ~"0.f";
+   assert to_str_hex(-0.9375) == ~"-0.f";
+   assert to_str_hex(infinity) == ~"inf";
+   assert to_str_hex(neg_infinity) == ~"-inf";
+   assert to_str_hex(NaN) == ~"NaN";
+   assert to_str_hex(0.) == ~"0";
+   assert to_str_hex(-0.) == ~"-0";
+}
+
+#[test]
+pub fn test_to_str_radix() {
+   assert to_str_radix(36., 36u) == ~"10";
+   assert to_str_radix(8.125, 2u) == ~"1000.001";
+}
+
+#[test]
+pub fn test_from_str_radix() {
+   assert from_str_radix(~"10", 36u) == Some(36.);
+   assert from_str_radix(~"1000.001", 2u) == Some(8.125);
+}
+
+#[test]
 pub fn test_positive() {
   assert(is_positive(infinity));
   assert(is_positive(1.));
@@ -610,8 +625,8 @@ pub fn test_nonnegative() {
 
 #[test]
 pub fn test_to_str_inf() {
-    assert to_str(infinity, 10u) == ~"inf";
-    assert to_str(-infinity, 10u) == ~"-inf";
+    assert to_str_digits(infinity, 10u) == ~"inf";
+    assert to_str_digits(-infinity, 10u) == ~"-inf";
 }
 
 #[test]
diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs
index a5c3afcc87f..2f77e71bef0 100644
--- a/src/libcore/repr.rs
+++ b/src/libcore/repr.rs
@@ -893,7 +893,7 @@ fn test_repr() {
     exact_test(&10, "10");
     exact_test(&true, "true");
     exact_test(&false, "false");
-    exact_test(&1.234, "1.2340");
+    exact_test(&1.234, "1.234");
     exact_test(&(&"hello"), "\"hello\"");
     exact_test(&(@"hello"), "@\"hello\"");
     exact_test(&(~"he\u10f3llo"), "~\"he\\u10f3llo\"");
@@ -918,11 +918,11 @@ fn test_repr() {
     exact_test(&(&["hi", "there"]),
                "&[\"hi\", \"there\"]");
     exact_test(&(P{a:10, b:1.234}),
-               "{a: 10, b: 1.2340}");
+               "{a: 10, b: 1.234}");
     exact_test(&(@P{a:10, b:1.234}),
-               "@{a: 10, b: 1.2340}");
+               "@{a: 10, b: 1.234}");
     exact_test(&(~P{a:10, b:1.234}),
-               "~{a: 10, b: 1.2340}");
+               "~{a: 10, b: 1.234}");
     exact_test(&(10_u8, ~"hello"),
                "(10, ~\"hello\")");
     exact_test(&(10_u16, ~"hello"),
diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs
index 13b09590b44..51205b0c647 100644
--- a/src/libcore/to_str.rs
+++ b/src/libcore/to_str.rs
@@ -24,18 +24,6 @@ use vec;
 
 pub trait ToStr { pub pure fn to_str() -> ~str; }
 
-impl float: ToStr {
-    #[inline(always)]
-    pure fn to_str() -> ~str { ::float::to_str(self, 4u) }
-}
-impl f32: ToStr {
-    #[inline(always)]
-    pure fn to_str() -> ~str { ::float::to_str(self as float, 4u) }
-}
-impl f64: ToStr {
-    #[inline(always)]
-    pure fn to_str() -> ~str { ::float::to_str(self as float, 4u) }
-}
 impl bool: ToStr {
     #[inline(always)]
     pure fn to_str() -> ~str { ::bool::to_str(self) }
diff --git a/src/libstd/json.rs b/src/libstd/json.rs
index f0929c3dba0..b1cdeef4e66 100644
--- a/src/libstd/json.rs
+++ b/src/libstd/json.rs
@@ -109,7 +109,7 @@ pub impl Encoder: serialize::Encoder {
     fn emit_f64(&self, v: f64) { self.emit_float(v as float); }
     fn emit_f32(&self, v: f32) { self.emit_float(v as float); }
     fn emit_float(&self, v: float) {
-        self.wr.write_str(float::to_str(v, 6u));
+        self.wr.write_str(float::to_str_digits(v, 6u));
     }
 
     fn emit_char(&self, v: char) { self.emit_borrowed_str(str::from_char(v)) }
@@ -213,7 +213,7 @@ pub impl PrettyEncoder: serialize::Encoder {
     fn emit_f64(&self, v: f64) { self.emit_float(v as float); }
     fn emit_f32(&self, v: f32) { self.emit_float(v as float); }
     fn emit_float(&self, v: float) {
-        self.wr.write_str(float::to_str(v, 6u));
+        self.wr.write_str(float::to_str_digits(v, 6u));
     }
 
     fn emit_char(&self, v: char) { self.emit_borrowed_str(str::from_char(v)) }