GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
test-numeric.c
1 
2 /* Test file created by Linas Vepstas <[email protected]>
3  * Review operation of the gnc-numeric tools by verifying results
4  * of vairous operations.
5  *
6  * June 2004
7  */
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301, USA.
23  */
24 
25 
26 #include "config.h"
27 #include <ctype.h>
28 #include <glib.h>
29 #include "cashobjects.h"
30 #include "test-stuff.h"
31 #include "test-engine-stuff.h"
32 #include "gnc-numeric.h"
33 
34 #define NREPS 2000
35 
36 static char *
37 gnc_numeric_print(gnc_numeric in)
38 {
39  char * retval;
40  if (gnc_numeric_check(in))
41  {
42  retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
43  in.num,
44  in.denom);
45  }
46  else
47  {
48  retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
49  in.num,
50  in.denom);
51  }
52  return retval;
53 }
54 
55 /* ======================================================= */
56 
57 #define check_unary_op(eq,ex,a,i,e) check_unary_op_r(eq,ex,a,i,e,__LINE__)
58 static void
59 check_unary_op_r (gboolean (*eqtest) (gnc_numeric, gnc_numeric),
60  gnc_numeric expected,
61  gnc_numeric actual,
62  gnc_numeric input,
63  const char * errmsg,
64  int line)
65 {
66  char *e = gnc_numeric_print (expected);
67  char *r = gnc_numeric_print (actual);
68  char *a = gnc_numeric_print (input);
69  char *str = g_strdup_printf (errmsg, e, r, a);
70 
71  do_test_call (eqtest(expected, actual), str, __FILE__, line);
72 
73  g_free (a);
74  g_free (r);
75  g_free (e);
76  g_free (str);
77 }
78 
79 /* ======================================================= */
80 
81 #define check_binary_op(ex,a,ia,ib,e) check_binary_op_r(ex,a,ia,ib,e,__LINE__,gnc_numeric_eq)
82 #define check_binary_op_equal(ex,a,ia,ib,e) check_binary_op_r(ex,a,ia,ib,e,__LINE__,gnc_numeric_equal)
83 static void
84 check_binary_op_r (gnc_numeric expected,
85  gnc_numeric actual,
86  gnc_numeric input_a,
87  gnc_numeric input_b,
88  const char * errmsg,
89  int line,
90  gboolean (*eq)(gnc_numeric, gnc_numeric))
91 {
92  char *e = gnc_numeric_print (expected);
93  char *r = gnc_numeric_print (actual);
94  char *a = gnc_numeric_print (input_a);
95  char *b = gnc_numeric_print (input_b);
96  char *str = g_strdup_printf (errmsg, e, r, a, b);
97 
98  do_test_call ((eq)(expected, actual), str, __FILE__, line);
99 
100  g_free (a);
101  g_free (b);
102  g_free (r);
103  g_free (e);
104  g_free (str);
105 }
106 
107 /* ======================================================= */
108 
109 static gboolean
110 gnc_numeric_unequal (gnc_numeric a, gnc_numeric b)
111 {
112  return (0 == gnc_numeric_equal (a, b));
113 }
114 
115 /* ======================================================= */
116 
117 /* Make sure that the equivalence operator we use for
118  * later tests actually works */
119 static void
120 check_eq_operator (void)
121 {
122  gnc_numeric a = gnc_numeric_create (42, 58);
123  gnc_numeric b = gnc_numeric_create (42, 58);
124  gnc_numeric c = gnc_numeric_create (40, 58);
125 
126  /* Check strict equivalence and non-equivalence */
127  do_test (gnc_numeric_eq(a, a), "expected self-equivalence");
128  do_test (gnc_numeric_eq(a, b), "expected equivalence");
129  do_test (0 == gnc_numeric_eq(a, c), "expected inequivalence");
130 }
131 
132 /* ======================================================= */
133 
134 static void
135 check_reduce (void)
136 {
137  gnc_numeric one, rone;
138  gnc_numeric four, rfour;
139  gnc_numeric val, rval;
140  /* Check common factor elimination (needed for equality checks) */
141  one = gnc_numeric_create (1, 1);
142  rone = gnc_numeric_create (1000000, 1000000);
143  rone = gnc_numeric_reduce (rone);
144  do_test (gnc_numeric_eq(one, rone), "reduce to one");
145 
146  four = gnc_numeric_create (4, 1);
147  rfour = gnc_numeric_create (480, 120);
148  rfour = gnc_numeric_reduce (rfour);
149  do_test (gnc_numeric_eq(four, rfour), "reduce to four");
150 
151  val = gnc_numeric_create(10023234LL, 334216654LL);
152  rval = gnc_numeric_reduce (val);
153  check_unary_op (gnc_numeric_eq,
154  gnc_numeric_create (5011617, 167108327),
155  rval,
156  val, "check_reduce(1) expected %s got %s = reduce(%s)");
157 
158  val = gnc_numeric_create(17474724864LL, 136048896LL);
159  rval = gnc_numeric_reduce (val);
160  check_unary_op (gnc_numeric_eq,
161  gnc_numeric_create (4 * 17 * 17, 9),
162  rval,
163  val, "check_reduce(2) expected %s got %s = reduce(%s)");
164 
165  val = gnc_numeric_create(1024LL, 1099511627776LL);
166  rval = gnc_numeric_reduce (val);
167  check_unary_op (gnc_numeric_eq,
168  gnc_numeric_create (1, 1024 * 1024 * 1024),
169  rval,
170  val, "check_reduce(3): expected %s got %s = reduce(%s)");
171 }
172 
173 /* ======================================================= */
174 
175 static void
176 check_equality_operator (void)
177 {
178  int i, m;
179  gint mult;
180  gint64 f, deno, numer;
181  gnc_numeric big, rbig;
182  gnc_numeric val, mval;
183  gnc_numeric bval, rval;
184  /* Check equality operator for some large numer/denom values */
185  numer = 1 << 30;
186  numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
187  deno = 1 << 30;
188  deno <<= 20;
189  rbig = gnc_numeric_create (numer, deno);
190 
191  big = gnc_numeric_create (1 << 10, 1);
192  do_test (gnc_numeric_equal(big, rbig), "equal to billion");
193 
194  big = gnc_numeric_create (1 << 20, 1 << 10);
195  do_test (gnc_numeric_equal(big, rbig), "equal to 1<<20/1<<10");
196 
197  big = gnc_numeric_create (1 << 30, 1 << 20);
198  do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30/1<<20");
199 
200  numer = 1 << 30;
201  numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
202  deno = 1 << 30;
203  rbig = gnc_numeric_create (numer, deno);
204 
205  big = gnc_numeric_create (1 << 30, 1);
206  do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30");
207 
208  numer = 1 << 30;
209  numer <<= 10;
210  big = gnc_numeric_create (numer, 1 << 10);
211  do_test (gnc_numeric_equal(big, rbig), "equal to 1<<40/1<<10");
212 
213  numer <<= 10;
214  big = gnc_numeric_create (numer, 1 << 20);
215  do_test (gnc_numeric_equal(big, rbig), "equal to 1<<50/1<<20");
216 
217  /* We assume RAND_MAX is less that 1<<32 */
218  for (i = 0; i < NREPS; i++)
219  {
220  deno = rand() / 2;
221  mult = rand() / 2;
222  numer = rand() / 2;
223 
224  /* avoid 0 */
225  if (deno == 0 || mult == 0)
226  {
227  i--;
228  continue;
229  }
230 
231  val = gnc_numeric_create (numer, deno);
232  mval = gnc_numeric_create (numer * mult, deno * mult);
233 
234  /* The reduced version should be equivalent */
235  bval = gnc_numeric_reduce (val);
236  rval = gnc_numeric_reduce (mval);
237  check_unary_op (gnc_numeric_eq,
238  bval, rval, mval, "expected %s got %s = reduce(%s)");
239 
240  /* The unreduced versions should be equal */
241  check_unary_op (gnc_numeric_equal,
242  val, mval, mval, "expected %s = %s");
243 
244  /* Certain modulo's should be very cleary un-equal; this
245  * helps stop funky modulo-64 aliasing in compares that
246  * might creep in. */
247  mval.denom >>= 1;
248  mval.num >>= 1;
249  m = 0;
250  f = mval.denom;
251  while (f % 2 == 0)
252  {
253  f >>= 1;
254  m++;
255  }
256  if (1 < m)
257  {
258  gint64 nn = 1 << (32 - m);
259  nn <<= 32;
260  nn += mval.num;
261  val = gnc_numeric_create (2 * nn, 2 * mval.denom);
262  check_unary_op (gnc_numeric_unequal,
263  val, mval, mval, "expected unequality %s != %s");
264 
265  }
266  }
267 }
268 
269 /* ======================================================= */
270 
271 static void
272 check_rounding (void)
273 {
274  gnc_numeric val;
275 
276  val = gnc_numeric_create(7, 16);
277  check_unary_op (gnc_numeric_eq,
278  gnc_numeric_create (43, 100),
280  val, "expected %s got %s = (%s as 100th's floor)");
281  check_unary_op (gnc_numeric_eq,
282  gnc_numeric_create (44, 100),
284  val, "expected %s got %s = (%s as 100th's ceiling)");
285  check_unary_op (gnc_numeric_eq,
286  gnc_numeric_create (43, 100),
288  val, "expected %s got %s = (%s as 100th's trunc)");
289  check_unary_op (gnc_numeric_eq,
290  gnc_numeric_create (44, 100),
292  val, "expected %s got %s = (%s as 100th's round)");
293 
294  val = gnc_numeric_create(1511, 1000);
295  check_unary_op (gnc_numeric_eq,
296  gnc_numeric_create (151, 100),
298  val, "expected %s got %s = (%s as 100th's round)");
299 
300  val = gnc_numeric_create(1516, 1000);
301  check_unary_op (gnc_numeric_eq,
302  gnc_numeric_create (152, 100),
304  val, "expected %s got %s = (%s as 100th's round)");
305 
306  /* Half-values always get rounded to nearest even number */
307  val = gnc_numeric_create(1515, 1000);
308  check_unary_op (gnc_numeric_eq,
309  gnc_numeric_create (152, 100),
311  val, "expected %s got %s = (%s as 100th's round)");
312 
313  val = gnc_numeric_create(1525, 1000);
314  check_unary_op (gnc_numeric_eq,
315  gnc_numeric_create (152, 100),
317  val, "expected %s got %s = (%s as 100th's round)");
318 
319  val = gnc_numeric_create(1535, 1000);
320  check_unary_op (gnc_numeric_eq,
321  gnc_numeric_create (154, 100),
323  val, "expected %s got %s = (%s as 100th's round)");
324 
325  val = gnc_numeric_create(1545, 1000);
326  check_unary_op (gnc_numeric_eq,
327  gnc_numeric_create (154, 100),
329  val, "expected %s got %s = (%s as 100th's round)");
330 }
331 
332 /* ======================================================= */
333 
334 static void
335 check_double (void)
336 {
337  double flo;
338  gnc_numeric val = gnc_numeric_create (0, 1);
339 
340  check_unary_op (gnc_numeric_eq,
341  gnc_numeric_create (112346, 100000),
342  double_to_gnc_numeric(1.1234567890123,
346  val, "expected %s = %s double 6 figs");
347 
348  check_unary_op (gnc_numeric_eq,
349  gnc_numeric_create (112346, 10000000),
350  double_to_gnc_numeric(0.011234567890123,
354  val, "expected %s = %s double 6 figs");
355 
356  check_unary_op (gnc_numeric_eq,
357  gnc_numeric_create (112346, 100),
358  double_to_gnc_numeric(1123.4567890123,
362  val, "expected %s = %s double 6 figs");
363  check_unary_op (gnc_numeric_eq,
364  gnc_numeric_create (112346, 10000000000LL),
365  double_to_gnc_numeric(1.1234567890123e-5,
369  val, "expected %s = %s double 6 figs");
370 
371  flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
372  do_test ((0.4375 == flo), "float pt conversion");
373 }
374 
375 /* ======================================================= */
376 
377 static void
378 check_neg (void)
379 {
380  gnc_numeric a = gnc_numeric_create(2, 6);
381  gnc_numeric b = gnc_numeric_create(1, 4);
384 
385  check_unary_op (gnc_numeric_eq,
386  gnc_numeric_create (-2, 6), c,
387  a, "expected %s got %s = -(%s)");
388 
389  check_unary_op (gnc_numeric_eq,
390  gnc_numeric_create (-1, 4), d,
391  b, "expected %s got %s = -(%s)");
392 
393 }
394 
395 /* ======================================================= */
396 
397 static void
398 check_add_subtract (void)
399 {
400  int i;
401  gnc_numeric a, b, c, d, z;
402 #if CHECK_ERRORS_TOO
403  gnc_numeric c;
404 #endif
405 
406  a = gnc_numeric_create(2, 6);
407  b = gnc_numeric_create(1, 4);
408 
409  /* Well, actually 14/24 would be acceptable/better in this case */
410  check_binary_op (gnc_numeric_create(7, 12),
412  a, b, "expected %s got %s = %s + %s for add exact");
413 
414  check_binary_op (gnc_numeric_create(58, 100),
416  a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
417 
418  check_binary_op (gnc_numeric_create(5833, 10000),
422  a, b, "expected %s got %s = %s + %s for add 4 sig figs");
423 
424  check_binary_op (gnc_numeric_create(583333, 1000000),
428  a, b, "expected %s got %s = %s + %s for add 6 sig figs");
429 
430  check_binary_op (gnc_numeric_create(1, 12),
432  a, b, "expected %s got %s = %s - %s for sub exact");
433 
434  /* We should try something trickier for reduce & lcd */
435  check_binary_op (gnc_numeric_create(1, 12),
437  a, b, "expected %s got %s = %s - %s for sub reduce");
438 
439  check_binary_op (gnc_numeric_create(1, 12),
441  a, b, "expected %s got %s = %s - %s for sub reduce");
442 
443  check_binary_op (gnc_numeric_create(8, 100),
445  a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
446 
447  /* ------------------------------------------------------------ */
448  /* This test has failed before */
449  c = gnc_numeric_neg (a);
450  d = gnc_numeric_neg (b);
451  z = gnc_numeric_zero();
452  check_binary_op (c, gnc_numeric_add_fixed(z, c),
453  z, c, "expected %s got %s = %s + %s for add fixed");
454 
455  check_binary_op (d, gnc_numeric_add_fixed(z, d),
456  z, d, "expected %s got %s = %s + %s for add fixed");
457 
458  /* ------------------------------------------------------------ */
459  /* Same as above, but with signs reviersed */
460  a = c;
461  b = d;
462  /* Well, actually 14/24 would be acceptable/better in this case */
463  check_binary_op (gnc_numeric_create(-7, 12),
465  a, b, "expected %s got %s = %s + %s for add exact");
466 
467  check_binary_op (gnc_numeric_create(-58, 100),
469  a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
470 
471  check_binary_op (gnc_numeric_create(-5833, 10000),
475  a, b, "expected %s got %s = %s + %s for add 4 sig figs");
476 
477  check_binary_op (gnc_numeric_create(-583333, 1000000),
481  a, b, "expected %s got %s = %s + %s for add 6 sig figs");
482 
483  check_binary_op (gnc_numeric_create(-1, 12),
485  a, b, "expected %s got %s = %s - %s for sub exact");
486 
487  /* We should try something trickier for reduce & lcd */
488  check_binary_op (gnc_numeric_create(-1, 12),
490  a, b, "expected %s got %s = %s - %s for sub reduce");
491 
492  check_binary_op (gnc_numeric_create(-1, 12),
494  a, b, "expected %s got %s = %s - %s for sub reduce");
495 
496  check_binary_op (gnc_numeric_create(-8, 100),
498  a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
499 
500  /* ------------------------------------------------------------ */
501 #if CHECK_ERRORS_TOO
502  c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
503  printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
504  gnc_numeric_print(a), gnc_numeric_print(b),
505  gnc_numeric_print(c),
506  gnc_numeric_print(err));
507 
508  c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
509  printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
510  gnc_numeric_print(a), gnc_numeric_print(b),
511  gnc_numeric_print(c),
512  gnc_numeric_print(err));
513 
514 #endif
515 
516  /* ------------------------------------------------------------ */
517  /* Add and subtract some random numbers */
518  for (i = 0; i < NREPS; i++)
519  {
520  gnc_numeric e;
521  gint64 deno = rand() + 1;
522  gint64 na = get_random_gint64();
523  gint64 nb = get_random_gint64();
524  gint64 ne;
525 
526  /* avoid overflow; */
527  na /= 2;
528  nb /= 2;
529 
530  a = gnc_numeric_create(na, deno);
531  b = gnc_numeric_create(nb, deno);
532 
533  /* Add */
534  ne = na + nb;
535  e = gnc_numeric_create(ne, deno);
536  check_binary_op (e,
538  a, b, "expected %s got %s = %s + %s for exact addition");
539 
540  /* Subtract */
541  ne = na - nb;
542  e = gnc_numeric_create(ne, deno);
543  check_binary_op (e,
545  a, b, "expected %s got %s = %s - %s for exact subtraction");
546  }
547 }
548 
549 static const gint64 pten[] = { 1, 10, 100, 1000, 10000, 100000, 1000000,
550  10000000, 100000000, 1000000000, 10000000000,
551  100000000000, 1000000000000, 10000000000000,
552  100000000000000, 10000000000000000,
553  100000000000000000, 1000000000000000000};
554 #define POWTEN_OVERFLOW -5
555 
556 static inline gint64
557 powten (int exp)
558 {
559  if (exp > 18 || exp < -18)
560  return POWTEN_OVERFLOW;
561  return exp < 0 ? -pten[-exp] : pten[exp];
562 }
563 
564 static void
565 check_add_subtract_overflow (void)
566 {
567  int i;
568 
569  for (i = 0; i < NREPS; i++)
570  {
571  /* Div to avoid addition overflows; we're looking for lcd conversion overflows here. */
572 
573  int exp_a = rand () % 1000;
574  int exp_b = rand () % 1000;
575  gint64 bin_deno_a = (exp_a == 0 ? 1 : exp_a);
576  gint64 bin_deno_b = (exp_b == 0 ? 1 : exp_b);
577 /*
578  int exp_a = rand () % 11;
579  int exp_b = rand () % 11;
580  gint64 bin_deno_a = (1 << exp_a);
581  gint64 bin_deno_b = (1 << exp_a);
582 */
583  gint64 dec_deno_a = powten (exp_a % 7);
584  gint64 dec_deno_b = powten (exp_b % 7);
585  gint64 na = get_random_gint64 () % (1000000 * dec_deno_a);
586  gint64 nb = get_random_gint64 () % (1000000 * dec_deno_b);
587  gnc_numeric result;
589  gchar *errmsg;
590 
591  gnc_numeric ba = gnc_numeric_create(na, bin_deno_a);
592  gnc_numeric bb = gnc_numeric_create(nb, bin_deno_b);
593  gnc_numeric da = gnc_numeric_create(na, dec_deno_a);
594  gnc_numeric db = gnc_numeric_create(nb, dec_deno_b);
595  gchar *ba_str = gnc_numeric_to_string (ba);
596  gchar *bb_str = gnc_numeric_to_string (bb);
597  gchar *da_str = gnc_numeric_to_string (da);
598  gchar *db_str = gnc_numeric_to_string (db);
599 
600 
601  /* Add */
602 
604  err = gnc_numeric_check (result);
605  errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
607  do_test (err == 0, errmsg);
608  g_free (errmsg);
609 
611  err = gnc_numeric_check (result);
612  errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
614  do_test (err == 0, errmsg);
615  g_free (errmsg);
617  err = gnc_numeric_check (result);
618  errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
620  do_test (err == 0, errmsg);
621  g_free (errmsg);
622 
624  err = gnc_numeric_check (result);
625  errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
627  do_test (err == 0, errmsg);
628  g_free (errmsg);
629  /* Subtract */
630 
632  err = gnc_numeric_check (result);
633  errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, bb_str,
635  do_test (err == 0, errmsg);
636  g_free (errmsg);
637 
639  err = gnc_numeric_check (result);
640  errmsg = g_strdup_printf ("%s + %s raised %s", da_str, bb_str,
642  do_test (err == 0, errmsg);
643  g_free (errmsg);
645  err = gnc_numeric_check (result);
646  errmsg = g_strdup_printf ("%s + %s raised %s", ba_str, db_str,
648  do_test (err == 0, errmsg);
649  g_free (errmsg);
650 
652  err = gnc_numeric_check (result);
653  errmsg = g_strdup_printf ("%s + %s raised %s", da_str, db_str,
655  do_test (err == 0, errmsg);
656  g_free (errmsg);
657 
658  g_free (ba_str);
659  g_free (bb_str);
660  g_free (da_str);
661  g_free (db_str);
662  }
663 
664 }
665 
666 /* ======================================================= */
667 
668 
669 static void
670 check_mult_div (void)
671 {
672  int i, j;
673  gint64 v;
674  gnc_numeric c, d;
675  gnc_numeric amt_a, amt_tot, frac, val_tot, val_a;
676  gnc_numeric a, b;
677 
678  a = gnc_numeric_create(-100, 100);
679  b = gnc_numeric_create(1, 1);
680  check_binary_op (gnc_numeric_create(-100, 100),
682  a, b, "expected %s got %s = %s / %s div exact");
683 
684  a = gnc_numeric_create(-100, 100);
685  b = gnc_numeric_create(-1, 1);
686  check_binary_op (gnc_numeric_create(100, 100),
688  a, b, "expected %s got %s = %s / %s div exact");
689 
690  a = gnc_numeric_create(-100, 100);
691  b = gnc_numeric_create(-1, 1);
692  check_binary_op (gnc_numeric_create(100, 100),
694  a, b, "expected %s got %s = %s * %s mult exact");
695 
696  a = gnc_numeric_create(2, 6);
697  b = gnc_numeric_create(1, 4);
698 
699  check_binary_op (gnc_numeric_create(2, 24),
701  a, b, "expected %s got %s = %s * %s for mult exact");
702 
703  check_binary_op (gnc_numeric_create(1, 12),
705  a, b, "expected %s got %s = %s * %s for mult reduce");
706 
707  check_binary_op (gnc_numeric_create(8, 100),
709  a, b, "expected %s got %s = %s * %s for mult 100th's");
710 
711  check_binary_op (gnc_numeric_create(8, 6),
713  a, b, "expected %s got %s = %s / %s for div exact");
714 
715  check_binary_op (gnc_numeric_create(4, 3),
717  a, b, "expected %s got %s = %s / %s for div reduce");
718 
719  check_binary_op (gnc_numeric_create(133, 100),
721  a, b, "expected %s got %s = %s * %s for div 100th's");
722 
723 #if CHECK_ERRORS_TOO
724  gnc_numeric c;
725  c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
726  printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
727  gnc_numeric_print(a), gnc_numeric_print(b),
728  gnc_numeric_print(c),
729  gnc_numeric_print(err));
730 
731  c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
732  printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
733  gnc_numeric_print(a), gnc_numeric_print(b),
734  gnc_numeric_print(c),
735  gnc_numeric_print(err));
736 
737 #endif
738 
739  /* Check for math with 2^63 < num*num < 2^64 which previously failed
740  * see http://bugzilla.gnome.org/show_bug.cgi?id=144980
741  */
742  v = 1000000;
743  a = gnc_numeric_create(1 * v, v);
744  b = gnc_numeric_create(10000000 * v, v);
745 
746  check_binary_op (b,
748  a, b, "expected %s got %s = %s * %s for multiply");
749 
750  /* Multiply some random numbers. This test presumes that
751  * RAND_MAX is approx 2^32
752  */
753  for (i = 0; i < NREPS; i++)
754  {
755  gint64 deno = 1;
756  gint64 na = rand();
757  gint64 nb = rand();
758  gint64 ne;
759 
760  /* avoid 0 */
761  if (nb / 4 == 0)
762  {
763  i--;
764  continue;
765  }
766 
767  /* avoid overflow; */
768  na /= 2;
769  nb /= 2;
770  ne = na * nb;
771 
772  a = gnc_numeric_create(na, deno);
773  b = gnc_numeric_create(nb, deno);
774 
775  check_binary_op_equal (gnc_numeric_create(ne, 1),
777  a, b, "expected %s got %s = %s * %s for mult exact");
778 
779  /* Force 128-bit math to come into play */
780  for (j = 1; j < 31; j++)
781  {
782  a = gnc_numeric_create(na << j, 1 << j);
783  b = gnc_numeric_create(nb << j, 1 << j);
784  check_binary_op (gnc_numeric_create(ne, 1),
786  a, b, "expected %s got %s = %s * %s for mult reduce");
787  }
788 
789  /* Do some hokey random 128-bit division too */
790  b = gnc_numeric_create(deno, nb);
791 
792  check_binary_op_equal (gnc_numeric_create(ne, 1),
794  a, b, "expected %s got %s = %s / %s for div exact");
795 
796  /* avoid overflow; */
797  na /= 2;
798  nb /= 2;
799  ne = na * nb;
800  for (j = 1; j < 16; j++)
801  {
802  a = gnc_numeric_create(na << j, 1 << j);
803  b = gnc_numeric_create(1 << j, nb << j);
804  check_binary_op (gnc_numeric_create(ne, 1),
806  a, b, "expected %s got %s = %s / %s for div reduce");
807  }
808  }
809 
810  a = gnc_numeric_create(782592055622866ULL, 89025);
811  b = gnc_numeric_create(2222554708930978ULL, 85568);
812  /* Dividing the above pair overflows, in that after
813  * the division the denominator won't fit into a
814  * 64-bit quantity. This can be seen from
815  * the factorization int primes:
816  * 782592055622866 = 2 * 2283317 * 171371749
817  * (yes, thats a seven and a nine digit prime)
818  * 2222554708930978 = 2 * 1111277354465489
819  * (yes, that's a sixteen-digit prime number)
820  * 89025 = 3*5*5*1187
821  * 85568= 64*7*191
822  * If the rounding method is exact/no-round, then
823  * an overflow error should be signalled; else the
824  * divide routine should shift down the results till
825  * the overflow is eliminated.
826  */
827 /* Doesn't overflow any more! */
828  check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
831  a, b, "expected %s got %s = %s / %s for div exact");
832 
833  check_binary_op (gnc_numeric_create(338441, 1000000),
836  a, b, "expected %s got %s = %s / %s for div round");
837 
838  /* The below is a 'typical' value calculation:
839  * value_frac = value_tot * amt_frace / amt_tot
840  * and has some typical potential-overflow values.
841  * 82718 = 2 * 59 * 701
842  * 47497125586 = 2 * 1489 * 15949337
843  * 69100955 = 5 * 7 * 11 * 179483
844  * 32005637020 = 4 * 5 * 7 * 43 * 71 * 103 * 727
845  */
846  a = gnc_numeric_create (-47497125586LL, 82718);
847  b = gnc_numeric_create (-69100955LL, 55739);
849  d = gnc_numeric_create (-32005637020LL, 55739);
850 
851  check_binary_op (gnc_numeric_create(-102547458LL, 82718),
852  gnc_numeric_div(c, d, 82718,
854  c, d, "expected %s got %s = %s / %s for div round");
855 
856  /* If we specify GNC_HOW_RND_NEVER, then we shoukld get an error,
857  * since the exact result won't fit into a 64-bit quantity. */
858  check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
859  gnc_numeric_div(c, d, 82718,
861  c, d, "expected %s got %s = %s / %s for div round");
862 
863  /* A simple irreducible ratio, involving negative numbers */
864  amt_a = gnc_numeric_create (-6005287905LL, 40595);
865  amt_tot = gnc_numeric_create (-8744187958LL, 40595);
866  frac = gnc_numeric_div (amt_a, amt_tot,
868 
869  check_binary_op (gnc_numeric_create(6005287905LL, 8744187958LL),
870  frac, amt_a, amt_tot,
871  "expected %s got %s = %s / %s for div reduce");
872 
873  /* Another overflow-prone condition */
874  val_tot = gnc_numeric_create (-4280656418LL, 19873);
875  val_a = gnc_numeric_mul (frac, val_tot,
876  gnc_numeric_denom(val_tot),
878  check_binary_op (gnc_numeric_create(-2939846940LL, 19873),
879  val_a, val_tot, frac,
880  "expected %s got %s = %s * %s for mult round");
881 
882  frac = gnc_numeric_create (396226789777979LL, 328758834367851752LL);
883  val_tot = gnc_numeric_create (467013515494988LL, 100);
884  val_a = gnc_numeric_mul (frac, val_tot,
885  gnc_numeric_denom(val_tot),
887  check_binary_op (gnc_numeric_create(562854124919LL, 100),
888  val_a, val_tot, frac,
889  "expected %s got %s = %s * %s for mult round");
890 
891  /* Yet another bug from bugzilla ... */
892  a = gnc_numeric_create (40066447153986554LL, 4518);
893  b = gnc_numeric_create (26703286457229LL, 3192);
894  frac = gnc_numeric_div(a, b,
898 
899  check_binary_op (gnc_numeric_create(106007, 100),
900  frac, a, b,
901  "expected %s got %s = %s / %s for mult sigfigs");
902 
903 }
904 
905 static void
906 check_reciprocal(void)
907 {
908  gnc_numeric a, b, ans, val;
909  double flo;
910 
911  val = gnc_numeric_create(-60, 20);
912  check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
915  val, "expected %s got %s = (%s as RECIP(1))");
916 
917  a = gnc_numeric_create(200, 100);
918  b = gnc_numeric_create(300, 100);
919 
920  /* 2 + 3 = 5 */
922  check_binary_op (gnc_numeric_create(5, -1),
923  ans, a, b, "expected %s got %s = %s + %s for reciprocal");
924 
925  /* 2 + 3 = 5 */
926  a = gnc_numeric_create(2, -1);
927  b = gnc_numeric_create(300, 100);
929  check_binary_op (gnc_numeric_create(5, -1),
930  ans, a, b, "expected %s got %s = %s + %s for reciprocal");
931 
932  /* check gnc_numeric_to_double */
933  flo = gnc_numeric_to_double(gnc_numeric_create(5, -1));
934  do_test ((5.0 == flo), "reciprocal conversion");
935 
936  /* check gnc_numeric_compare */
937  a = gnc_numeric_create(2, 1);
938  b = gnc_numeric_create(2, -1);
939  do_test((0 == gnc_numeric_compare(a, b)), " 2 == 2 ");
940  a = gnc_numeric_create(2, 1);
941  b = gnc_numeric_create(3, -1);
942  do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");
943  a = gnc_numeric_create(-2, 1);
944  b = gnc_numeric_create(2, -1);
945  do_test((-1 == gnc_numeric_compare(a, b)), " -2 < 2 ");
946  a = gnc_numeric_create(2, -1);
947  b = gnc_numeric_create(3, -1);
948  do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");
949 
950  /* check for equality */
951  a = gnc_numeric_create(2, 1);
952  b = gnc_numeric_create(2, -1);
953  do_test(gnc_numeric_equal(a, b), " 2 == 2 ");
954 
955  /* check gnc_numeric_mul */
956  a = gnc_numeric_create(2, 1);
957  b = gnc_numeric_create(3, -1);
959  check_binary_op (gnc_numeric_create(6, -1),
960  ans, a, b, "expected %s got %s = %s * %s for reciprocal");
961 
962  /* check gnc_numeric_div */
963  /* -60 / 20 = -3 */
964  a = gnc_numeric_create(-60, 1);
965  b = gnc_numeric_create(2, -10);
967  check_binary_op (gnc_numeric_create(-3, -1),
968  ans, a, b, "expected %s got %s = %s / %s for reciprocal");
969 
970  /* 60 / 20 = 3 */
971  a = gnc_numeric_create(60, 1);
972  b = gnc_numeric_create(2, -10);
974  check_binary_op (gnc_numeric_create(3, -1),
975  ans, a, b, "expected %s got %s = %s / %s for reciprocal");
976 
977 
978 }
979 
980 /* ======================================================= */
981 
982 static void
983 run_test (void)
984 {
985  check_eq_operator ();
986  check_reduce ();
987  check_equality_operator ();
988  check_rounding();
989  check_double();
990  check_neg();
991  check_add_subtract();
992  check_add_subtract_overflow ();
993  check_mult_div ();
994  check_reciprocal();
995 }
996 
997 int
998 main (int argc, char **argv)
999 {
1000  qof_init();
1001  if (cashobjects_register())
1002  {
1003  run_test ();
1004  print_test_results();
1005  }
1006  qof_close();
1007  return get_rv();
1008 }
1009 
1010 /* ======================== END OF FILE ====================== */
gnc_numeric gnc_numeric_mul_with_error(gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
gnc_numeric double_to_gnc_numeric(double n, gint64 denom, gint how)
gnc_numeric gnc_numeric_add_with_error(gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_neg(gnc_numeric a)
An exact-rational-number library for gnucash. (to be renamed qofnumeric.h in libqof2) ...
GNCNumericErrorCode
Definition: gnc-numeric.h:222
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
gchar * gnc_numeric_to_string(gnc_numeric n)
gnc_numeric gnc_numeric_sub_with_error(gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)
gnc_numeric gnc_numeric_reduce(gnc_numeric n)
gdouble gnc_numeric_to_double(gnc_numeric n)
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
#define GNC_DENOM_RECIPROCAL(a)
Definition: gnc-numeric.h:249
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
gnc_numeric gnc_numeric_error(GNCNumericErrorCode error_code)
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
void qof_close(void)
Safely close down the Query Object Framework.
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
void qof_init(void)
Initialise the Query Object Framework.
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
#define GNC_HOW_DENOM_SIGFIGS(n)
Definition: gnc-numeric.h:218
gnc_numeric gnc_numeric_div_with_error(gnc_numeric a, gnc_numeric b, gint64 denom, gint how, gnc_numeric *error)