/* Module: float */ // FIXME find out why these have to be exported explicitly export to_str_common, to_str_exact, to_str, from_str; export add, sub, mul, div, rem, lt, le, gt, eq, eq, ne; export is_positive, is_negative, is_nonpositive, is_nonnegative; export is_zero, is_infinite, is_finite; export NaN, is_NaN, infinity, neg_infinity; export consts; export logarithm; export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh; export erf, erfc, exp, expm1, exp2, abs, abs_sub; export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp; export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix; export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc; export signbit; // export when m_float == c_double export j0, j1, jn, y0, y1, yn; // PORT this must match in width according to architecture import m_float = f64; import f64::*; type t = float; /** * Section: String Conversions */ /* Function: to_str_common Converts a float to a string Parameters: num - The float value digits - The number of significant digits exact - Whether to enforce the exact number of significant digits */ fn to_str_common(num: float, digits: uint, exact: bool) -> str { if is_NaN(num) { ret "NaN"; } let (num, accum) = if num < 0.0 { (-num, "-") } else { (num, "") }; let trunc = num as uint; let frac = num - (trunc as float); accum += uint::str(trunc); if frac < epsilon || digits == 0u { ret accum; } accum += "."; let i = digits; let epsilon = 1. / pow_uint_to_uint_as_float(10u, i); while i > 0u && (frac >= epsilon || exact) { frac *= 10.0; epsilon *= 10.0; let digit = frac as uint; accum += uint::str(digit); frac -= digit as float; i -= 1u; } ret accum; } /* Function: to_str Converts a float to a string with exactly the number of provided significant digits Parameters: num - The float value digits - The number of significant digits */ fn to_str_exact(num: float, digits: uint) -> str { to_str_common(num, digits, true) } /* Function: to_str Converts a float to a string with a maximum number of significant digits Parameters: num - The float value digits - The number of significant digits */ fn to_str(num: float, digits: uint) -> str { to_str_common(num, digits, false) } /* Function: from_str 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" Leading and trailing whitespace are ignored. Parameters: num - A string, possibly empty. Returns: If the string did not represent a valid number. Otherwise, the floating-point number represented [num]. */ fn from_str(num: str) -> float { let num = str::trim(num); 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. //The string must start with one of the following characters. alt str::char_at(num, 0u) { '-' | '+' | '0' to '9' | '.' {} _ { ret NaN; } } //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' to '9' { total = total * 10f; total += ((c as int) - ('0' as int)) as float; } '.' | 'e' | 'E' { break; } _ { ret NaN; } } } if c == '.' {//Examine decimal part let decimal = 1f; 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 /= 10f; total += (((c as int) - ('0' as int)) as float)*decimal; } 'e' | 'E' { break; } _ { ret NaN; } } } } 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; alt 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_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; } } else { ret NaN; } } if(pos < len) { ret NaN; } else { if(neg) { total *= -1f; } ret total; } } /** * Section: Arithmetics */ /* Function: pow_uint_to_uint_as_float Compute the exponentiation of an integer by another integer as a float. Parameters: x - The base. pow - The exponent. Returns: 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; } #[test] fn test_from_str() { assert ( from_str("3") == 3. ); assert ( from_str(" 3 ") == 3. ); assert ( from_str("3.14") == 3.14 ); assert ( from_str("+3.14") == 3.14 ); assert ( from_str("-3.14") == -3.14 ); assert ( from_str("2.5E10") == 25000000000. ); assert ( from_str("2.5e10") == 25000000000. ); assert ( from_str("25000000000.E-10") == 2.5 ); assert ( from_str("") == 0. ); assert ( from_str(".") == 0. ); assert ( from_str(".e1") == 0. ); assert ( from_str(".e-1") == 0. ); assert ( from_str("5.") == 5. ); assert ( from_str(".5") == 0.5 ); assert ( from_str("0.5") == 0.5 ); assert ( from_str("0.5 ") == 0.5 ); assert ( from_str(" 0.5 ") == 0.5 ); assert ( from_str(" -.5 ") == -0.5 ); assert ( from_str(" -.5 ") == -0.5 ); assert ( from_str(" -5 ") == -5. ); assert ( is_NaN(from_str("x")) ); assert ( from_str(" ") == 0. ); assert ( from_str(" ") == 0. ); assert ( from_str(" 0.5") == 0.5 ); assert ( from_str(" 0.5 ") == 0.5 ); assert ( from_str(" .1 ") == 0.1 ); assert ( is_NaN(from_str("e")) ); assert ( is_NaN(from_str("E")) ); assert ( is_NaN(from_str("E1")) ); assert ( is_NaN(from_str("1e1e1")) ); assert ( is_NaN(from_str("1e1.1")) ); assert ( is_NaN(from_str("1e1-1")) ); } #[test] fn test_positive() { assert(is_positive(infinity)); assert(is_positive(1.)); assert(is_positive(0.)); assert(!is_positive(-1.)); assert(!is_positive(neg_infinity)); assert(!is_positive(1./neg_infinity)); assert(!is_positive(NaN)); } #[test] fn test_negative() { assert(!is_negative(infinity)); assert(!is_negative(1.)); assert(!is_negative(0.)); assert(is_negative(-1.)); assert(is_negative(neg_infinity)); assert(is_negative(1./neg_infinity)); assert(!is_negative(NaN)); } #[test] fn test_nonpositive() { assert(!is_nonpositive(infinity)); assert(!is_nonpositive(1.)); assert(!is_nonpositive(0.)); assert(is_nonpositive(-1.)); assert(is_nonpositive(neg_infinity)); assert(is_nonpositive(1./neg_infinity)); assert(!is_nonpositive(NaN)); } #[test] fn test_nonnegative() { assert(is_nonnegative(infinity)); assert(is_nonnegative(1.)); assert(is_nonnegative(0.)); assert(!is_nonnegative(-1.)); assert(!is_nonnegative(neg_infinity)); assert(!is_nonnegative(1./neg_infinity)); assert(!is_nonnegative(NaN)); } // // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //