[gcalctool] Support floor, ceiling, round, fractional notation. Fix fractional result for negative numbers



commit 036cc9954a12c6c17392d4904b1aee55624f22e5
Author: Robert Ancell <robert ancell gmail com>
Date:   Wed May 12 19:31:32 2010 +0200

    Support floor, ceiling, round, fractional notation.  Fix fractional result for negative numbers

 src/mp-binary.c          |    2 +-
 src/mp-convert.c         |    8 ++++----
 src/mp-equation-lexer.l  |    4 ++++
 src/mp-equation-parser.y |    5 +++++
 src/mp-equation.c        |    2 +-
 src/mp.c                 |   45 +++++++++++++++++++++++++++++++++++++++++----
 src/mp.h                 |   12 +++++++++---
 src/unittest.c           |   30 ++++++++++++++++++++++++++----
 8 files changed, 91 insertions(+), 17 deletions(-)
---
diff --git a/src/mp-binary.c b/src/mp-binary.c
index 4f75e40..8e11970 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -185,7 +185,7 @@ mp_shift(const MPNumber *x, int count, MPNumber *z)
         for (i = 0; i < -count; i++)
             multiplier *= 2;
         mp_divide_integer(x, multiplier, &temp);
-        mp_integer_component(&temp, z);
+        mp_floor(&temp, z);
     }
 }
 
diff --git a/src/mp-convert.c b/src/mp-convert.c
index f527b13..c57ee9e 100644
--- a/src/mp-convert.c
+++ b/src/mp-convert.c
@@ -523,7 +523,7 @@ mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accura
     mp_add(&number, &temp, &number);
 
     /* Split into integer and fractional component */
-    mp_integer_component(&number, &integer_component);
+    mp_floor(&number, &integer_component);
     mp_fractional_component(&number, &fractional_component);
 
     /* Write out the integer component least significant digit to most */
@@ -532,11 +532,11 @@ mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accura
         MPNumber t, t2, t3;
 
         mp_divide_integer(&temp, base, &t);
-        mp_integer_component(&t, &t);
+        mp_floor(&t, &t);
         mp_multiply_integer(&t, base, &t2);
 
         mp_subtract(&temp, &t2, &t3);
-        mp_integer_component(&t3, &t3);
+        mp_floor(&t3, &t3);
 
         g_string_prepend_c(string, digits[mp_cast_to_int(&t3)]);
 
@@ -553,7 +553,7 @@ mp_cast_to_string_real(const MPNumber *x, int default_base, int base, int accura
         MPNumber digit;
 
         mp_multiply_integer(&temp, base, &temp);
-        mp_integer_component(&temp, &digit);
+        mp_floor(&temp, &digit);
         d = mp_cast_to_int(&digit);
 
         g_string_append_c(string, digits[d]);
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index 17956c6..bbc9765 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -87,6 +87,10 @@ IN   [iI][nN]
 "*"|"Ã?"     {return tMULTIPLY;}
 "/"|"â??"|"÷" {return tDIVIDE;}
 {MOD}       {return tMOD;}
+"â??"         {return tLFLOOR;}
+"â??"         {return tRFLOOR;}
+"â??"         {return tLCEILING;}
+"â??"         {return tRCEILING;}
 "â??"         {return tROOT;}
 "â??"         {return tROOT3;}
 "â??"         {return tROOT4;}
diff --git a/src/mp-equation-parser.y b/src/mp-equation-parser.y
index c4696fb..29e476d 100644
--- a/src/mp-equation-parser.y
+++ b/src/mp-equation-parser.y
@@ -178,6 +178,7 @@ static void do_conversion(yyscan_t yyscanner, const MPNumber *x, const char *x_u
 }
 
 %left <int_t> tNUMBER
+%left tLFLOOR tRFLOOR tLCEILING tRCEILING
 %left UNARY_PLUS
 %left tADD tSUBTRACT
 %left tAND tOR tXOR tXNOR
@@ -215,6 +216,10 @@ unit:
 exp:
   '(' exp ')' {mp_set_from_mp(&$2, &$$);}
 | exp '(' exp ')' {mp_multiply(&$1, &$3, &$$);}
+| tLFLOOR exp tRFLOOR {mp_floor(&$2, &$$);}
+| tLCEILING exp tRCEILING {mp_ceiling(&$2, &$$);}
+| '[' exp ']' {mp_round(&$2, &$$);}
+| '{' exp '}' {mp_fractional_component(&$2, &$$);}
 | '|' exp '|' {mp_abs(&$2, &$$);}
 | exp '^' exp {mp_xpowy(&$1, &$3, &$$);}
 | exp tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
diff --git a/src/mp-equation.c b/src/mp-equation.c
index ceac748..89fcdf3 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -184,7 +184,7 @@ get_function(MPEquationParserState *state, const char *name, const MPNumber *x,
     else if (strcmp(lower_name, "conj") == 0)
         mp_conjugate(x, z);
     else if (strcmp(lower_name, "int") == 0)
-        mp_integer_component(x, z);
+        mp_floor(x, z);
     else if (strcmp(lower_name, "frac") == 0)
         mp_fractional_component(x, z);
     else if (strcmp(lower_name, "re") == 0)
diff --git a/src/mp.c b/src/mp.c
index edb6591..2533c89 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -450,11 +450,13 @@ mp_fractional_component(const MPNumber *x, MPNumber *z)
     }
     if (z->fraction[0] == 0)
         z->sign = 0;
+    if (z->sign < 0)
+       z->sign = -z->sign;
 }
 
 
 void
-mp_integer_component(const MPNumber *x, MPNumber *z)
+mp_floor(const MPNumber *x, MPNumber *z)
 {
     int i;
 
@@ -477,6 +479,41 @@ mp_integer_component(const MPNumber *x, MPNumber *z)
 }
 
 
+void
+mp_ceiling(const MPNumber *x, MPNumber *z)
+{
+    MPNumber f;
+
+    mp_floor(x, z);
+    mp_fractional_component(x, &f);
+    if (mp_is_zero(&f))
+        return;
+
+    if (mp_is_negative(x))
+       mp_add_integer(z, -1, z);
+    else
+       mp_add_integer(z, 1, z);
+}
+
+
+void
+mp_round(const MPNumber *x, MPNumber *z)
+{
+    MPNumber f, one;
+
+    mp_floor(x, z);
+    mp_fractional_component(x, &f);
+    mp_multiply_integer(&f, 2, &f);
+    mp_set_from_integer(1, &one);
+    if (mp_is_less_than(&f, &one))
+        return;
+
+    if (mp_is_negative(x))
+       mp_add_integer(z, -1, z);
+    else
+       mp_add_integer(z, 1, z);   
+}
+
 int
 mp_compare_mp_to_mp(const MPNumber *x, const MPNumber *y)
 {
@@ -733,12 +770,12 @@ mp_is_integer(const MPNumber *x)
     /* This fix is required for 1/3 repiprocal not being detected as an integer */
     /* Multiplication and division by 10000 is used to get around a
      * limitation to the "fix" for Sun bugtraq bug #4006391 in the
-     * mp_integer_component() routine in mp.c, when the exponent is less than 1.
+     * mp_floor() routine in mp.c, when the exponent is less than 1.
      */
     mp_set_from_integer(10000, &t3);
     mp_multiply(x, &t3, &t1);
     mp_divide(&t1, &t3, &t1);
-    mp_integer_component(&t1, &t2);
+    mp_floor(&t1, &t2);
     return mp_is_equal(&t1, &t2);
 
     /* Correct way to check for integer */
@@ -1814,7 +1851,7 @@ mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     }
 
     mp_divide(x, y, &t1);
-    mp_integer_component(&t1, &t1);
+    mp_floor(&t1, &t1);
     mp_multiply(&t1, y, &t2);
     mp_subtract(x, &t2, z);
 
diff --git a/src/mp.h b/src/mp.h
index 28fbbc0..2e356dd 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -167,11 +167,17 @@ void   mp_divide_integer(const MPNumber *x, int64_t y, MPNumber *z);
 /* Sets z = 1 ÷ x */
 void   mp_reciprocal(const MPNumber *, MPNumber *);
 
-/* Sets z = fractional part of x */
+/* Sets z = {x} */
 void   mp_fractional_component(const MPNumber *x, MPNumber *z);
 
-/* Sets z = integer part of x */
-void   mp_integer_component(const MPNumber *x, MPNumber *z);
+/* Sets z = â??xâ?? */
+void   mp_floor(const MPNumber *x, MPNumber *z);
+
+/* Sets z = â??xâ?? */
+void   mp_ceiling(const MPNumber *x, MPNumber *z);
+
+/* Sets z = [x] */
+void   mp_round(const MPNumber *x, MPNumber *z);
 
 /* Sets z = ln x */
 void   mp_ln(const MPNumber *x, MPNumber *z);
diff --git a/src/unittest.c b/src/unittest.c
index ac57e21..3ea51a2 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -401,10 +401,32 @@ test_equations()
     test("8 mod 7", "1", 0);
     test("â??1 mod 7", "6", 0);
 
-    test("int 3.2", "3", 0);
-    test("frac 3.2", "0.2", 0);
-    test("int (â??3.2)", "â??3", 0);
-    test("frac (â??3.2)", "â??0.2", 0);
+    test("â??3â??", "3", 0);
+    test("â??3â??", "3", 0);
+    test("[3]", "3", 0);
+    test("â??â??3â??", "â??3", 0);
+    test("â??â??3â??", "â??3", 0);
+    test("[â??3]", "â??3", 0);
+    test("â??3.2â??", "3", 0);
+    test("â??3.2â??", "4", 0);
+    test("[3.2]", "3", 0);
+    test("â??â??3.2â??", "â??3", 0);
+    test("â??â??3.2â??", "â??4", 0);
+    test("[â??3.2]", "â??3", 0);
+    test("â??3.5â??", "3", 0);
+    test("â??3.5â??", "4", 0);
+    test("[3.5]", "4", 0);
+    test("â??â??3.5â??", "â??3", 0);
+    test("â??â??3.5â??", "â??4", 0);
+    test("[â??3.5]", "â??4", 0);
+    test("â??3.7â??", "3", 0);
+    test("â??3.7â??", "4", 0);
+    test("[3.7]", "4", 0);
+    test("â??â??3.7â??", "â??3", 0);
+    test("â??â??3.7â??", "â??4", 0);
+    test("[â??3.7]", "â??4", 0);
+    test("{3.2}", "0.2", 0);
+    test("{â??3.2}", "0.2", 0);
 
     test("|1|", "1", 0);
     test("|â??1|", "1", 0);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]