QOF  0.7.5
test-numeric.c
1 /***************************************************************************
2  * test-numeric.c
3  *
4  * Test file created by Linas Vepstas <linas@linas.org>
5  * Review operation of the gnc-numeric tools by verifying results
6  * of various operations.
7  *
8  * June 2004
9  * Copyright 2004 Linas Vepstas <linas@linas.org>
10  ****************************************************************************/
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25  * 02110-1301, USA.
26  */
27 
28 #include <ctype.h>
29 #include <glib.h>
30 #include "qof.h"
31 #include "test-stuff.h"
32 #include "test-engine-stuff.h"
33 #include "qofnumeric.h"
34 
35 #define NREPS 2000
36 
37 static char *
38 qof_numeric_print (QofNumeric in)
39 {
40  char *retval;
41  if (qof_numeric_check (in))
42  {
43  retval =
44  g_strdup_printf ("<ERROR> [%" G_GINT64_FORMAT " / %"
45  G_GINT64_FORMAT "]", in.num, in.denom);
46  }
47  else
48  {
49  retval =
50  g_strdup_printf ("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
51  in.num, in.denom);
52  }
53  return retval;
54 }
55 
56 /* ======================================================= */
57 
58 static void
59 check_unary_op (gboolean (*eqtest) (QofNumeric, QofNumeric),
60  QofNumeric expected,
61  QofNumeric actual, QofNumeric input, const gchar *errmsg)
62 {
63  gchar *e = qof_numeric_print (expected);
64  gchar *r = qof_numeric_print (actual);
65  gchar *a = qof_numeric_print (input);
66  gchar *str = g_strdup_printf (errmsg, e, r, a);
67 
68  do_test (eqtest (expected, actual), str);
69 
70  g_free (a);
71  g_free (r);
72  g_free (e);
73  g_free (str);
74 }
75 
76 /* ======================================================= */
77 
78 static void
79 check_binary_op (QofNumeric expected,
80  QofNumeric actual,
81  QofNumeric input_a, QofNumeric input_b, const gchar *errmsg)
82 {
83  gchar *e = qof_numeric_print (expected);
84  gchar *r = qof_numeric_print (actual);
85  gchar *a = qof_numeric_print (input_a);
86  gchar *b = qof_numeric_print (input_b);
87  gchar *str = g_strdup_printf (errmsg, e, r, a, b);
88 
89  do_test (qof_numeric_eq (expected, actual), str);
90 
91  g_free (a);
92  g_free (b);
93  g_free (r);
94  g_free (e);
95  g_free (str);
96 }
97 
98 /* ======================================================= */
99 
100 static gboolean
101 qof_numeric_unequal (QofNumeric a, QofNumeric b)
102 {
103  return (0 == qof_numeric_equal (a, b));
104 }
105 
106 /* ======================================================= */
107 
108 /* Make sure that the equivalence operator we use for
109  * later tests actually works */
110 static void
111 check_eq_operator (void)
112 {
113  QofNumeric a = qof_numeric_create (42, 58);
114  QofNumeric b = qof_numeric_create (42, 58);
115  QofNumeric c = qof_numeric_create (40, 58);
116 
117  /* Check strict equivalence and non-equivalence */
118  do_test (qof_numeric_eq (a, a), "expected self-equivalence");
119  do_test (qof_numeric_eq (a, b), "expected equivalence");
120  do_test (0 == qof_numeric_eq (a, c), "expected inequivalence");
121 }
122 
123 /* ======================================================= */
124 
125 static void
126 check_reduce (void)
127 {
128  QofNumeric one, rone;
129  QofNumeric four, rfour;
130  QofNumeric val, rval;
131  /* Check common factor elimination (needed for equality checks) */
132  one = qof_numeric_create (1, 1);
133  rone = qof_numeric_create (1000000, 1000000);
134  rone = qof_numeric_reduce (rone);
135  do_test (qof_numeric_eq (one, rone), "reduce to one");
136 
137  four = qof_numeric_create (4, 1);
138  rfour = qof_numeric_create (480, 120);
139  rfour = qof_numeric_reduce (rfour);
140  do_test (qof_numeric_eq (four, rfour), "reduce to four");
141 
142  val = qof_numeric_create (10023234LL, 334216654LL);
143  rval = qof_numeric_reduce (val);
144  check_unary_op (qof_numeric_eq,
145  qof_numeric_create (5011617, 167108327),
146  rval,
147  val, "check_reduce(1) expected %s = %s = reduce(%s)");
148 
149  val = qof_numeric_create (17474724864LL, 136048896LL);
150  rval = qof_numeric_reduce (val);
151  check_unary_op (qof_numeric_eq,
152  qof_numeric_create (4 * 17 * 17, 9),
153  rval,
154  val, "check_reduce(2) expected %s = %s = reduce(%s)");
155 
156  val = qof_numeric_create (1024LL, 1099511627776LL);
157  rval = qof_numeric_reduce (val);
158  check_unary_op (qof_numeric_eq,
159  qof_numeric_create (1, 1024 * 1024 * 1024),
160  rval,
161  val, "check_reduce(3): expected %s = %s = reduce(%s)");
162 }
163 
164 /* ======================================================= */
165 
166 static void
167 check_equality_operator (void)
168 {
169  gint i, m;
170  gint mult;
171  gint64 f, deno, numer;
172  QofNumeric big, rbig;
173  QofNumeric val, mval;
174  QofNumeric bval, rval;
175  /* Check equality operator for some large numer/denom values */
176  numer = 1 << 30;
177  numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
178  deno = 1 << 30;
179  deno <<= 20;
180  rbig = qof_numeric_create (numer, deno);
181 
182  big = qof_numeric_create (1 << 10, 1);
183  do_test (qof_numeric_equal (big, rbig), "equal to billion");
184 
185  big = qof_numeric_create (1 << 20, 1 << 10);
186  do_test (qof_numeric_equal (big, rbig), "equal to 1<<20/1<<10");
187 
188  big = qof_numeric_create (1 << 30, 1 << 20);
189  do_test (qof_numeric_equal (big, rbig), "equal to 1<<30/1<<20");
190 
191  numer = 1 << 30;
192  numer <<= 30; /* we don't trust cpp to compute 1<<60 correctly */
193  deno = 1 << 30;
194  rbig = qof_numeric_create (numer, deno);
195 
196  big = qof_numeric_create (1 << 30, 1);
197  do_test (qof_numeric_equal (big, rbig), "equal to 1<<30");
198 
199  numer = 1 << 30;
200  numer <<= 10;
201  big = qof_numeric_create (numer, 1 << 10);
202  do_test (qof_numeric_equal (big, rbig), "equal to 1<<40/1<<10");
203 
204  numer <<= 10;
205  big = qof_numeric_create (numer, 1 << 20);
206  do_test (qof_numeric_equal (big, rbig), "equal to 1<<50/1<<20");
207 
208  /* We assume RAND_MAX is less that 1<<32 */
209  for (i = 0; i < NREPS; i++)
210  {
211  deno = rand () / 2;
212  mult = rand () / 2;
213  numer = rand () / 2;
214 
215  val = qof_numeric_create (numer, deno);
216  mval = qof_numeric_create (numer * mult, deno * mult);
217 
218  /* The reduced version should be equivalent */
219  bval = qof_numeric_reduce (val);
220  rval = qof_numeric_reduce (mval);
221  check_unary_op (qof_numeric_eq,
222  bval, rval, mval, "expected %s = %s = reduce(%s)");
223 
224  /* The unreduced versions should be equal */
225  check_unary_op (qof_numeric_equal,
226  val, mval, mval, "expected %s = %s");
227 
228  /* Certain modulo's should be very cleary un-equal; this
229  * helps stop funky modulo-64 aliasing in compares that
230  * might creep in. */
231  mval.denom >>= 1;
232  mval.num >>= 1;
233  m = 0;
234  f = mval.denom;
235  while (f % 2 == 0)
236  {
237  f >>= 1;
238  m++;
239  }
240  if (1 < m)
241  {
242  gint64 nn = 1 << (32 - m);
243  nn <<= 32;
244  nn += mval.num;
245  val = qof_numeric_create (2 * nn, 2 * mval.denom);
246  check_unary_op (qof_numeric_unequal,
247  val, mval, mval, "expected unequality %s != %s");
248 
249  }
250  }
251 }
252 
253 /* ======================================================= */
254 
255 static void
256 check_rounding (void)
257 {
258  QofNumeric val;
259 
260  val = qof_numeric_create (7, 16);
261  check_unary_op (qof_numeric_eq,
262  qof_numeric_create (43, 100),
264  val, "expected %s = %s = (%s as 100th's floor)");
265  check_unary_op (qof_numeric_eq,
266  qof_numeric_create (44, 100),
268  val, "expected %s = %s = (%s as 100th's ceiling)");
269  check_unary_op (qof_numeric_eq,
270  qof_numeric_create (43, 100),
272  val, "expected %s = %s = (%s as 100th's trunc)");
273  check_unary_op (qof_numeric_eq,
274  qof_numeric_create (44, 100),
276  val, "expected %s = %s = (%s as 100th's round)");
277 
278  val = qof_numeric_create (1511, 1000);
279  check_unary_op (qof_numeric_eq,
280  qof_numeric_create (151, 100),
282  val, "expected %s = %s = (%s as 100th's round)");
283 
284  val = qof_numeric_create (1516, 1000);
285  check_unary_op (qof_numeric_eq,
286  qof_numeric_create (152, 100),
288  val, "expected %s = %s = (%s as 100th's round)");
289 
290  /* Half-values always get rounded to nearest even number */
291  val = qof_numeric_create (1515, 1000);
292  check_unary_op (qof_numeric_eq,
293  qof_numeric_create (152, 100),
295  val, "expected %s = %s = (%s as 100th's round)");
296 
297  val = qof_numeric_create (1525, 1000);
298  check_unary_op (qof_numeric_eq,
299  qof_numeric_create (152, 100),
301  val, "expected %s = %s = (%s as 100th's round)");
302 
303  val = qof_numeric_create (1535, 1000);
304  check_unary_op (qof_numeric_eq,
305  qof_numeric_create (154, 100),
307  val, "expected %s = %s = (%s as 100th's round)");
308 
309  val = qof_numeric_create (1545, 1000);
310  check_unary_op (qof_numeric_eq,
311  qof_numeric_create (154, 100),
313  val, "expected %s = %s = (%s as 100th's round)");
314 }
315 
316 /* ======================================================= */
317 
318 static void
319 check_double (void)
320 {
321  gdouble flo;
322  QofNumeric val = qof_numeric_create (0, 1);
323 
324  check_unary_op (qof_numeric_eq,
325  qof_numeric_create (112346, 100000),
326  qof_numeric_from_double (1.1234567890123,
330  val, "expected %s = %s double 6 figs");
331 
332  check_unary_op (qof_numeric_eq,
333  qof_numeric_create (112346, 10000000),
334  qof_numeric_from_double (0.011234567890123,
338  val, "expected %s = %s double 6 figs");
339 
340  check_unary_op (qof_numeric_eq,
341  qof_numeric_create (112346, 100),
342  qof_numeric_from_double (1123.4567890123,
346  val, "expected %s = %s double 6 figs");
347  check_unary_op (qof_numeric_eq,
348  qof_numeric_create (112346, 10000000000LL),
349  qof_numeric_from_double (1.1234567890123e-5,
353  val, "expected %s = %s double 6 figs");
354 
356  do_test ((0.4375 == flo), "float pt conversion");
357 }
358 
359 /* ======================================================= */
360 
361 static void
362 check_neg (void)
363 {
364  QofNumeric a = qof_numeric_create (2, 6);
365  QofNumeric b = qof_numeric_create (1, 4);
366  QofNumeric c = qof_numeric_neg (a);
367  QofNumeric d = qof_numeric_neg (b);
368 
369  check_unary_op (qof_numeric_eq,
370  qof_numeric_create (-2, 6), c,
371  a, "expected %s = %s = -(%s)");
372 
373  check_unary_op (qof_numeric_eq,
374  qof_numeric_create (-1, 4), d,
375  b, "expected %s = %s = -(%s)");
376 
377 }
378 
379 /* ======================================================= */
380 
381 static void
382 check_add_subtract (void)
383 {
384  gint i;
385  QofNumeric a, b, c, d, z;
386 #if CHECK_ERRORS_TOO
387  QofNumeric c;
388 #endif
389 
390  a = qof_numeric_create (2, 6);
391  b = qof_numeric_create (1, 4);
392 
393  /* Well, actually 14/24 would be acceptable/better in this case */
394  check_binary_op (qof_numeric_create (7, 12),
396  QOF_HOW_DENOM_EXACT), a, b,
397  "expected %s got %s = %s + %s for add exact");
398 
399  check_binary_op (qof_numeric_create (58, 100),
400  qof_numeric_add (a, b, 100, QOF_HOW_RND_ROUND),
401  a, b,
402  "expected %s got %s = %s + %s for add 100ths (banker's)");
403 
404  check_binary_op (qof_numeric_create (5833, 10000),
408  a, b, "expected %s got %s = %s + %s for add 4 sig figs");
409 
410  check_binary_op (qof_numeric_create (583333, 1000000),
414  a, b, "expected %s got %s = %s + %s for add 6 sig figs");
415 
416  check_binary_op (qof_numeric_create (1, 12),
418  QOF_HOW_DENOM_EXACT), a, b,
419  "expected %s got %s = %s - %s for sub exact");
420 
421  /* We should try something trickier for reduce & lcd */
422  check_binary_op (qof_numeric_create (1, 12),
424  QOF_HOW_DENOM_REDUCE), a, b,
425  "expected %s got %s = %s - %s for sub reduce");
426 
427  check_binary_op (qof_numeric_create (1, 12),
429  QOF_HOW_DENOM_LCD), a, b,
430  "expected %s got %s = %s - %s for sub reduce");
431 
432  check_binary_op (qof_numeric_create (8, 100),
433  qof_numeric_sub (a, b, 100, QOF_HOW_RND_ROUND),
434  a, b,
435  "expected %s got %s = %s - %s for sub 100ths (banker's)");
436 
437  /* ------------------------------------------------------------ */
438  /* This test has failed before */
439  c = qof_numeric_neg (a);
440  d = qof_numeric_neg (b);
441  z = qof_numeric_zero ();
442  check_binary_op (c, qof_numeric_add_fixed (z, c),
443  z, c, "expected %s got %s = %s + %s for add fixed");
444 
445  check_binary_op (d, qof_numeric_add_fixed (z, d),
446  z, d, "expected %s got %s = %s + %s for add fixed");
447 
448  /* ------------------------------------------------------------ */
449  /* Same as above, but with signs reviersed */
450  a = c;
451  b = d;
452  /* Well, actually 14/24 would be acceptable/better in this case */
453  check_binary_op (qof_numeric_create (-7, 12),
455  QOF_HOW_DENOM_EXACT), a, b,
456  "expected %s got %s = %s + %s for add exact");
457 
458  check_binary_op (qof_numeric_create (-58, 100),
459  qof_numeric_add (a, b, 100, QOF_HOW_RND_ROUND),
460  a, b,
461  "expected %s got %s = %s + %s for add 100ths (banker's)");
462 
463  check_binary_op (qof_numeric_create (-5833, 10000),
467  a, b, "expected %s got %s = %s + %s for add 4 sig figs");
468 
469  check_binary_op (qof_numeric_create (-583333, 1000000),
473  a, b, "expected %s got %s = %s + %s for add 6 sig figs");
474 
475  check_binary_op (qof_numeric_create (-1, 12),
477  QOF_HOW_DENOM_EXACT), a, b,
478  "expected %s got %s = %s - %s for sub exact");
479 
480  /* We should try something trickier for reduce & lcd */
481  check_binary_op (qof_numeric_create (-1, 12),
483  QOF_HOW_DENOM_REDUCE), a, b,
484  "expected %s got %s = %s - %s for sub reduce");
485 
486  check_binary_op (qof_numeric_create (-1, 12),
488  QOF_HOW_DENOM_LCD), a, b,
489  "expected %s got %s = %s - %s for sub reduce");
490 
491  check_binary_op (qof_numeric_create (-8, 100),
492  qof_numeric_sub (a, b, 100, QOF_HOW_RND_ROUND),
493  a, b,
494  "expected %s got %s = %s - %s for sub 100ths (banker's)");
495 
496  /* ------------------------------------------------------------ */
497 #if CHECK_ERRORS_TOO
498  c = qof_numeric_add_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
499  printf ("add 100ths/error : %s + %s = %s + (error) %s\n\n",
500  qof_numeric_print (a), qof_numeric_print (b),
501  qof_numeric_print (c), qof_numeric_print (err));
502 
503  c = qof_numeric_sub_with_error (a, b, 100, QOf_HOW_RND_FLOOR, &err);
504  printf ("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
505  qof_numeric_print (a), qof_numeric_print (b),
506  qof_numeric_print (c), qof_numeric_print (err));
507 
508 #endif
509 
510  /* ------------------------------------------------------------ */
511  /* Add and subtract some random numbers */
512  for (i = 0; i < NREPS; i++)
513  {
514  QofNumeric e;
515  gint64 deno = rand () + 1;
516  gint64 na = get_random_gint64 ();
517  gint64 nb = get_random_gint64 ();
518  gint64 ne;
519 
520  /* avoid overflow; */
521  na /= 2;
522  nb /= 2;
523 
524  a = qof_numeric_create (na, deno);
525  b = qof_numeric_create (nb, deno);
526 
527  /* Add */
528  ne = na + nb;
529  e = qof_numeric_create (ne, deno);
530  check_binary_op (e,
532  QOF_HOW_DENOM_EXACT), a, b,
533  "expected %s got %s = %s + %s for exact addition");
534 
535  /* Subtract */
536  ne = na - nb;
537  e = qof_numeric_create (ne, deno);
538  check_binary_op (e,
540  QOF_HOW_DENOM_EXACT), a, b,
541  "expected %s got %s = %s - %s for exact subtraction");
542  }
543 }
544 
545 /* ======================================================= */
546 
547 static void
548 check_mult_div (void)
549 {
550  gint i, j;
551  gint64 v;
552  QofNumeric c, d;
553  QofNumeric amt_a, amt_tot, frac, val_tot, val_a;
554  QofNumeric a, b;
555 
556  a = qof_numeric_create (-100, 100);
557  b = qof_numeric_create (1, 1);
558  check_binary_op (qof_numeric_create (-100, 100),
560  QOF_HOW_DENOM_EXACT), a, b,
561  "expected %s got %s = %s / %s div exact");
562 
563  a = qof_numeric_create (-100, 100);
564  b = qof_numeric_create (-1, 1);
565  check_binary_op (qof_numeric_create (100, 100),
567  QOF_HOW_DENOM_EXACT), a, b,
568  "expected %s got %s = %s / %s div exact");
569 
570  a = qof_numeric_create (-100, 100);
571  b = qof_numeric_create (-1, 1);
572  check_binary_op (qof_numeric_create (100, 100),
574  QOF_HOW_DENOM_EXACT), a, b,
575  "expected %s got %s = %s * %s mult exact");
576 
577  a = qof_numeric_create (2, 6);
578  b = qof_numeric_create (1, 4);
579 
580  check_binary_op (qof_numeric_create (2, 24),
582  QOF_HOW_DENOM_EXACT), a, b,
583  "expected %s got %s = %s * %s for mult exact");
584 
585  check_binary_op (qof_numeric_create (1, 12),
587  QOF_HOW_DENOM_REDUCE), a, b,
588  "expected %s got %s = %s * %s for mult reduce");
589 
590  check_binary_op (qof_numeric_create (8, 100),
591  qof_numeric_mul (a, b, 100, QOF_HOW_RND_ROUND),
592  a, b, "expected %s got %s = %s * %s for mult 100th's");
593 
594  check_binary_op (qof_numeric_create (8, 6),
596  QOF_HOW_DENOM_EXACT), a, b,
597  "expected %s got %s = %s / %s for div exact");
598 
599  check_binary_op (qof_numeric_create (4, 3),
601  QOF_HOW_DENOM_REDUCE), a, b,
602  "expected %s got %s = %s / %s for div reduce");
603 
604  check_binary_op (qof_numeric_create (133, 100),
605  qof_numeric_div (a, b, 100, QOF_HOW_RND_ROUND),
606  a, b, "expected %s got %s = %s * %s for div 100th's");
607 
608 #if CHECK_ERRORS_TOO
609  QofNumeric c;
610  c = qof_numeric_mul_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
611  printf ("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
612  qof_numeric_print (a), qof_numeric_print (b),
613  qof_numeric_print (c), qof_numeric_print (err));
614 
615  c = qof_numeric_div_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
616  printf ("div 100ths/error : %s / %s = %s + (error) %s\n\n",
617  qof_numeric_print (a), qof_numeric_print (b),
618  qof_numeric_print (c), qof_numeric_print (err));
619 
620 #endif
621 
622  /* Check for math with 2^63 < num*num < 2^64 which previously failed
623  * see http://bugzilla.gnome.org/show_bug.cgi?id=144980
624  */
625  v = 1000000;
626  a = qof_numeric_create (1 * v, v);
627  b = qof_numeric_create (10000000 * v, v);
628 
629  check_binary_op (b,
631  QOF_HOW_DENOM_LCD), a, b,
632  "expected %s got %s = %s * %s for multiply");
633 
634  /* Multiply some random numbers. This test presumes that
635  * RAND_MAX is approx 2^32
636  */
637  for (i = 0; i < NREPS; i++)
638  {
639  gint64 deno = 1;
640  gint64 na = rand ();
641  gint64 nb = rand ();
642  gint64 ne;
643 
644  /* avoid overflow; */
645  na /= 2;
646  nb /= 2;
647  ne = na * nb;
648 
649  a = qof_numeric_create (na, deno);
650  b = qof_numeric_create (nb, deno);
651 
652  check_binary_op (qof_numeric_create (ne, 1),
654  QOF_HOW_DENOM_EXACT), a, b,
655  "expected %s got %s = %s * %s for mult exact");
656 
657  /* Force 128-bit math to come into play */
658  for (j = 1; j < 31; j++)
659  {
660  a = qof_numeric_create (na << j, 1 << j);
661  b = qof_numeric_create (nb << j, 1 << j);
662  check_binary_op (qof_numeric_create (ne, 1),
664  QOF_HOW_DENOM_REDUCE), a, b,
665  "expected %s got %s = %s * %s for mult reduce");
666  }
667 
668  /* Do some hokey random 128-bit division too */
669  b = qof_numeric_create (deno, nb);
670 
671  check_binary_op (qof_numeric_create (ne, 1),
673  QOF_HOW_DENOM_EXACT), a, b,
674  "expected %s got %s = %s / %s for div exact");
675 
676  /* avoid overflow; */
677  na /= 2;
678  nb /= 2;
679  ne = na * nb;
680  for (j = 1; j < 16; j++)
681  {
682  a = qof_numeric_create (na << j, 1 << j);
683  b = qof_numeric_create (1 << j, nb << j);
684  check_binary_op (qof_numeric_create (ne, 1),
686  QOF_HOW_DENOM_REDUCE), a, b,
687  "expected %s got %s = %s / %s for div reduce");
688  }
689  }
690 
691  a = qof_numeric_create (782592055622866ULL, 89025);
692  b = qof_numeric_create (2222554708930978ULL, 85568);
693  /* Dividing the above pair overflows, in that after
694  * the division the denominator won't fit into a
695  * 64-bit quantity. This can be seen from
696  * the factorization int primes:
697  * 782592055622866 = 2 * 2283317 * 171371749
698  * (yes, thats a seven and a nine digit prime)
699  * 2222554708930978 = 2 * 1111277354465489
700  * (yes, that's a sixteen-digit prime number)
701  * 89025 = 3*5*5*1187
702  * 85568= 64*7*191
703  * If the rounding method is exact/no-round, then
704  * an overflow error should be signalled; else the
705  * divide routine should shift down the results till
706  * the overflow is eliminated.
707  *
708  */
709  check_binary_op (qof_numeric_error (QOF_ERROR_OVERFLOW),
712  QOF_HOW_DENOM_EXACT), a, b,
713  "expected %s got %s = %s / %s for div exact");
714 
715  check_binary_op (qof_numeric_create (338441, 1000000),
718  QOF_HOW_RND_ROUND), a, b,
719  "expected %s got %s = %s / %s for div round");
720 
721  /* Below is a 'typical' value calculation:
722  * value_frac = value_tot * amt_frace / amt_tot
723  * and has some typical potential-overflow values.
724  * 82718 = 2 * 59 * 701
725  * 47497125586 = 2 * 1489 * 15949337
726  * 69100955 = 5 * 7 * 11 * 179483
727  * 32005637020 = 4 * 5 * 7 * 43 * 71 * 103 * 727
728  */
729  a = qof_numeric_create (-47497125586LL, 82718);
730  b = qof_numeric_create (-69100955LL, 55739);
732  d = qof_numeric_create (-32005637020LL, 55739);
733 
734  check_binary_op (qof_numeric_create (-102547458LL, 82718),
735  qof_numeric_div (c, d, 82718,
737  c, d, "expected %s got %s = %s / %s for div round");
738 
739  /* If we specify QOF_HOW_RND_NEVER, then we should get an error,
740  * since the exact result won't fit into a 64-bit quantity. */
741  check_binary_op (qof_numeric_error (QOF_ERROR_REMAINDER),
742  qof_numeric_div (c, d, 82718,
744  QOF_HOW_RND_NEVER), c, d,
745  "expected %s got %s = %s / %s for div round");
746 
747  /* A simple irreducible ratio, involving negative numbers */
748  amt_a = qof_numeric_create (-6005287905LL, 40595);
749  amt_tot = qof_numeric_create (-8744187958LL, 40595);
750  frac = qof_numeric_div (amt_a, amt_tot,
752 
753  check_binary_op (qof_numeric_create (6005287905LL, 8744187958LL),
754  frac, amt_a, amt_tot,
755  "expected %s got %s = %s / %s for div reduce");
756 
757  /* Another overflow-prone condition */
758  val_tot = qof_numeric_create (-4280656418LL, 19873);
759  val_a = qof_numeric_mul (frac, val_tot,
760  qof_numeric_denom (val_tot),
762  check_binary_op (qof_numeric_create (-2939846940LL, 19873),
763  val_a, val_tot, frac,
764  "expected %s got %s = %s * %s for mult round");
765 
766  frac = qof_numeric_create (396226789777979LL, 328758834367851752LL);
767  val_tot = qof_numeric_create (467013515494988LL, 100);
768  val_a = qof_numeric_mul (frac, val_tot,
769  qof_numeric_denom (val_tot),
771  check_binary_op (qof_numeric_create (562854125307LL, 100),
772  val_a, val_tot, frac,
773  "expected %s got %s = %s * %s for mult round");
774 
775  /* Yet another bug from bugzilla ... */
776  a = qof_numeric_create (40066447153986554LL, 4518);
777  b = qof_numeric_create (26703286457229LL, 3192);
778  frac = qof_numeric_div (a, b,
781 
782  check_binary_op (qof_numeric_create (106007, 100),
783  frac, a, b,
784  "expected %s got %s = %s / %s for mult sigfigs");
785 
786 }
787 
788 static void
789 check_reciprocal (void)
790 {
791  QofNumeric a, b, ans, val;
792  gdouble flo;
793 
794  val = qof_numeric_create (-60, 20);
795  check_unary_op (qof_numeric_eq, qof_numeric_create (-3, -1),
798  val, "expected %s = %s = (%s as RECIP(1))");
799 
800  a = qof_numeric_create (200, 100);
801  b = qof_numeric_create (300, 100);
802 
803  /* 2 + 3 = 5 */
805  check_binary_op (qof_numeric_create (5, -1),
806  ans, a, b,
807  "expected %s got %s = %s + %s for reciprocal");
808 
809  /* 2 + 3 = 5 */
810  a = qof_numeric_create (2, -1);
811  b = qof_numeric_create (300, 100);
813  check_binary_op (qof_numeric_create (5, -1),
814  ans, a, b,
815  "expected %s got %s = %s + %s for reciprocal");
816 
817 
818  /* 2 + 3 = 5 */
819  a = qof_numeric_create (2, -1);
820  b = qof_numeric_create (300, 100);
822  check_binary_op (qof_numeric_create (5, -1),
823  ans, a, b, "expected %s got %s = %s + %s for recirocal");
824 
825  /* check gnc_numeric_to_double */
827  do_test ((5.0 == flo), "reciprocal conversion");
828 
829  /* check gnc_numeric_compare */
830  a = qof_numeric_create (2, 1);
831  b = qof_numeric_create (2, -1);
832  do_test ((0 == qof_numeric_compare (a, b)), " 2 == 2 ");
833  a = qof_numeric_create (2, 1);
834  b = qof_numeric_create (3, -1);
835  do_test ((-1 == qof_numeric_compare (a, b)), " 2 < 3 ");
836  a = qof_numeric_create (-2, 1);
837  b = qof_numeric_create (2, -1);
838  do_test ((-1 == qof_numeric_compare (a, b)), " -2 < 2 ");
839  a = qof_numeric_create (2, -1);
840  b = qof_numeric_create (3, -1);
841  do_test ((-1 == qof_numeric_compare (a, b)), " 2 < 3 ");
842 
843  /* check for equality */
844  a = qof_numeric_create (2, 1);
845  b = qof_numeric_create (2, -1);
846  do_test (qof_numeric_equal (a, b), " 2 == 2 ");
847 
848  /* check gnc_numeric_mul */
849  a = qof_numeric_create (2, 1);
850  b = qof_numeric_create (3, -1);
852  check_binary_op (qof_numeric_create (6, -1),
853  ans, a, b, "expected %s got %s = %s * %s for recirocal");
854 
855  /* check gnc_numeric_div */
856  /* -60 / 20 = -3 */
857  a = qof_numeric_create (-60, 1);
858  b = qof_numeric_create (2, -10);
860  check_binary_op (qof_numeric_create (-3, -1),
861  ans, a, b, "expected %s got %s = %s / %s for recirocal");
862 
863  /* 60 / 20 = 3 */
864  a = qof_numeric_create (60, 1);
865  b = qof_numeric_create (2, -10);
867  check_binary_op (qof_numeric_create (3, -1),
868  ans, a, b, "expected %s got %s = %s / %s for recirocal");
869 
870 }
871 
872 
873 /* ======================================================= */
874 
875 static void
876 run_test (void)
877 {
878  check_eq_operator ();
879  check_reduce ();
880  check_equality_operator ();
881  check_rounding ();
882  check_double ();
883  check_neg ();
884  check_add_subtract ();
885  check_mult_div ();
886  check_reciprocal ();
887 }
888 
889 int
890 main (void)
891 {
892  qof_init ();
893  run_test ();
894 
895  print_test_results ();
896  exit (get_rv ());
897  qof_close ();
898  return get_rv();
899 }
900 
901 /* ======================== END OF FILE ====================== */