[Gnucash-changes] add double-precision tests, add tests of multiplication of random

Linas Vepstas linas at cvs.gnucash.org
Sat Jun 26 02:12:09 EDT 2004


Log Message:
-----------
add double-precision tests,
add tests of multiplication of random numbers

Modified Files:
--------------
    gnucash/src/engine/test:
        test-numeric.c

Revision Data
-------------
Index: test-numeric.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/test/test-numeric.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -Lsrc/engine/test/test-numeric.c -Lsrc/engine/test/test-numeric.c -u -r1.8 -r1.9
--- src/engine/test/test-numeric.c
+++ src/engine/test/test-numeric.c
@@ -15,18 +15,20 @@
 #include "test-engine-stuff.h"
 #include "gnc-numeric.h"
 
-#define NREPS 3000
-
+#define NREPS 1000
 
 static char *
-gnc_numeric_print(gnc_numeric in) {
+gnc_numeric_print(gnc_numeric in) 
+{
   char * retval;
-  if(gnc_numeric_check(in)) {
+  if(gnc_numeric_check(in)) 
+  {
     retval = g_strdup_printf("<ERROR> [%lld / %lld]",
                              (long long int) in.num,
                              (long long int) in.denom); 
   }
-  else {
+  else 
+  {
     retval = g_strdup_printf("[%lld / %lld]",
                              (long long int) in.num,
                              (long long int) in.denom); 
@@ -34,6 +36,8 @@
   return retval;
 }
 
+/* ======================================================= */
+
 static void
 check_unary_op (gboolean (*eqtest) (gnc_numeric, gnc_numeric), 
                 gnc_numeric expected, 
@@ -54,6 +58,8 @@
 	g_free (str);
 }
 
+/* ======================================================= */
+
 static void
 check_binary_op (gnc_numeric expected, 
                  gnc_numeric actual, 
@@ -76,64 +82,7 @@
 	g_free (str);
 }
 
-#ifdef XXX_GNC_NUMERIC_TEST
-int
-main(int argc, char ** argv) {
-  gnc_numeric a = gnc_numeric_create(1, 3);
-  gnc_numeric b = gnc_numeric_create(1, 4);
-  gnc_numeric d = gnc_numeric_create(1, 2);
-  
-  gnc_numeric err;
-  int i;
-  gint64 v;
-
-  printf("7/16 as float: %e\n",
-         gnc_numeric_to_double(gnc_numeric_create(7, 16)));
-  
-  printf("add LCM: %s + %s = %s\n",
-         gnc_numeric_print(b), gnc_numeric_print(d),
-         gnc_numeric_print(gnc_numeric_add(b, d, GNC_DENOM_AUTO,
-                                           GNC_DENOM_LCD)));
- 
-  printf("float to 6 sigfigs: %s\n",
-         gnc_numeric_print(double_to_gnc_numeric(1.1234567890123, 
-                                                 GNC_DENOM_AUTO, 
-                                                 GNC_DENOM_SIGFIGS(6) |
-                                                 GNC_RND_ROUND)));
-  printf("float to 6 sigfigs: %s\n",
-         gnc_numeric_print(double_to_gnc_numeric(.011234567890123, 
-                                                 GNC_DENOM_AUTO, 
-                                                 GNC_DENOM_SIGFIGS(6) |
-                                                 GNC_RND_ROUND)));
-  printf("float to 6 sigfigs: %s\n",
-         gnc_numeric_print(double_to_gnc_numeric(1123.4567890123, 
-                                                 GNC_DENOM_AUTO, 
-                                                 GNC_DENOM_SIGFIGS(6) |
-                                                 GNC_RND_ROUND)));
-  printf("float to 6 sigfigs: %s\n",
-         gnc_numeric_print(double_to_gnc_numeric(1.1234567890123e-5, 
-                                                 GNC_DENOM_AUTO, 
-                                                 GNC_DENOM_SIGFIGS(6) |
-                                                 GNC_RND_ROUND)));
-  printf("add to 4 sigfigs: %s + %s = %s\n",
-         gnc_numeric_print(a), gnc_numeric_print(b),
-         gnc_numeric_print(gnc_numeric_add(a, b, 
-                                           GNC_DENOM_AUTO, 
-                                           GNC_DENOM_SIGFIGS(4) |
-                                           GNC_RND_ROUND)));
-  
-   
-  v = 1000000;
-  a = gnc_numeric_create(1*v, v);
-  b = gnc_numeric_create(10000000*v, v);
-  printf("multiply (LCD): %s * %s = %s\n",
-	 gnc_numeric_print(a), gnc_numeric_print(b),
-	 gnc_numeric_print(gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_LCD)));
-
-
-  return 0;
-}
-#endif
+/* ======================================================= */
 
 static gboolean
 gnc_numeric_unequal (gnc_numeric a, gnc_numeric b)
@@ -141,6 +90,8 @@
 	return (0 == gnc_numeric_equal (a,b));
 }
 
+/* ======================================================= */
+
 /* Make sure that the equivalence operator we use for 
  * later tests actually works */
 static void
@@ -156,6 +107,7 @@
 	do_test (0 == gnc_numeric_eq(a, c), "expected inequivalence");
 }
 
+/* ======================================================= */
 
 static void
 check_reduce (void)
@@ -193,6 +145,8 @@
                    val, "expected %s = %s = reduce(%s)");
 }
 
+/* ======================================================= */
+
 static void
 check_equality_operator (void)
 {
@@ -275,6 +229,8 @@
 	}
 }
 	
+/* ======================================================= */
+
 static void 
 check_rounding (void)
 {
@@ -336,12 +292,57 @@
                    val, "expected %s = %s = (%s as 100th's round)");
 }
 
+/* ======================================================= */
+
+static void
+check_double (void)
+{
+	gnc_numeric val = gnc_numeric_create (0,1);
+
+	check_unary_op (gnc_numeric_eq,
+	                gnc_numeric_create (112346,100000),
+                   double_to_gnc_numeric(1.1234567890123, 
+                                         GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(6) |
+                                         GNC_RND_ROUND),
+                   val, "expected %s = %s double 6 figs");
+
+	check_unary_op (gnc_numeric_eq,
+	                gnc_numeric_create (112346,10000000),
+                   double_to_gnc_numeric(0.011234567890123, 
+                                         GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(6) |
+                                         GNC_RND_ROUND),
+                   val, "expected %s = %s double 6 figs");
+
+	check_unary_op (gnc_numeric_eq,
+	                gnc_numeric_create (112346,100),
+                   double_to_gnc_numeric(1123.4567890123, 
+                                         GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(6) |
+                                         GNC_RND_ROUND),
+                   val, "expected %s = %s double 6 figs");
+	check_unary_op (gnc_numeric_eq,
+	                gnc_numeric_create (112346,10000000000LL),
+                   double_to_gnc_numeric(1.1234567890123e-5, 
+                                         GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(6) |
+                                         GNC_RND_ROUND),
+                   val, "expected %s = %s double 6 figs");
+
+	double flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
+	do_test ((0.4375 == flo), "float pt conversion");
+}
+
+/* ======================================================= */
+
 static void
 check_add_subtract (void)
 {
-  gnc_numeric a = gnc_numeric_create(1, 3);
+  gnc_numeric a = gnc_numeric_create(2, 6);
   gnc_numeric b = gnc_numeric_create(1, 4);
 
+  /* Well, actually 14/24 would be acceptable/better in this case */
   check_binary_op (gnc_numeric_create(7,12), 
                    gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
 						 a, b, "expected %s got %s = %s + %s for add exact");
@@ -350,17 +351,34 @@
                    gnc_numeric_add(a, b, 100, GNC_RND_ROUND),
 						 a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
   
+  check_binary_op (gnc_numeric_create(5833,10000), 
+                   gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(4) |
+                                         GNC_RND_ROUND),
+						 a, b, "expected %s got %s = %s + %s for add 4 sig figs");
+  
+  check_binary_op (gnc_numeric_create(583333,1000000), 
+                   gnc_numeric_add(a, b, GNC_DENOM_AUTO, 
+                                         GNC_DENOM_SIGFIGS(6) |
+                                         GNC_RND_ROUND),
+						 a, b, "expected %s got %s = %s + %s for add 6 sig figs");
+  
   check_binary_op (gnc_numeric_create(1,12), 
                    gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
 						 a, b, "expected %s got %s = %s - %s for sub exact");
   
+  /* We should try something trickier for reduce & lcd */
   check_binary_op (gnc_numeric_create(1,12), 
                    gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
-						 a, b, "expected %s got %s = %s - %s for sub least");
+						 a, b, "expected %s got %s = %s - %s for sub reduce");
+  
+  check_binary_op (gnc_numeric_create(1,12), 
+                   gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_DENOM_LCD),
+						 a, b, "expected %s got %s = %s - %s for sub reduce");
   
   check_binary_op (gnc_numeric_create(8,100), 
                    gnc_numeric_sub(a, b, 100, GNC_RND_ROUND),
-						 a, b, "expected %s got %s = %s - %s for add 100ths (banker's)");
+						 a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
   
 #if CHECK_ERRORS_TOO
   gnc_numeric c;
@@ -411,6 +429,8 @@
 	}
 }
 
+/* ======================================================= */
+
 static void
 check_mult_div (void)
 {
@@ -457,8 +477,53 @@
   
 #endif
   
+  /* Check for math with 2^63 < num*num < 2^64 which previously failed 
+   * see http://bugzilla.gnome.org/show_bug.cgi?id=144980 
+   */
+  gint64 v = 1000000;
+  a = gnc_numeric_create(1*v, v);
+  b = gnc_numeric_create(10000000*v, v);
+
+  check_binary_op (b,
+	                gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_LCD),
+						 a, b, "expected %s got %s = %s * %s for multiply");
+
+	/* Multiply some random numbers.  This test presumes that
+	 * RAND_MAX is less than 2^32 
+    */
+	int i;
+	for (i=0; i<NREPS; i++)
+	{
+		gint64 deno = 1;
+		gint64 na = rand();
+		gint64 nb = rand();
+		gint64 ne;
+
+		/* avoid overflow; */
+		na /= 2;
+		nb /= 2;
+		ne = na*nb;
+		
+		a = gnc_numeric_create(na, deno);
+		b = gnc_numeric_create(nb, deno);
+
+		check_binary_op (gnc_numeric_create(ne,1), 
+                   gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_EXACT),
+						 a, b, "expected %s got %s = %s * %s for mult exact");
+		int j;
+		for (j=1; j<31; j++)
+		{
+			a = gnc_numeric_create(na << j, 1<<j);
+			b = gnc_numeric_create(nb << j, 1<<j);
+			check_binary_op (gnc_numeric_create(ne, 1), 
+                   gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_DENOM_REDUCE),
+						 a, b, "expected %s got %s = %s * %s for mult exact");
+		}
+	}
+
 }
   
+/* ======================================================= */
 
 static void
 run_test (void)
@@ -467,6 +532,7 @@
 	check_reduce ();
 	check_equality_operator ();
 	check_rounding();
+	check_double();
 	check_add_subtract();
 	check_mult_div ();
 }
@@ -489,3 +555,5 @@
   scm_boot_guile(argc, argv, main_helper, NULL);
   return 0;
 }
+
+/* ======================== END OF FILE ====================== */


More information about the gnucash-changes mailing list