about summary refs log tree commit diff
path: root/src/libcore/float.rs
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2011-12-13 16:25:51 -0800
committerGraydon Hoare <graydon@mozilla.com>2011-12-13 16:34:50 -0800
commitfa9ad984fb2f013baebdbe01a42baa3b9101dd84 (patch)
tree49115690e45ca322337b93f25308cd618f85b013 /src/libcore/float.rs
parent32087f5c2a35bf8050067c22a57fd60269633a60 (diff)
downloadrust-fa9ad984fb2f013baebdbe01a42baa3b9101dd84.tar.gz
rust-fa9ad984fb2f013baebdbe01a42baa3b9101dd84.zip
Copy first batch of material from libstd to libcore.
Diffstat (limited to 'src/libcore/float.rs')
-rw-r--r--src/libcore/float.rs343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/libcore/float.rs b/src/libcore/float.rs
new file mode 100644
index 00000000000..015dceb1dc1
--- /dev/null
+++ b/src/libcore/float.rs
@@ -0,0 +1,343 @@
+/*
+Module: 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 {
+    let (num, accum) = num < 0.0 ? (-num, "-") : (num, "");
+    let trunc = num as uint;
+    let frac = num - (trunc as float);
+    accum += uint::str(trunc);
+    if frac == 0.0 || 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:
+
+<NaN> 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 = 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;
+             }
+             '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:
+<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;
+}
+
+
+/* Const: NaN */
+const NaN: float = 0./0.;
+
+/* Const: infinity */
+const infinity: float = 1./0.;
+
+/* Const: neg_infinity */
+const neg_infinity: float = -1./0.;
+
+/* Predicate: isNaN */
+pure fn isNaN(f: float) -> bool { f != f }
+
+/* Function: add */
+pure fn add(x: float, y: float) -> float { ret x + y; }
+
+/* Function: sub */
+pure fn sub(x: float, y: float) -> float { ret x - y; }
+
+/* Function: mul */
+pure fn mul(x: float, y: float) -> float { ret x * y; }
+
+/* Function: div */
+pure fn div(x: float, y: float) -> float { ret x / y; }
+
+/* Function: rem */
+pure fn rem(x: float, y: float) -> float { ret x % y; }
+
+/* Predicate: lt */
+pure fn lt(x: float, y: float) -> bool { ret x < y; }
+
+/* Predicate: le */
+pure fn le(x: float, y: float) -> bool { ret x <= y; }
+
+/* Predicate: eq */
+pure fn eq(x: float, y: float) -> bool { ret x == y; }
+
+/* Predicate: ne */
+pure fn ne(x: float, y: float) -> bool { ret x != y; }
+
+/* Predicate: ge */
+pure fn ge(x: float, y: float) -> bool { ret x >= y; }
+
+/* Predicate: gt */
+pure fn gt(x: float, y: float) -> bool { ret x > y; }
+
+/*
+Predicate: positive
+
+Returns true if `x` is a positive number, including +0.0 and +Infinity.
+ */
+pure fn positive(x: float) -> bool { ret x > 0. || (1./x) == infinity; }
+
+/*
+Predicate: negative
+
+Returns true if `x` is a negative number, including -0.0 and -Infinity.
+ */
+pure fn negative(x: float) -> bool { ret x < 0. || (1./x) == neg_infinity; }
+
+/*
+Predicate: nonpositive
+
+Returns true if `x` is a negative number, including -0.0 and -Infinity.
+(This is the same as `float::negative`.)
+*/
+pure fn nonpositive(x: float) -> bool {
+  ret x < 0. || (1./x) == neg_infinity;
+}
+
+/*
+Predicate: nonnegative
+
+Returns true if `x` is a positive number, including +0.0 and +Infinity.
+(This is the same as `float::positive`.)
+*/
+pure fn nonnegative(x: float) -> bool {
+  ret x > 0. || (1./x) == infinity;
+}
+
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//