+/**
+ * String conversions
+ */
+
fn float_to_str(num: float, digits: uint) -> str {
let accum = if num < 0.0 { num = -num; "-" } else { "" };
let trunc = num as uint;
ret accum;
}
+/**
+ * Convert a string to a float
+ *
+ * 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"
+ * * "", or, equivalently, "." (understood as 0)
+ * * "5."
+ * * ".5", or, equivalently, "0.5"
+ *
+ * @param num A string, possibly empty.
+ * @return [NaN] if the string did not represent a valid number.
+ * @return Otherwise, the floating-point number represented [num].
+ */
fn str_to_float(num: str) -> float {
- let digits = str::split(num, '.' as u8);
- let total = int::from_str(digits[0]) as float;
-
- fn dec_val(c: char) -> int { ret (c as int) - ('0' as int); }
-
- let right = digits[1];
- let len = str::char_len(digits[1]);
- let i = 1u;
- while (i < len) {
- total += dec_val(str::pop_char(right)) as float /
- (int::pow(10, i) as float);
- i += 1u;
- }
- ret total;
+ let pos = 0u; //Current byte position in the string.
+ //Used to walk the string in O(n).
+ let len = str::byte_len(num); //Length of the string, in bytes.
+
+ if len == 0u { ret 0.; }
+ let total = 0f; //Accumulated result
+ let c = 'z'; //Latest char.
+
+ //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
+ let neg = false; //Sign of the result
+ alt str::char_at(num, 0u) {
+ '-' {
+ neg = true;
+ pos = 1u;
+ }
+ '+' {
+ pos = 1u;
+ }
+ _ {}
+ }
+
+ //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;
+ alt c {
+ '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
+ total = total * 10f;
+ total += ((c as int) - ('0' as int)) as float;
+ }
+ _ {
+ break;
+ }
+ }
+ }
+
+ if c == '.' {//Examine decimal part
+ let decimal = 1.f;
+ while(pos < len) {
+ let char_range = str::char_range_at(num, pos);
+ c = char_range.ch;
+ pos = char_range.next;
+ alt c {
+ '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
+ decimal /= 10.f;
+ total += (((c as int) - ('0' as int)) as float)*decimal;
+ }
+ _ {
+ break;
+ }
+ }
+ }
+ }
+
+ if (c == 'e') | (c == 'E') {//Examine exponent
+ let exponent = 0u;
+ let neg_exponent = false;
+ if(pos < len) {
+ let char_range = str::char_range_at(num, pos);
+ c = char_range.ch;
+ alt 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;
+ pos = char_range.next;
+ alt c {
+ '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
+ exponent *= 10u;
+ exponent += ((c as uint) - ('0' as uint));
+ }
+ _ {
+ break;
+ }
+ }
+ }
+ let multiplier = pow_uint_to_uint_as_float(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;
+ }
+ }
+ }
+
+ if(pos < len) {
+ ret NaN();
+ } else {
+ if(neg) {
+ total *= -1f;
+ }
+ ret total;
+ }
+}
+
+/**
+ * Arithmetics
+ */
+
+/**
+ * Compute the exponentiation of an integer by another integer as a float.
+ *
+ *
+ * @param x The base.
+ * @param pow The exponent.
+ * @return [NaN] of both [x] and [pow] are [0u], otherwise [x^pow].
+ */
+fn pow_uint_to_uint_as_float(x: uint, pow: uint) -> float {
+ if x == 0u {
+ if pow == 0u {
+ ret NaN();
+ }
+ ret 0.;
+ }
+ let my_pow = pow;
+ let total = 1f;
+ let multiplier = x as float;
+ while (my_pow > 0u) {
+ if my_pow % 2u == 1u {
+ total = total * multiplier;
+ }
+ my_pow /= 2u;
+ multiplier *= multiplier;
+ }
+ ret total;
+}
+
+
+/**
+ * Constants
+ */
+
+//TODO: Once this is possible, replace the body of these functions
+//by an actual constant.
+
+fn NaN() -> float {
+ ret 0./0.;
+}
+
+fn infinity() -> float {
+ ret 1./0.;
+}
+
+fn neg_infinity() -> float {
+ ret -1./0.;
}
//