about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarvin Löbel <loebel.marvin@gmail.com>2013-02-15 03:29:36 +0100
committerMarvin Löbel <loebel.marvin@gmail.com>2013-02-15 03:29:36 +0100
commitadac6cb5c61dfae79901264af4c235b66fb6267a (patch)
tree19e6f65e63412cac8656a30576f87a314611ac88
parentbf27352953dba644568118a254ac4a3c3035daa0 (diff)
downloadrust-adac6cb5c61dfae79901264af4c235b66fb6267a.tar.gz
rust-adac6cb5c61dfae79901264af4c235b66fb6267a.zip
Moved numeric string conversion functions into own module
-rw-r--r--src/libcore/num/f32.rs33
-rw-r--r--src/libcore/num/f64.rs33
-rw-r--r--src/libcore/num/float.rs33
-rw-r--r--src/libcore/num/int-template.rs25
-rw-r--r--src/libcore/num/num.rs541
-rw-r--r--src/libcore/num/strconv.rs556
-rw-r--r--src/libcore/num/uint-template.rs25
7 files changed, 642 insertions, 604 deletions
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 8350ba42591..3c5de1b703b 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -14,6 +14,7 @@ use cmath;
 use cmp;
 use libc::{c_float, c_int};
 use num::NumCast;
+use num::strconv;
 use num;
 use ops;
 use option::Option;
@@ -376,8 +377,8 @@ impl num::Round for f32 {
  */
 #[inline(always)]
 pub pure fn to_str(num: f32) -> ~str {
-    let (r, _) = num::to_str_common(
-        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -390,8 +391,8 @@ pub pure fn to_str(num: f32) -> ~str {
  */
 #[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);
+    let (r, _) = strconv::to_str_common(
+        &num, 16u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -411,8 +412,8 @@ pub pure fn to_str_hex(num: f32) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix(num: f32, rdx: uint) -> ~str {
-    let (r, special) = num::to_str_common(
-        &num, rdx, true, true, num::SignNeg, num::DigAll);
+    let (r, special) = strconv::to_str_common(
+        &num, rdx, true, true, strconv::SignNeg, strconv::DigAll);
     if special { fail!(~"number has a special value, \
                       try to_str_radix_special() if those are expected") }
     r
@@ -429,7 +430,8 @@ pub pure fn to_str_radix(num: f32, rdx: uint) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
-    num::to_str_common(&num, rdx, true, true, num::SignNeg, num::DigAll)
+    strconv::to_str_common(&num, rdx, true, true,
+                           strconv::SignNeg, strconv::DigAll)
 }
 
 /**
@@ -443,8 +445,8 @@ pub pure fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
  */
 #[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));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigExact(dig));
     r
 }
 
@@ -459,8 +461,8 @@ pub pure fn to_str_exact(num: f32, dig: uint) -> ~str {
  */
 #[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));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigMax(dig));
     r
 }
 
@@ -505,7 +507,8 @@ impl num::ToStrRadix for f32 {
  */
 #[inline(always)]
 pub pure fn from_str(num: &str) -> Option<f32> {
-    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+    strconv::from_str_common(num, 10u, true, true, true,
+                             strconv::ExpDec, false)
 }
 
 /**
@@ -537,7 +540,8 @@ pub pure fn from_str(num: &str) -> Option<f32> {
  */
 #[inline(always)]
 pub pure fn from_str_hex(num: &str) -> Option<f32> {
-    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+    strconv::from_str_common(num, 16u, true, true, true,
+                             strconv::ExpBin, false)
 }
 
 /**
@@ -561,7 +565,8 @@ pub pure fn from_str_hex(num: &str) -> Option<f32> {
  */
 #[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)
+    strconv::from_str_common(num, rdx, true, true, false,
+                             strconv::ExpNone, false)
 }
 
 impl from_str::FromStr for f32 {
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 474067a1860..0bd6e0e9d77 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -15,6 +15,7 @@ use cmp;
 use libc::{c_double, c_int};
 use libc;
 use num::NumCast;
+use num::strconv;
 use num;
 use ops;
 use option::Option;
@@ -401,8 +402,8 @@ impl num::Round for f64 {
  */
 #[inline(always)]
 pub pure fn to_str(num: f64) -> ~str {
-    let (r, _) = num::to_str_common(
-        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -415,8 +416,8 @@ pub pure fn to_str(num: f64) -> ~str {
  */
 #[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);
+    let (r, _) = strconv::to_str_common(
+        &num, 16u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -436,8 +437,8 @@ pub pure fn to_str_hex(num: f64) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix(num: f64, rdx: uint) -> ~str {
-    let (r, special) = num::to_str_common(
-        &num, rdx, true, true, num::SignNeg, num::DigAll);
+    let (r, special) = strconv::to_str_common(
+        &num, rdx, true, true, strconv::SignNeg, strconv::DigAll);
     if special { fail!(~"number has a special value, \
                       try to_str_radix_special() if those are expected") }
     r
@@ -454,7 +455,8 @@ pub pure fn to_str_radix(num: f64, rdx: uint) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
-    num::to_str_common(&num, rdx, true, true, num::SignNeg, num::DigAll)
+    strconv::to_str_common(&num, rdx, true, true,
+                           strconv::SignNeg, strconv::DigAll)
 }
 
 /**
@@ -468,8 +470,8 @@ pub pure fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
  */
 #[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));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigExact(dig));
     r
 }
 
@@ -484,8 +486,8 @@ pub pure fn to_str_exact(num: f64, dig: uint) -> ~str {
  */
 #[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));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigMax(dig));
     r
 }
 
@@ -530,7 +532,8 @@ impl num::ToStrRadix for f64 {
  */
 #[inline(always)]
 pub pure fn from_str(num: &str) -> Option<f64> {
-    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+    strconv::from_str_common(num, 10u, true, true, true,
+                             strconv::ExpDec, false)
 }
 
 /**
@@ -562,7 +565,8 @@ pub pure fn from_str(num: &str) -> Option<f64> {
  */
 #[inline(always)]
 pub pure fn from_str_hex(num: &str) -> Option<f64> {
-    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+    strconv::from_str_common(num, 16u, true, true, true,
+                             strconv::ExpBin, false)
 }
 
 /**
@@ -586,7 +590,8 @@ pub pure fn from_str_hex(num: &str) -> Option<f64> {
  */
 #[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)
+    strconv::from_str_common(num, rdx, true, true, false,
+                             strconv::ExpNone, false)
 }
 
 impl from_str::FromStr for f64 {
diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs
index 0f0b721e462..87879f6d7ad 100644
--- a/src/libcore/num/float.rs
+++ b/src/libcore/num/float.rs
@@ -26,6 +26,7 @@ use cmp::{Eq, Ord};
 use cmp;
 use f64;
 use num::NumCast;
+use num::strconv;
 use num;
 use ops;
 use option::{None, Option, Some};
@@ -107,8 +108,8 @@ pub mod consts {
  */
 #[inline(always)]
 pub pure fn to_str(num: float) -> ~str {
-    let (r, _) = num::to_str_common(
-        &num, 10u, true, true, num::SignNeg, num::DigAll);
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -121,8 +122,8 @@ pub pure fn to_str(num: float) -> ~str {
  */
 #[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);
+    let (r, _) = strconv::to_str_common(
+        &num, 16u, true, true, strconv::SignNeg, strconv::DigAll);
     r
 }
 
@@ -142,8 +143,8 @@ pub pure fn to_str_hex(num: float) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix(num: float, radix: uint) -> ~str {
-    let (r, special) = num::to_str_common(
-        &num, radix, true, true, num::SignNeg, num::DigAll);
+    let (r, special) = strconv::to_str_common(
+        &num, radix, true, true, strconv::SignNeg, strconv::DigAll);
     if special { fail!(~"number has a special value, \
                       try to_str_radix_special() if those are expected") }
     r
@@ -160,7 +161,8 @@ pub pure fn to_str_radix(num: float, radix: uint) -> ~str {
  */
 #[inline(always)]
 pub pure fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
-    num::to_str_common(&num, radix, true, true, num::SignNeg, num::DigAll)
+    strconv::to_str_common(&num, radix, true, true,
+                           strconv::SignNeg, strconv::DigAll)
 }
 
 /**
@@ -174,8 +176,8 @@ pub pure fn to_str_radix_special(num: float, radix: uint) -> (~str, bool) {
  */
 #[inline(always)]
 pub pure fn to_str_exact(num: float, digits: uint) -> ~str {
-    let (r, _) = num::to_str_common(
-        &num, 10u, true, true, num::SignNeg, num::DigExact(digits));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigExact(digits));
     r
 }
 
@@ -196,8 +198,8 @@ pub fn test_to_str_exact_do_decimal() {
  */
 #[inline(always)]
 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));
+    let (r, _) = strconv::to_str_common(
+        &num, 10u, true, true, strconv::SignNeg, strconv::DigMax(digits));
     r
 }
 
@@ -242,7 +244,8 @@ impl num::ToStrRadix for float {
  */
 #[inline(always)]
 pub pure fn from_str(num: &str) -> Option<float> {
-    num::from_str_common(num, 10u, true, true, true, num::ExpDec, false)
+    strconv::from_str_common(num, 10u, true, true, true,
+                             strconv::ExpDec, false)
 }
 
 /**
@@ -274,7 +277,8 @@ pub pure fn from_str(num: &str) -> Option<float> {
  */
 #[inline(always)]
 pub pure fn from_str_hex(num: &str) -> Option<float> {
-    num::from_str_common(num, 16u, true, true, true, num::ExpBin, false)
+    strconv::from_str_common(num, 16u, true, true, true,
+                             strconv::ExpBin, false)
 }
 
 /**
@@ -298,7 +302,8 @@ pub pure fn from_str_hex(num: &str) -> Option<float> {
  */
 #[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)
+    strconv::from_str_common(num, radix, true, true, false,
+                             strconv::ExpNone, false)
 }
 
 impl from_str::FromStr for float {
diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs
index eaaa78b84f8..df9756423ef 100644
--- a/src/libcore/num/int-template.rs
+++ b/src/libcore/num/int-template.rs
@@ -16,6 +16,7 @@ use cmp;
 use to_str::ToStr;
 use from_str::FromStr;
 use num::{ToStrRadix, FromStrRadix};
+use num::strconv;
 use num;
 use prelude::*;
 use str;
@@ -218,22 +219,22 @@ impl ops::Neg<T> for T {
 /// Parse a string as a number in base 10.
 #[inline(always)]
 pub pure fn from_str(s: &str) -> Option<T> {
-    num::from_str_common(s, 10u, true, false, false,
-                         num::ExpNone, false)
+    strconv::from_str_common(s, 10u, true, false, false,
+                         strconv::ExpNone, false)
 }
 
 /// Parse a string as a number in the given base.
 #[inline(always)]
 pub pure fn from_str_radix(s: &str, radix: uint) -> Option<T> {
-    num::from_str_common(s, radix, true, false, false,
-                         num::ExpNone, false)
+    strconv::from_str_common(s, radix, true, false, false,
+                         strconv::ExpNone, false)
 }
 
 /// Parse a byte slice as a number in the given base.
 #[inline(always)]
 pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
-    num::from_str_bytes_common(buf, radix, true, false, false,
-                               num::ExpNone, false)
+    strconv::from_str_bytes_common(buf, radix, true, false, false,
+                               strconv::ExpNone, false)
 }
 
 impl FromStr for T {
@@ -255,24 +256,24 @@ impl FromStrRadix for T {
 /// Convert to a string as a byte slice in a given base.
 #[inline(always)]
 pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
-    let (buf, _) = num::to_str_bytes_common(&n, radix, false, false,
-                                            num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, false,
+                            strconv::SignNeg, strconv::DigAll);
     f(buf)
 }
 
 /// Convert to a string in base 10.
 #[inline(always)]
 pub pure fn to_str(num: T) -> ~str {
-    let (buf, _) = num::to_str_common(&num, 10u, false, false,
-                                      num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_common(&num, 10u, false, false,
+                                      strconv::SignNeg, strconv::DigAll);
     buf
 }
 
 /// Convert to a string in a given base.
 #[inline(always)]
 pub pure fn to_str_radix(num: T, radix: uint) -> ~str {
-    let (buf, _) = num::to_str_common(&num, radix, false, false,
-                                      num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_common(&num, radix, false, false,
+                                      strconv::SignNeg, strconv::DigAll);
     buf
 }
 
diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs
index 44cd66363fb..af322e9b6c6 100644
--- a/src/libcore/num/num.rs
+++ b/src/libcore/num/num.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -17,6 +17,8 @@ use str;
 use kinds::Copy;
 use vec;
 
+pub mod strconv;
+
 pub trait IntConvertible {
     pure fn to_int(&self) -> int;
     static pure fn from_int(n: int) -> Self;
@@ -186,540 +188,3 @@ pub pure fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(
     total
 }
 
-pub enum ExponentFormat {
-    ExpNone,
-    ExpDec,
-    ExpBin
-}
-
-pub enum SignificantDigits {
-    DigAll,
-    DigMax(uint),
-    DigExact(uint)
-}
-
-pub enum SignFormat {
-    SignNone,
-    SignNeg,
-    SignAll
-}
-
-/**
- * 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_str()` or `to_str_radix()`.
- *
- * # Arguments
- * - `num`           - The number to convert. Accepts any number that
- *                     implements the numeric traits.
- * - `radix`         - Base to use. Accepts only the values 2-36.
- * - `special`       - Whether to attempt to compare to special values like
- *                     `inf` or `NaN`. Also needed to detect negative 0.
- *                     Can fail if it doesn't match `num`s type
- *                     (see safety note).
- * - `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)`.
- *     - `SignNeg`:  Only `-` on negative values.
- *     - `SignAll`:  Both `+` on positive, and `-` on negative numbers.
- * - `digits`        - The amount of digits to use for emitting the
- *                     fractional part, if any. Options are:
- *     - `DigAll`:         All calculatable digits. Beware of bignums or
- *                         fractions!
- *     - `DigMax(uint)`:   Maximum N digits, truncating any trailing zeros.
- *     - `DigExact(uint)`: Exactly N digits.
- *
- * # Return value
- * A tuple containing the byte vector, and a boolean flag indicating
- * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
- * It returns a tuple because there can be ambiguity between a special value
- * and a number representation at higher bases.
- *
- * # Failure
- * - Fails if `radix` < 2 or `radix` > 36.
- * - Fails on wrong value for `special` (see safety note).
- *
- * # Safety note
- * The function detects the special values `inf`, `-inf` and `NaN` by
- * dynamically comparing `num` to `1 / 0`, `-1 / 0` and `0 / 0`
- * (each of type T) if `special` is `true`. This will fail on integer types
- * with a 'divide by zero'. Likewise, it will fail if `num` **is** one of
- * those special values, and `special` is `false`, because then the
- * algorithm just does normal calculations on them.
- */
-pub pure fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+
-                                  Neg<T>+Modulo<T,T>+Mul<T,T>>(
-        num: &T, radix: uint, special: bool, negative_zero: bool,
-        sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
-    if radix as int <  2 {
-        fail!(fmt!("to_str_bytes_common: radix %? to low, \
-                   must lie in the range [2, 36]", radix));
-    } else if radix as int > 36 {
-        fail!(fmt!("to_str_bytes_common: radix %? to high, \
-                   must lie in the range [2, 36]", radix));
-    }
-
-    let _0: T = Zero::zero();
-    let _1: T = One::one();
-
-    if special {
-        if is_NaN(num) {
-            return (str::to_bytes("NaN"), true);
-        } else if is_infinity(num){
-            return match sign {
-                SignAll => (str::to_bytes("+inf"), true),
-                _       => (str::to_bytes("inf"), true)
-            }
-        } else if is_neg_infinity(num) {
-            return match sign {
-                SignNone => (str::to_bytes("inf"), true),
-                _        => (str::to_bytes("-inf"), true),
-            }
-        }
-    }
-
-    let neg = *num < _0 || (negative_zero && *num == _0
-                            && special && is_neg_zero(num));
-    let mut buf: ~[u8] = ~[];
-    let radix_gen: T   = cast(radix as int);
-
-    let mut deccum;
-
-    // First emit the non-fractional part, looping at least once to make
-    // sure at least a `0` gets emitted.
-    deccum = num.round(RoundToZero);
-    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_signed = deccum % radix_gen;
-        let current_digit = if current_digit_signed < _0 {
-            -current_digit_signed
-        } else {
-            current_digit_signed
-        };
-
-        // Decrease the deccumulator one digit at a time
-        deccum /= radix_gen;
-        deccum = deccum.round(RoundToZero);
-
-        unsafe { // FIXME: Pureness workaround (#4568)
-            buf.push(char::from_digit(current_digit.to_int() as uint, radix)
-                 .unwrap() as u8);
-        }
-
-        // No more digits to calculate for the non-fractional part -> break
-        if deccum == _0 { break; }
-    }
-
-    // If limited digits, calculate one digit more for rounding.
-    let (limit_digits, digit_count, exact) = match digits {
-        DigAll          => (false, 0u,      false),
-        DigMax(count)   => (true,  count+1, false),
-        DigExact(count) => (true,  count+1, true)
-    };
-
-    // Decide what sign to put in front
-    match sign {
-        SignNeg | SignAll if neg => {
-            unsafe { // FIXME: Pureness workaround (#4568)
-                buf.push('-' as u8);
-            }
-        }
-        SignAll => {
-            unsafe { // FIXME: Pureness workaround (#4568)
-                buf.push('+' as u8);
-            }
-        }
-        _ => ()
-    }
-
-    unsafe { // FIXME: Pureness workaround (#4568)
-        vec::reverse(buf);
-    }
-
-    // Remember start of the fractional digits.
-    // Points one beyond end of buf if none get generated,
-    // or at the '.' otherwise.
-    let start_fractional_digits = buf.len();
-
-    // Now emit the fractional part, if any
-    deccum = num.fract();
-    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
-        unsafe { // FIXME: Pureness workaround (#4568)
-            buf.push('.' as u8);
-        }
-        let mut dig = 0u;
-
-        // calculate new digits while
-        // - there is no limit and there are digits left
-        // - or there is a limit, it's not reached yet and
-        //   - it's exact
-        //   - or it's a maximum, and there are still digits left
-        while (!limit_digits && deccum != _0)
-           || (limit_digits && dig < digit_count && (
-                   exact
-                || (!exact && deccum != _0)
-              )
-        ) {
-            // Shift first fractional digit into the integer part
-            deccum *= radix_gen;
-
-            // Calculate the absolute value of each digit.
-            // See note in first loop.
-            let current_digit_signed = deccum.round(RoundToZero);
-            let current_digit = if current_digit_signed < _0 {
-                -current_digit_signed
-            } else {
-                current_digit_signed
-            };
-
-            unsafe { // FIXME: Pureness workaround (#4568)
-                buf.push(char::from_digit(
-                    current_digit.to_int() as uint, radix).unwrap() as u8);
-            }
-
-            // Decrease the deccumulator one fractional digit at a time
-            deccum = deccum.fract();
-            dig += 1u;
-        }
-
-        // If digits are limited, and that limit has been reached,
-        // cut off the one extra digit, and depending on its value
-        // round the remaining ones.
-        if limit_digits && dig == digit_count {
-            let ascii2value = |chr: u8| {
-                char::to_digit(chr as char, radix).unwrap() as uint
-            };
-            let value2ascii = |val: uint| {
-                char::from_digit(val, radix).unwrap() as u8
-            };
-
-            unsafe { // FIXME: Pureness workaround (#4568)
-                let extra_digit = ascii2value(buf.pop());
-                if extra_digit >= radix / 2 { // -> need to round
-                    let mut i: int = buf.len() as int - 1;
-                    loop {
-                        // If reached left end of number, have to
-                        // insert additional digit:
-                        if i < 0
-                        || buf[i] == '-' as u8
-                        || buf[i] == '+' as u8 {
-                            buf.insert((i + 1) as uint, value2ascii(1));
-                            break;
-                        }
-
-                        // Skip the '.'
-                        if buf[i] == '.' as u8 { i -= 1; loop; }
-
-                        // Either increment the digit,
-                        // or set to 0 if max and carry the 1.
-                        let current_digit = ascii2value(buf[i]);
-                        if current_digit < (radix - 1) {
-                            buf[i] = value2ascii(current_digit+1);
-                            break;
-                        } else {
-                            buf[i] = value2ascii(0);
-                            i -= 1;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // if number of digits is not exact, remove all trailing '0's up to
-    // and including the '.'
-    if !exact {
-        let buf_max_i = buf.len() - 1;
-
-        // index to truncate from
-        let mut i = buf_max_i;
-
-        // discover trailing zeros of fractional part
-        while i > start_fractional_digits && buf[i] == '0' as u8 {
-            i -= 1;
-        }
-
-        // Only attempt to truncate digits if buf has fractional digits
-        if i >= start_fractional_digits {
-            // If buf ends with '.', cut that too.
-            if buf[i] == '.' as u8 { i -= 1 }
-
-            // only resize buf if we actually remove digits
-            if i < buf_max_i {
-                buf = buf.slice(0, i + 1);
-            }
-        }
-    } // If exact and trailing '.', just cut that
-    else {
-        let max_i = buf.len() - 1;
-        if buf[max_i] == '.' as u8 {
-            buf = buf.slice(0, max_i);
-        }
-    }
-
-    (buf, false)
-}
-
-/**
- * Converts a number to its string representation. This is a wrapper for
- * `to_str_bytes_common()`, for details see there.
- */
-#[inline(always)]
-pub pure fn to_str_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+Neg<T>
-                            +Modulo<T,T>+Mul<T,T>>(
-        num: &T, radix: uint, special: bool, negative_zero: bool,
-        sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
-    let (bytes, special) = to_str_bytes_common(num, radix, special,
-                               negative_zero, sign, digits);
-    (str::from_bytes(bytes), special)
-}
-
-// Some constants for from_str_bytes_common's input validation,
-// they define minimum radix values for which the character is a valid digit.
-priv const DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
-priv const DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
-priv const DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
-
-/**
- * Parses a byte slice as a number. This is meant to
- * be a common base implementation for all numeric string conversion
- * functions like `from_str()` or `from_str_radix()`.
- *
- * # Arguments
- * - `buf`        - The byte slice to parse.
- * - `radix`      - Which base to parse the number as. Accepts 2-36.
- * - `negative`   - Whether to accept negative numbers.
- * - `fractional` - Whether to accept numbers with fractional parts.
- * - `special`    - Whether to accept special values like `inf`
- *                  and `NaN`. Can conflict with `radix`, see Failure.
- * - `exponent`   - Which exponent format to accept. Options are:
- *     - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
- *                  `-8.2`.
- *     - `ExpDec`:  Accepts numbers with a decimal exponent like `42e5` or
- *                  `8.2E-2`. The exponent string itself is always base 10.
- *                  Can conflict with `radix`, see Failure.
- *     - `ExpBin`:  Accepts numbers with a binary exponent like `42P-8` or
- *                  `FFp128`. The exponent string itself is always base 10.
- *                  Can conflict with `radix`, see Failure.
- * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
- *
- * # Return value
- * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
- * `None` otherwise, depending on the constraints set by the remaining
- * arguments.
- *
- * # Failure
- * - Fails if `radix` < 2 or `radix` > 36.
- * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
- *   between digit and exponent sign `'e'`.
- * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
- *   between digit and exponent sign `'p'`.
- * - Fails if `radix` > 18 and `special == true` due to conflict
- *   between digit and lowest first character in `inf` and `NaN`, the `'i'`.
- *
- * # Possible improvements
- * - Could accept option to allow ignoring underscores, allowing for numbers
- *   formated like `FF_AE_FF_FF`.
- */
-pub pure fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
-                                    Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>>(
-        buf: &[u8], radix: uint, negative: bool, fractional: bool,
-        special: bool, exponent: ExponentFormat, empty_zero: bool
-        ) -> Option<T> {
-    match exponent {
-        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
-          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
-                        use of 'e' as decimal exponent", radix)),
-        ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
-          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
-                        use of 'p' as binary exponent", radix)),
-        _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
-          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
-                        special values 'inf' and 'NaN'", radix)),
-        _ if radix as int < 2
-          => fail!(fmt!("from_str_bytes_common: radix %? to low, \
-                        must lie in the range [2, 36]", radix)),
-        _ if radix as int > 36
-          => fail!(fmt!("from_str_bytes_common: radix %? to high, \
-                        must lie in the range [2, 36]", radix)),
-        _ => ()
-    }
-
-    let _0: T = Zero::zero();
-    let _1: T = One::one();
-    let radix_gen: T = cast(radix as int);
-
-    let len = buf.len();
-
-    if len == 0 {
-        if empty_zero {
-            return Some(_0);
-        } else {
-            return None;
-        }
-    }
-
-    if special {
-        if buf == str::to_bytes("inf") || buf == str::to_bytes("+inf") {
-            return Some(infinity());
-        } else if buf == str::to_bytes("-inf") {
-            if negative {
-                return Some(neg_infinity());
-            } else {
-                return None;
-            }
-        } else if buf == str::to_bytes("NaN") {
-            return Some(NaN());
-        }
-    }
-
-    let (start, accum_positive) = match buf[0] {
-      '-' as u8 if !negative => return None,
-      '-' as u8 => (1u, false),
-      '+' as u8 => (1u, true),
-       _        => (0u, true)
-    };
-
-    // Initialize accumulator with signed zero for floating point parsing to
-    // work
-    let mut accum      = if accum_positive { _0 } else { -_1 * _0};
-    let mut last_accum = accum; // Necessary to detect overflow
-    let mut i          = start;
-    let mut exp_found  = false;
-
-    // Parse integer part of number
-    while i < len {
-        let c = buf[i] as char;
-
-        match char::to_digit(c, radix) {
-            Some(digit) => {
-                // shift accum one digit left
-                accum *= radix_gen;
-
-                // add/subtract current digit depending on sign
-                if accum_positive {
-                    accum += cast(digit as int);
-                } else {
-                    accum -= cast(digit as int);
-                }
-
-                // Detect overflow by comparing to last value
-                if accum_positive && accum < last_accum { return None; }
-                if !accum_positive && accum > last_accum { return None; }
-                last_accum = accum;
-            }
-            None => match c {
-                'e' | 'E' | 'p' | 'P' => {
-                    exp_found = true;
-                    break;                       // start of exponent
-                }
-                '.' if fractional => {
-                    i += 1u;                     // skip the '.'
-                    break;                       // start of fractional part
-                }
-                _ => return None                 // invalid number
-            }
-        }
-
-        i += 1u;
-    }
-
-    // Parse fractional part of number
-    // Skip if already reached start of exponent
-    if !exp_found {
-        let mut power = _1;
-
-        while i < len {
-            let c = buf[i] as char;
-
-            match char::to_digit(c, radix) {
-                Some(digit) => {
-                    // Decrease power one order of magnitude
-                    power /= radix_gen;
-
-                    let digit_t: T = cast(digit);
-
-                    // add/subtract current digit depending on sign
-                    if accum_positive {
-                        accum += digit_t * power;
-                    } else {
-                        accum -= digit_t * power;
-                    }
-
-                    // Detect overflow by comparing to last value
-                    if accum_positive && accum < last_accum { return None; }
-                    if !accum_positive && accum > last_accum { return None; }
-                    last_accum = accum;
-                }
-                None => match c {
-                    'e' | 'E' | 'p' | 'P' => {
-                        exp_found = true;
-                        break;                   // start of exponent
-                    }
-                    _ => return None             // invalid number
-                }
-            }
-
-            i += 1u;
-        }
-    }
-
-    // Special case: buf not empty, but does not contain any digit in front
-    // of the exponent sign -> number is empty string
-    if i == start {
-        if empty_zero {
-            return Some(_0);
-        } else {
-            return None;
-        }
-    }
-
-    let mut multiplier = _1;
-
-    if exp_found {
-        let c = buf[i] as char;
-        let base = match (c, exponent) {
-            ('e', ExpDec) | ('E', ExpDec) => 10u,
-            ('p', ExpBin) | ('P', ExpBin) => 2u,
-            _ => return None // char doesn't fit given exponent format
-        };
-
-        // parse remaining bytes as decimal integer,
-        // skipping the exponent char
-        let exp: Option<int> = from_str_bytes_common(
-            buf.view(i+1, len), 10, true, false, false, ExpNone, false);
-
-        match exp {
-            Some(exp_pow) => {
-                multiplier = if exp_pow < 0 {
-                    _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
-                } else {
-                    pow_with_uint::<T>(base, exp_pow.to_int() as uint)
-                }
-            }
-            None => return None // invalid exponent -> invalid number
-        }
-    }
-
-    Some(accum * multiplier)
-}
-
-/**
- * Parses a string as a number. This is a wrapper for
- * `from_str_bytes_common()`, for details see there.
- */
-#[inline(always)]
-pub pure fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
-                              Sub<T,T>+Neg<T>+Add<T,T>>(
-        buf: &str, radix: uint, negative: bool, fractional: bool,
-        special: bool, exponent: ExponentFormat, empty_zero: bool
-        ) -> Option<T> {
-    from_str_bytes_common(str::to_bytes(buf), radix, negative,
-                            fractional, special, exponent, empty_zero)
-}
diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs
new file mode 100644
index 00000000000..6aa933ffbed
--- /dev/null
+++ b/src/libcore/num/strconv.rs
@@ -0,0 +1,556 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::cmp::{Ord, Eq};
+use ops::{Add, Div, Modulo, Mul, Neg, Sub};
+use option::{None, Option, Some};
+use char;
+use str;
+use kinds::Copy;
+use vec;
+use num::*;
+
+pub enum ExponentFormat {
+    ExpNone,
+    ExpDec,
+    ExpBin
+}
+
+pub enum SignificantDigits {
+    DigAll,
+    DigMax(uint),
+    DigExact(uint)
+}
+
+pub enum SignFormat {
+    SignNone,
+    SignNeg,
+    SignAll
+}
+
+/**
+ * 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_str()` or `to_str_radix()`.
+ *
+ * # Arguments
+ * - `num`           - The number to convert. Accepts any number that
+ *                     implements the numeric traits.
+ * - `radix`         - Base to use. Accepts only the values 2-36.
+ * - `special`       - Whether to attempt to compare to special values like
+ *                     `inf` or `NaN`. Also needed to detect negative 0.
+ *                     Can fail if it doesn't match `num`s type
+ *                     (see safety note).
+ * - `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)`.
+ *     - `SignNeg`:  Only `-` on negative values.
+ *     - `SignAll`:  Both `+` on positive, and `-` on negative numbers.
+ * - `digits`        - The amount of digits to use for emitting the
+ *                     fractional part, if any. Options are:
+ *     - `DigAll`:         All calculatable digits. Beware of bignums or
+ *                         fractions!
+ *     - `DigMax(uint)`:   Maximum N digits, truncating any trailing zeros.
+ *     - `DigExact(uint)`: Exactly N digits.
+ *
+ * # Return value
+ * A tuple containing the byte vector, and a boolean flag indicating
+ * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
+ * It returns a tuple because there can be ambiguity between a special value
+ * and a number representation at higher bases.
+ *
+ * # Failure
+ * - Fails if `radix` < 2 or `radix` > 36.
+ * - Fails on wrong value for `special` (see safety note).
+ *
+ * # Safety note
+ * The function detects the special values `inf`, `-inf` and `NaN` by
+ * dynamically comparing `num` to `1 / 0`, `-1 / 0` and `0 / 0`
+ * (each of type T) if `special` is `true`. This will fail on integer types
+ * with a 'divide by zero'. Likewise, it will fail if `num` **is** one of
+ * those special values, and `special` is `false`, because then the
+ * algorithm just does normal calculations on them.
+ */
+pub pure fn to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+
+                                  Neg<T>+Modulo<T,T>+Mul<T,T>>(
+        num: &T, radix: uint, special: bool, negative_zero: bool,
+        sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
+    if radix as int <  2 {
+        fail!(fmt!("to_str_bytes_common: radix %? to low, \
+                   must lie in the range [2, 36]", radix));
+    } else if radix as int > 36 {
+        fail!(fmt!("to_str_bytes_common: radix %? to high, \
+                   must lie in the range [2, 36]", radix));
+    }
+
+    let _0: T = Zero::zero();
+    let _1: T = One::one();
+
+    if special {
+        if is_NaN(num) {
+            return (str::to_bytes("NaN"), true);
+        } else if is_infinity(num){
+            return match sign {
+                SignAll => (str::to_bytes("+inf"), true),
+                _       => (str::to_bytes("inf"), true)
+            }
+        } else if is_neg_infinity(num) {
+            return match sign {
+                SignNone => (str::to_bytes("inf"), true),
+                _        => (str::to_bytes("-inf"), true),
+            }
+        }
+    }
+
+    let neg = *num < _0 || (negative_zero && *num == _0
+                            && special && is_neg_zero(num));
+    let mut buf: ~[u8] = ~[];
+    let radix_gen: T   = cast(radix as int);
+
+    let mut deccum;
+
+    // First emit the non-fractional part, looping at least once to make
+    // sure at least a `0` gets emitted.
+    deccum = num.round(RoundToZero);
+    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_signed = deccum % radix_gen;
+        let current_digit = if current_digit_signed < _0 {
+            -current_digit_signed
+        } else {
+            current_digit_signed
+        };
+
+        // Decrease the deccumulator one digit at a time
+        deccum /= radix_gen;
+        deccum = deccum.round(RoundToZero);
+
+        unsafe { // FIXME: Pureness workaround (#4568)
+            buf.push(char::from_digit(current_digit.to_int() as uint, radix)
+                 .unwrap() as u8);
+        }
+
+        // No more digits to calculate for the non-fractional part -> break
+        if deccum == _0 { break; }
+    }
+
+    // If limited digits, calculate one digit more for rounding.
+    let (limit_digits, digit_count, exact) = match digits {
+        DigAll          => (false, 0u,      false),
+        DigMax(count)   => (true,  count+1, false),
+        DigExact(count) => (true,  count+1, true)
+    };
+
+    // Decide what sign to put in front
+    match sign {
+        SignNeg | SignAll if neg => {
+            unsafe { // FIXME: Pureness workaround (#4568)
+                buf.push('-' as u8);
+            }
+        }
+        SignAll => {
+            unsafe { // FIXME: Pureness workaround (#4568)
+                buf.push('+' as u8);
+            }
+        }
+        _ => ()
+    }
+
+    unsafe { // FIXME: Pureness workaround (#4568)
+        vec::reverse(buf);
+    }
+
+    // Remember start of the fractional digits.
+    // Points one beyond end of buf if none get generated,
+    // or at the '.' otherwise.
+    let start_fractional_digits = buf.len();
+
+    // Now emit the fractional part, if any
+    deccum = num.fract();
+    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
+        unsafe { // FIXME: Pureness workaround (#4568)
+            buf.push('.' as u8);
+        }
+        let mut dig = 0u;
+
+        // calculate new digits while
+        // - there is no limit and there are digits left
+        // - or there is a limit, it's not reached yet and
+        //   - it's exact
+        //   - or it's a maximum, and there are still digits left
+        while (!limit_digits && deccum != _0)
+           || (limit_digits && dig < digit_count && (
+                   exact
+                || (!exact && deccum != _0)
+              )
+        ) {
+            // Shift first fractional digit into the integer part
+            deccum *= radix_gen;
+
+            // Calculate the absolute value of each digit.
+            // See note in first loop.
+            let current_digit_signed = deccum.round(RoundToZero);
+            let current_digit = if current_digit_signed < _0 {
+                -current_digit_signed
+            } else {
+                current_digit_signed
+            };
+
+            unsafe { // FIXME: Pureness workaround (#4568)
+                buf.push(char::from_digit(
+                    current_digit.to_int() as uint, radix).unwrap() as u8);
+            }
+
+            // Decrease the deccumulator one fractional digit at a time
+            deccum = deccum.fract();
+            dig += 1u;
+        }
+
+        // If digits are limited, and that limit has been reached,
+        // cut off the one extra digit, and depending on its value
+        // round the remaining ones.
+        if limit_digits && dig == digit_count {
+            let ascii2value = |chr: u8| {
+                char::to_digit(chr as char, radix).unwrap() as uint
+            };
+            let value2ascii = |val: uint| {
+                char::from_digit(val, radix).unwrap() as u8
+            };
+
+            unsafe { // FIXME: Pureness workaround (#4568)
+                let extra_digit = ascii2value(buf.pop());
+                if extra_digit >= radix / 2 { // -> need to round
+                    let mut i: int = buf.len() as int - 1;
+                    loop {
+                        // If reached left end of number, have to
+                        // insert additional digit:
+                        if i < 0
+                        || buf[i] == '-' as u8
+                        || buf[i] == '+' as u8 {
+                            buf.insert((i + 1) as uint, value2ascii(1));
+                            break;
+                        }
+
+                        // Skip the '.'
+                        if buf[i] == '.' as u8 { i -= 1; loop; }
+
+                        // Either increment the digit,
+                        // or set to 0 if max and carry the 1.
+                        let current_digit = ascii2value(buf[i]);
+                        if current_digit < (radix - 1) {
+                            buf[i] = value2ascii(current_digit+1);
+                            break;
+                        } else {
+                            buf[i] = value2ascii(0);
+                            i -= 1;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // if number of digits is not exact, remove all trailing '0's up to
+    // and including the '.'
+    if !exact {
+        let buf_max_i = buf.len() - 1;
+
+        // index to truncate from
+        let mut i = buf_max_i;
+
+        // discover trailing zeros of fractional part
+        while i > start_fractional_digits && buf[i] == '0' as u8 {
+            i -= 1;
+        }
+
+        // Only attempt to truncate digits if buf has fractional digits
+        if i >= start_fractional_digits {
+            // If buf ends with '.', cut that too.
+            if buf[i] == '.' as u8 { i -= 1 }
+
+            // only resize buf if we actually remove digits
+            if i < buf_max_i {
+                buf = buf.slice(0, i + 1);
+            }
+        }
+    } // If exact and trailing '.', just cut that
+    else {
+        let max_i = buf.len() - 1;
+        if buf[max_i] == '.' as u8 {
+            buf = buf.slice(0, max_i);
+        }
+    }
+
+    (buf, false)
+}
+
+/**
+ * Converts a number to its string representation. This is a wrapper for
+ * `to_str_bytes_common()`, for details see there.
+ */
+#[inline(always)]
+pub pure fn to_str_common<T:NumCast+Zero+One+Eq+Ord+Round+Copy+Div<T,T>+Neg<T>
+                            +Modulo<T,T>+Mul<T,T>>(
+        num: &T, radix: uint, special: bool, negative_zero: bool,
+        sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
+    let (bytes, special) = to_str_bytes_common(num, radix, special,
+                               negative_zero, sign, digits);
+    (str::from_bytes(bytes), special)
+}
+
+// Some constants for from_str_bytes_common's input validation,
+// they define minimum radix values for which the character is a valid digit.
+priv const DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
+priv const DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
+priv const DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
+
+/**
+ * Parses a byte slice as a number. This is meant to
+ * be a common base implementation for all numeric string conversion
+ * functions like `from_str()` or `from_str_radix()`.
+ *
+ * # Arguments
+ * - `buf`        - The byte slice to parse.
+ * - `radix`      - Which base to parse the number as. Accepts 2-36.
+ * - `negative`   - Whether to accept negative numbers.
+ * - `fractional` - Whether to accept numbers with fractional parts.
+ * - `special`    - Whether to accept special values like `inf`
+ *                  and `NaN`. Can conflict with `radix`, see Failure.
+ * - `exponent`   - Which exponent format to accept. Options are:
+ *     - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
+ *                  `-8.2`.
+ *     - `ExpDec`:  Accepts numbers with a decimal exponent like `42e5` or
+ *                  `8.2E-2`. The exponent string itself is always base 10.
+ *                  Can conflict with `radix`, see Failure.
+ *     - `ExpBin`:  Accepts numbers with a binary exponent like `42P-8` or
+ *                  `FFp128`. The exponent string itself is always base 10.
+ *                  Can conflict with `radix`, see Failure.
+ * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
+ *
+ * # Return value
+ * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
+ * `None` otherwise, depending on the constraints set by the remaining
+ * arguments.
+ *
+ * # Failure
+ * - Fails if `radix` < 2 or `radix` > 36.
+ * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
+ *   between digit and exponent sign `'e'`.
+ * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
+ *   between digit and exponent sign `'p'`.
+ * - Fails if `radix` > 18 and `special == true` due to conflict
+ *   between digit and lowest first character in `inf` and `NaN`, the `'i'`.
+ *
+ * # Possible improvements
+ * - Could accept option to allow ignoring underscores, allowing for numbers
+ *   formated like `FF_AE_FF_FF`.
+ */
+pub pure fn from_str_bytes_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+
+                                    Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>>(
+        buf: &[u8], radix: uint, negative: bool, fractional: bool,
+        special: bool, exponent: ExponentFormat, empty_zero: bool
+        ) -> Option<T> {
+    match exponent {
+        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
+          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
+                        use of 'e' as decimal exponent", radix)),
+        ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
+          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
+                        use of 'p' as binary exponent", radix)),
+        _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
+          => fail!(fmt!("from_str_bytes_common: radix %? incompatible with \
+                        special values 'inf' and 'NaN'", radix)),
+        _ if radix as int < 2
+          => fail!(fmt!("from_str_bytes_common: radix %? to low, \
+                        must lie in the range [2, 36]", radix)),
+        _ if radix as int > 36
+          => fail!(fmt!("from_str_bytes_common: radix %? to high, \
+                        must lie in the range [2, 36]", radix)),
+        _ => ()
+    }
+
+    let _0: T = Zero::zero();
+    let _1: T = One::one();
+    let radix_gen: T = cast(radix as int);
+
+    let len = buf.len();
+
+    if len == 0 {
+        if empty_zero {
+            return Some(_0);
+        } else {
+            return None;
+        }
+    }
+
+    if special {
+        if buf == str::to_bytes("inf") || buf == str::to_bytes("+inf") {
+            return Some(infinity());
+        } else if buf == str::to_bytes("-inf") {
+            if negative {
+                return Some(neg_infinity());
+            } else {
+                return None;
+            }
+        } else if buf == str::to_bytes("NaN") {
+            return Some(NaN());
+        }
+    }
+
+    let (start, accum_positive) = match buf[0] {
+      '-' as u8 if !negative => return None,
+      '-' as u8 => (1u, false),
+      '+' as u8 => (1u, true),
+       _        => (0u, true)
+    };
+
+    // Initialize accumulator with signed zero for floating point parsing to
+    // work
+    let mut accum      = if accum_positive { _0 } else { -_1 * _0};
+    let mut last_accum = accum; // Necessary to detect overflow
+    let mut i          = start;
+    let mut exp_found  = false;
+
+    // Parse integer part of number
+    while i < len {
+        let c = buf[i] as char;
+
+        match char::to_digit(c, radix) {
+            Some(digit) => {
+                // shift accum one digit left
+                accum *= radix_gen;
+
+                // add/subtract current digit depending on sign
+                if accum_positive {
+                    accum += cast(digit as int);
+                } else {
+                    accum -= cast(digit as int);
+                }
+
+                // Detect overflow by comparing to last value
+                if accum_positive && accum < last_accum { return None; }
+                if !accum_positive && accum > last_accum { return None; }
+                last_accum = accum;
+            }
+            None => match c {
+                'e' | 'E' | 'p' | 'P' => {
+                    exp_found = true;
+                    break;                       // start of exponent
+                }
+                '.' if fractional => {
+                    i += 1u;                     // skip the '.'
+                    break;                       // start of fractional part
+                }
+                _ => return None                 // invalid number
+            }
+        }
+
+        i += 1u;
+    }
+
+    // Parse fractional part of number
+    // Skip if already reached start of exponent
+    if !exp_found {
+        let mut power = _1;
+
+        while i < len {
+            let c = buf[i] as char;
+
+            match char::to_digit(c, radix) {
+                Some(digit) => {
+                    // Decrease power one order of magnitude
+                    power /= radix_gen;
+
+                    let digit_t: T = cast(digit);
+
+                    // add/subtract current digit depending on sign
+                    if accum_positive {
+                        accum += digit_t * power;
+                    } else {
+                        accum -= digit_t * power;
+                    }
+
+                    // Detect overflow by comparing to last value
+                    if accum_positive && accum < last_accum { return None; }
+                    if !accum_positive && accum > last_accum { return None; }
+                    last_accum = accum;
+                }
+                None => match c {
+                    'e' | 'E' | 'p' | 'P' => {
+                        exp_found = true;
+                        break;                   // start of exponent
+                    }
+                    _ => return None             // invalid number
+                }
+            }
+
+            i += 1u;
+        }
+    }
+
+    // Special case: buf not empty, but does not contain any digit in front
+    // of the exponent sign -> number is empty string
+    if i == start {
+        if empty_zero {
+            return Some(_0);
+        } else {
+            return None;
+        }
+    }
+
+    let mut multiplier = _1;
+
+    if exp_found {
+        let c = buf[i] as char;
+        let base = match (c, exponent) {
+            ('e', ExpDec) | ('E', ExpDec) => 10u,
+            ('p', ExpBin) | ('P', ExpBin) => 2u,
+            _ => return None // char doesn't fit given exponent format
+        };
+
+        // parse remaining bytes as decimal integer,
+        // skipping the exponent char
+        let exp: Option<int> = from_str_bytes_common(
+            buf.view(i+1, len), 10, true, false, false, ExpNone, false);
+
+        match exp {
+            Some(exp_pow) => {
+                multiplier = if exp_pow < 0 {
+                    _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
+                } else {
+                    pow_with_uint::<T>(base, exp_pow.to_int() as uint)
+                }
+            }
+            None => return None // invalid exponent -> invalid number
+        }
+    }
+
+    Some(accum * multiplier)
+}
+
+/**
+ * Parses a string as a number. This is a wrapper for
+ * `from_str_bytes_common()`, for details see there.
+ */
+#[inline(always)]
+pub pure fn from_str_common<T:NumCast+Zero+One+Ord+Copy+Div<T,T>+Mul<T,T>+
+                              Sub<T,T>+Neg<T>+Add<T,T>>(
+        buf: &str, radix: uint, negative: bool, fractional: bool,
+        special: bool, exponent: ExponentFormat, empty_zero: bool
+        ) -> Option<T> {
+    from_str_bytes_common(str::to_bytes(buf), radix, negative,
+                            fractional, special, exponent, empty_zero)
+}
diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs
index b1ef3f11fa4..9829bf9d9e0 100644
--- a/src/libcore/num/uint-template.rs
+++ b/src/libcore/num/uint-template.rs
@@ -17,6 +17,7 @@ use cmp;
 use to_str::ToStr;
 use from_str::FromStr;
 use num::{ToStrRadix, FromStrRadix};
+use num::strconv;
 use num;
 use option::{None, Option, Some};
 use prelude::*;
@@ -182,22 +183,22 @@ impl ops::Neg<T> for T {
 /// Parse a string as a number in base 10.
 #[inline(always)]
 pub pure fn from_str(s: &str) -> Option<T> {
-    num::from_str_common(s, 10u, false, false, false,
-                         num::ExpNone, false)
+    strconv::from_str_common(s, 10u, false, false, false,
+                             strconv::ExpNone, false)
 }
 
 /// Parse a string as a number in the given base.
 #[inline(always)]
 pub pure fn from_str_radix(s: &str, radix: uint) -> Option<T> {
-    num::from_str_common(s, radix, false, false, false,
-                         num::ExpNone, false)
+    strconv::from_str_common(s, radix, false, false, false,
+                             strconv::ExpNone, false)
 }
 
 /// Parse a byte slice as a number in the given base.
 #[inline(always)]
 pub pure fn parse_bytes(buf: &[u8], radix: uint) -> Option<T> {
-    num::from_str_bytes_common(buf, radix, false, false, false,
-                               num::ExpNone, false)
+    strconv::from_str_bytes_common(buf, radix, false, false, false,
+                                   strconv::ExpNone, false)
 }
 
 impl FromStr for T {
@@ -219,24 +220,24 @@ impl FromStrRadix for T {
 /// Convert to a string as a byte slice in a given base.
 #[inline(always)]
 pub pure fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
-    let (buf, _) = num::to_str_bytes_common(&n, radix, false, false,
-                                            num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_bytes_common(&n, radix, false, false,
+                            strconv::SignNeg, strconv::DigAll);
     f(buf)
 }
 
 /// Convert to a string in base 10.
 #[inline(always)]
 pub pure fn to_str(num: T) -> ~str {
-    let (buf, _) = num::to_str_common(&num, 10u, false, false,
-                                      num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_common(&num, 10u, false, false,
+                            strconv::SignNeg, strconv::DigAll);
     buf
 }
 
 /// Convert to a string in a given base.
 #[inline(always)]
 pub pure fn to_str_radix(num: T, radix: uint) -> ~str {
-    let (buf, _) = num::to_str_common(&num, radix, false, false,
-                                      num::SignNeg, num::DigAll);
+    let (buf, _) = strconv::to_str_common(&num, radix, false, false,
+                            strconv::SignNeg, strconv::DigAll);
     buf
 }