[Fix] float.rs: str_to_float reimplemented
This commit is contained in:
parent
3219c40e18
commit
7faed3d87c
187
src/lib/float.rs
187
src/lib/float.rs
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* 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;
|
||||
@ -15,21 +19,180 @@ fn float_to_str(num: float, digits: uint) -> str {
|
||||
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;
|
||||
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.
|
||||
|
||||
fn dec_val(c: char) -> int { ret (c as int) - ('0' as int); }
|
||||
if len == 0u { ret 0.; }
|
||||
let total = 0f; //Accumulated result
|
||||
let c = 'z'; //Latest char.
|
||||
|
||||
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;
|
||||
//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.;
|
||||
}
|
||||
|
||||
//
|
||||
|
Loading…
x
Reference in New Issue
Block a user