GnuCash 2.4.99
test-numeric.c
00001 
00002 /* Test file created by Linas Vepstas <linas@linas.org>
00003  * Review operation of the gnc-numeric tools by verifying results
00004  * of vairous operations.
00005  *
00006  * June 2004
00007  */
00008 /*
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00022  *  02110-1301, USA.
00023  */
00024 
00025 
00026 #include "config.h"
00027 #include <ctype.h>
00028 #include <glib.h>
00029 #include "cashobjects.h"
00030 #include "test-stuff.h"
00031 #include "test-engine-stuff.h"
00032 #include "gnc-numeric.h"
00033 
00034 #define NREPS 2000
00035 
00036 static char *
00037 gnc_numeric_print(gnc_numeric in)
00038 {
00039     char * retval;
00040     if (gnc_numeric_check(in))
00041     {
00042         retval = g_strdup_printf("<ERROR> [%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
00043                                  in.num,
00044                                  in.denom);
00045     }
00046     else
00047     {
00048         retval = g_strdup_printf("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT "]",
00049                                  in.num,
00050                                  in.denom);
00051     }
00052     return retval;
00053 }
00054 
00055 /* ======================================================= */
00056 
00057 #define check_unary_op(eq,ex,a,i,e) check_unary_op_r(eq,ex,a,i,e,__LINE__)
00058 static void
00059 check_unary_op_r (gboolean (*eqtest) (gnc_numeric, gnc_numeric),
00060                   gnc_numeric expected,
00061                   gnc_numeric actual,
00062                   gnc_numeric input,
00063                   const char * errmsg,
00064                   int line)
00065 {
00066     char *e = gnc_numeric_print (expected);
00067     char *r = gnc_numeric_print (actual);
00068     char *a = gnc_numeric_print (input);
00069     char *str = g_strdup_printf (errmsg, e, r, a);
00070 
00071     do_test_call (eqtest(expected, actual), str, __FILE__, line);
00072 
00073     g_free (a);
00074     g_free (r);
00075     g_free (e);
00076     g_free (str);
00077 }
00078 
00079 /* ======================================================= */
00080 
00081 #define check_binary_op(ex,a,ia,ib,e) check_binary_op_r(ex,a,ia,ib,e,__LINE__,gnc_numeric_eq)
00082 #define check_binary_op_equal(ex,a,ia,ib,e) check_binary_op_r(ex,a,ia,ib,e,__LINE__,gnc_numeric_equal)
00083 static void
00084 check_binary_op_r (gnc_numeric expected,
00085                    gnc_numeric actual,
00086                    gnc_numeric input_a,
00087                    gnc_numeric input_b,
00088                    const char * errmsg,
00089                    int line,
00090                    gboolean (*eq)(gnc_numeric, gnc_numeric))
00091 {
00092     char *e = gnc_numeric_print (expected);
00093     char *r = gnc_numeric_print (actual);
00094     char *a = gnc_numeric_print (input_a);
00095     char *b = gnc_numeric_print (input_b);
00096     char *str = g_strdup_printf (errmsg, e, r, a, b);
00097 
00098     do_test_call ((eq)(expected, actual), str, __FILE__, line);
00099 
00100     g_free (a);
00101     g_free (b);
00102     g_free (r);
00103     g_free (e);
00104     g_free (str);
00105 }
00106 
00107 /* ======================================================= */
00108 
00109 static gboolean
00110 gnc_numeric_unequal (gnc_numeric a, gnc_numeric b)
00111 {
00112     return (0 == gnc_numeric_equal (a, b));
00113 }
00114 
00115 /* ======================================================= */
00116 
00117 /* Make sure that the equivalence operator we use for
00118  * later tests actually works */
00119 static void
00120 check_eq_operator (void)
00121 {
00122     gnc_numeric a = gnc_numeric_create (42, 58);
00123     gnc_numeric b = gnc_numeric_create (42, 58);
00124     gnc_numeric c = gnc_numeric_create (40, 58);
00125 
00126     /* Check strict equivalence and non-equivalence */
00127     do_test (gnc_numeric_eq(a, a), "expected self-equivalence");
00128     do_test (gnc_numeric_eq(a, b), "expected equivalence");
00129     do_test (0 == gnc_numeric_eq(a, c), "expected inequivalence");
00130 }
00131 
00132 /* ======================================================= */
00133 
00134 static void
00135 check_reduce (void)
00136 {
00137     gnc_numeric one, rone;
00138     gnc_numeric four, rfour;
00139     gnc_numeric val, rval;
00140     /* Check common factor elimination (needed for equality checks) */
00141     one = gnc_numeric_create (1, 1);
00142     rone = gnc_numeric_create (1000000, 1000000);
00143     rone = gnc_numeric_reduce (rone);
00144     do_test (gnc_numeric_eq(one, rone), "reduce to one");
00145 
00146     four = gnc_numeric_create (4, 1);
00147     rfour = gnc_numeric_create (480, 120);
00148     rfour = gnc_numeric_reduce (rfour);
00149     do_test (gnc_numeric_eq(four, rfour), "reduce to four");
00150 
00151     val = gnc_numeric_create(10023234LL, 334216654LL);
00152     rval = gnc_numeric_reduce (val);
00153     check_unary_op (gnc_numeric_eq,
00154                     gnc_numeric_create (5011617, 167108327),
00155                     rval,
00156                     val, "check_reduce(1) expected %s = %s = reduce(%s)");
00157 
00158     val = gnc_numeric_create(17474724864LL, 136048896LL);
00159     rval = gnc_numeric_reduce (val);
00160     check_unary_op (gnc_numeric_eq,
00161                     gnc_numeric_create (4 * 17 * 17, 9),
00162                     rval,
00163                     val, "check_reduce(2) expected %s = %s = reduce(%s)");
00164 
00165     val = gnc_numeric_create(1024LL, 1099511627776LL);
00166     rval = gnc_numeric_reduce (val);
00167     check_unary_op (gnc_numeric_eq,
00168                     gnc_numeric_create (1, 1024 * 1024 * 1024),
00169                     rval,
00170                     val, "check_reduce(3): expected %s = %s = reduce(%s)");
00171 }
00172 
00173 /* ======================================================= */
00174 
00175 static void
00176 check_equality_operator (void)
00177 {
00178     int i, m;
00179     gint mult;
00180     gint64 f, deno, numer;
00181     gnc_numeric big, rbig;
00182     gnc_numeric val, mval;
00183     gnc_numeric bval, rval;
00184     /* Check equality operator for some large numer/denom values */
00185     numer = 1 << 30;
00186     numer <<= 30;   /* we don't trust cpp to compute 1<<60 correctly */
00187     deno = 1 << 30;
00188     deno <<= 20;
00189     rbig = gnc_numeric_create (numer, deno);
00190 
00191     big = gnc_numeric_create (1 << 10, 1);
00192     do_test (gnc_numeric_equal(big, rbig), "equal to billion");
00193 
00194     big = gnc_numeric_create (1 << 20, 1 << 10);
00195     do_test (gnc_numeric_equal(big, rbig), "equal to 1<<20/1<<10");
00196 
00197     big = gnc_numeric_create (1 << 30, 1 << 20);
00198     do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30/1<<20");
00199 
00200     numer = 1 << 30;
00201     numer <<= 30;   /* we don't trust cpp to compute 1<<60 correctly */
00202     deno = 1 << 30;
00203     rbig = gnc_numeric_create (numer, deno);
00204 
00205     big = gnc_numeric_create (1 << 30, 1);
00206     do_test (gnc_numeric_equal(big, rbig), "equal to 1<<30");
00207 
00208     numer = 1 << 30;
00209     numer <<= 10;
00210     big = gnc_numeric_create (numer, 1 << 10);
00211     do_test (gnc_numeric_equal(big, rbig), "equal to 1<<40/1<<10");
00212 
00213     numer <<= 10;
00214     big = gnc_numeric_create (numer, 1 << 20);
00215     do_test (gnc_numeric_equal(big, rbig), "equal to 1<<50/1<<20");
00216 
00217     /* We assume RAND_MAX is less that 1<<32 */
00218     for (i = 0; i < NREPS; i++)
00219     {
00220         deno = rand() / 2;
00221         mult = rand() / 2;
00222         numer = rand() / 2;
00223 
00224         /* avoid 0 */
00225         if (deno == 0 || mult == 0)
00226         {
00227             i--;
00228             continue;
00229         }
00230 
00231         val = gnc_numeric_create (numer, deno);
00232         mval = gnc_numeric_create (numer * mult, deno * mult);
00233 
00234         /* The reduced version should be equivalent */
00235         bval = gnc_numeric_reduce (val);
00236         rval = gnc_numeric_reduce (mval);
00237         check_unary_op (gnc_numeric_eq,
00238                         bval, rval, mval, "expected %s = %s = reduce(%s)");
00239 
00240         /* The unreduced versions should be equal */
00241         check_unary_op (gnc_numeric_equal,
00242                         val, mval, mval, "expected %s = %s");
00243 
00244         /* Certain modulo's should be very cleary un-equal; this
00245          * helps stop funky modulo-64 aliasing in compares that
00246          * might creep in. */
00247         mval.denom >>= 1;
00248         mval.num >>= 1;
00249         m = 0;
00250         f = mval.denom;
00251         while (f % 2 == 0)
00252         {
00253             f >>= 1;
00254             m++;
00255         }
00256         if (1 < m)
00257         {
00258             gint64 nn = 1 << (32 - m);
00259             nn <<= 32;
00260             nn += mval.num;
00261             val = gnc_numeric_create (2 * nn, 2 * mval.denom);
00262             check_unary_op (gnc_numeric_unequal,
00263                             val, mval, mval, "expected unequality %s != %s");
00264 
00265         }
00266     }
00267 }
00268 
00269 /* ======================================================= */
00270 
00271 static void
00272 check_rounding (void)
00273 {
00274     gnc_numeric val;
00275 
00276     val = gnc_numeric_create(7, 16);
00277     check_unary_op (gnc_numeric_eq,
00278                     gnc_numeric_create (43, 100),
00279                     gnc_numeric_convert (val, 100, GNC_HOW_RND_FLOOR),
00280                     val, "expected %s = %s = (%s as 100th's floor)");
00281     check_unary_op (gnc_numeric_eq,
00282                     gnc_numeric_create (44, 100),
00283                     gnc_numeric_convert (val, 100, GNC_HOW_RND_CEIL),
00284                     val, "expected %s = %s = (%s as 100th's ceiling)");
00285     check_unary_op (gnc_numeric_eq,
00286                     gnc_numeric_create (43, 100),
00287                     gnc_numeric_convert (val, 100, GNC_HOW_RND_TRUNC),
00288                     val, "expected %s = %s = (%s as 100th's trunc)");
00289     check_unary_op (gnc_numeric_eq,
00290                     gnc_numeric_create (44, 100),
00291                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00292                     val, "expected %s = %s = (%s as 100th's round)");
00293 
00294     val = gnc_numeric_create(1511, 1000);
00295     check_unary_op (gnc_numeric_eq,
00296                     gnc_numeric_create (151, 100),
00297                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00298                     val, "expected %s = %s = (%s as 100th's round)");
00299 
00300     val = gnc_numeric_create(1516, 1000);
00301     check_unary_op (gnc_numeric_eq,
00302                     gnc_numeric_create (152, 100),
00303                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00304                     val, "expected %s = %s = (%s as 100th's round)");
00305 
00306     /* Half-values always get rounded to nearest even number */
00307     val = gnc_numeric_create(1515, 1000);
00308     check_unary_op (gnc_numeric_eq,
00309                     gnc_numeric_create (152, 100),
00310                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00311                     val, "expected %s = %s = (%s as 100th's round)");
00312 
00313     val = gnc_numeric_create(1525, 1000);
00314     check_unary_op (gnc_numeric_eq,
00315                     gnc_numeric_create (152, 100),
00316                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00317                     val, "expected %s = %s = (%s as 100th's round)");
00318 
00319     val = gnc_numeric_create(1535, 1000);
00320     check_unary_op (gnc_numeric_eq,
00321                     gnc_numeric_create (154, 100),
00322                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00323                     val, "expected %s = %s = (%s as 100th's round)");
00324 
00325     val = gnc_numeric_create(1545, 1000);
00326     check_unary_op (gnc_numeric_eq,
00327                     gnc_numeric_create (154, 100),
00328                     gnc_numeric_convert (val, 100, GNC_HOW_RND_ROUND),
00329                     val, "expected %s = %s = (%s as 100th's round)");
00330 }
00331 
00332 /* ======================================================= */
00333 
00334 static void
00335 check_double (void)
00336 {
00337     double flo;
00338     gnc_numeric val = gnc_numeric_create (0, 1);
00339 
00340     check_unary_op (gnc_numeric_eq,
00341                     gnc_numeric_create (112346, 100000),
00342                     double_to_gnc_numeric(1.1234567890123,
00343                                           GNC_DENOM_AUTO,
00344                                           GNC_HOW_DENOM_SIGFIGS(6) |
00345                                           GNC_HOW_RND_ROUND),
00346                     val, "expected %s = %s double 6 figs");
00347 
00348     check_unary_op (gnc_numeric_eq,
00349                     gnc_numeric_create (112346, 10000000),
00350                     double_to_gnc_numeric(0.011234567890123,
00351                                           GNC_DENOM_AUTO,
00352                                           GNC_HOW_DENOM_SIGFIGS(6) |
00353                                           GNC_HOW_RND_ROUND),
00354                     val, "expected %s = %s double 6 figs");
00355 
00356     check_unary_op (gnc_numeric_eq,
00357                     gnc_numeric_create (112346, 100),
00358                     double_to_gnc_numeric(1123.4567890123,
00359                                           GNC_DENOM_AUTO,
00360                                           GNC_HOW_DENOM_SIGFIGS(6) |
00361                                           GNC_HOW_RND_ROUND),
00362                     val, "expected %s = %s double 6 figs");
00363     check_unary_op (gnc_numeric_eq,
00364                     gnc_numeric_create (112346, 10000000000LL),
00365                     double_to_gnc_numeric(1.1234567890123e-5,
00366                                           GNC_DENOM_AUTO,
00367                                           GNC_HOW_DENOM_SIGFIGS(6) |
00368                                           GNC_HOW_RND_ROUND),
00369                     val, "expected %s = %s double 6 figs");
00370 
00371     flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
00372     do_test ((0.4375 == flo), "float pt conversion");
00373 }
00374 
00375 /* ======================================================= */
00376 
00377 static void
00378 check_neg (void)
00379 {
00380     gnc_numeric a = gnc_numeric_create(2, 6);
00381     gnc_numeric b = gnc_numeric_create(1, 4);
00382     gnc_numeric c = gnc_numeric_neg (a);
00383     gnc_numeric d = gnc_numeric_neg (b);
00384 
00385     check_unary_op (gnc_numeric_eq,
00386                     gnc_numeric_create (-2, 6), c,
00387                     a, "expected %s = %s = -(%s)");
00388 
00389     check_unary_op (gnc_numeric_eq,
00390                     gnc_numeric_create (-1, 4), d,
00391                     b, "expected %s = %s = -(%s)");
00392 
00393 }
00394 
00395 /* ======================================================= */
00396 
00397 static void
00398 check_add_subtract (void)
00399 {
00400     int i;
00401     gnc_numeric a, b, c, d, z;
00402 #if CHECK_ERRORS_TOO
00403     gnc_numeric c;
00404 #endif
00405 
00406     a = gnc_numeric_create(2, 6);
00407     b = gnc_numeric_create(1, 4);
00408 
00409     /* Well, actually 14/24 would be acceptable/better in this case */
00410     check_binary_op (gnc_numeric_create(7, 12),
00411                      gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00412                      a, b, "expected %s got %s = %s + %s for add exact");
00413 
00414     check_binary_op (gnc_numeric_create(58, 100),
00415                      gnc_numeric_add(a, b, 100, GNC_HOW_RND_ROUND),
00416                      a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
00417 
00418     check_binary_op (gnc_numeric_create(5833, 10000),
00419                      gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00420                                      GNC_HOW_DENOM_SIGFIGS(4) |
00421                                      GNC_HOW_RND_ROUND),
00422                      a, b, "expected %s got %s = %s + %s for add 4 sig figs");
00423 
00424     check_binary_op (gnc_numeric_create(583333, 1000000),
00425                      gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00426                                      GNC_HOW_DENOM_SIGFIGS(6) |
00427                                      GNC_HOW_RND_ROUND),
00428                      a, b, "expected %s got %s = %s + %s for add 6 sig figs");
00429 
00430     check_binary_op (gnc_numeric_create(1, 12),
00431                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00432                      a, b, "expected %s got %s = %s - %s for sub exact");
00433 
00434     /* We should try something trickier for reduce & lcd */
00435     check_binary_op (gnc_numeric_create(1, 12),
00436                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00437                      a, b, "expected %s got %s = %s - %s for sub reduce");
00438 
00439     check_binary_op (gnc_numeric_create(1, 12),
00440                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
00441                      a, b, "expected %s got %s = %s - %s for sub reduce");
00442 
00443     check_binary_op (gnc_numeric_create(8, 100),
00444                      gnc_numeric_sub(a, b, 100, GNC_HOW_RND_ROUND),
00445                      a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
00446 
00447     /* ------------------------------------------------------------ */
00448     /* This test has failed before */
00449     c = gnc_numeric_neg (a);
00450     d = gnc_numeric_neg (b);
00451     z = gnc_numeric_zero();
00452     check_binary_op (c, gnc_numeric_add_fixed(z, c),
00453                      z, c, "expected %s got %s = %s + %s for add fixed");
00454 
00455     check_binary_op (d, gnc_numeric_add_fixed(z, d),
00456                      z, d, "expected %s got %s = %s + %s for add fixed");
00457 
00458     /* ------------------------------------------------------------ */
00459     /* Same as above, but with signs reviersed */
00460     a = c;
00461     b = d;
00462     /* Well, actually 14/24 would be acceptable/better in this case */
00463     check_binary_op (gnc_numeric_create(-7, 12),
00464                      gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00465                      a, b, "expected %s got %s = %s + %s for add exact");
00466 
00467     check_binary_op (gnc_numeric_create(-58, 100),
00468                      gnc_numeric_add(a, b, 100, GNC_HOW_RND_ROUND),
00469                      a, b, "expected %s got %s = %s + %s for add 100ths (banker's)");
00470 
00471     check_binary_op (gnc_numeric_create(-5833, 10000),
00472                      gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00473                                      GNC_HOW_DENOM_SIGFIGS(4) |
00474                                      GNC_HOW_RND_ROUND),
00475                      a, b, "expected %s got %s = %s + %s for add 4 sig figs");
00476 
00477     check_binary_op (gnc_numeric_create(-583333, 1000000),
00478                      gnc_numeric_add(a, b, GNC_DENOM_AUTO,
00479                                      GNC_HOW_DENOM_SIGFIGS(6) |
00480                                      GNC_HOW_RND_ROUND),
00481                      a, b, "expected %s got %s = %s + %s for add 6 sig figs");
00482 
00483     check_binary_op (gnc_numeric_create(-1, 12),
00484                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00485                      a, b, "expected %s got %s = %s - %s for sub exact");
00486 
00487     /* We should try something trickier for reduce & lcd */
00488     check_binary_op (gnc_numeric_create(-1, 12),
00489                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00490                      a, b, "expected %s got %s = %s - %s for sub reduce");
00491 
00492     check_binary_op (gnc_numeric_create(-1, 12),
00493                      gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
00494                      a, b, "expected %s got %s = %s - %s for sub reduce");
00495 
00496     check_binary_op (gnc_numeric_create(-8, 100),
00497                      gnc_numeric_sub(a, b, 100, GNC_HOW_RND_ROUND),
00498                      a, b, "expected %s got %s = %s - %s for sub 100ths (banker's)");
00499 
00500     /* ------------------------------------------------------------ */
00501 #if CHECK_ERRORS_TOO
00502     c = gnc_numeric_add_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
00503     printf("add 100ths/error : %s + %s = %s + (error) %s\n\n",
00504            gnc_numeric_print(a), gnc_numeric_print(b),
00505            gnc_numeric_print(c),
00506            gnc_numeric_print(err));
00507 
00508     c = gnc_numeric_sub_with_error(a, b, 100, GNC_HOW_RND_FLOOR, &err);
00509     printf("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
00510            gnc_numeric_print(a), gnc_numeric_print(b),
00511            gnc_numeric_print(c),
00512            gnc_numeric_print(err));
00513 
00514 #endif
00515 
00516     /* ------------------------------------------------------------ */
00517     /* Add and subtract some random numbers */
00518     for (i = 0; i < NREPS; i++)
00519     {
00520         gnc_numeric e;
00521         gint64 deno = rand() + 1;
00522         gint64 na = get_random_gint64();
00523         gint64 nb = get_random_gint64();
00524         gint64 ne;
00525 
00526         /* avoid overflow; */
00527         na /= 2;
00528         nb /= 2;
00529 
00530         a = gnc_numeric_create(na, deno);
00531         b = gnc_numeric_create(nb, deno);
00532 
00533         /* Add */
00534         ne = na + nb;
00535         e = gnc_numeric_create(ne, deno);
00536         check_binary_op (e,
00537                          gnc_numeric_add(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00538                          a, b, "expected %s got %s = %s + %s for exact addition");
00539 
00540         /* Subtract */
00541         ne = na - nb;
00542         e = gnc_numeric_create(ne, deno);
00543         check_binary_op (e,
00544                          gnc_numeric_sub(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00545                          a, b, "expected %s got %s = %s - %s for exact subtraction");
00546     }
00547 }
00548 
00549 /* ======================================================= */
00550 
00551 static void
00552 check_mult_div (void)
00553 {
00554     int i, j;
00555     gint64 v;
00556     gnc_numeric c, d;
00557     gnc_numeric amt_a, amt_tot, frac, val_tot, val_a;
00558     gnc_numeric a, b;
00559 
00560     a = gnc_numeric_create(-100, 100);
00561     b = gnc_numeric_create(1, 1);
00562     check_binary_op (gnc_numeric_create(-100, 100),
00563                      gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00564                      a, b, "expected %s got %s = %s / %s div exact");
00565 
00566     a = gnc_numeric_create(-100, 100);
00567     b = gnc_numeric_create(-1, 1);
00568     check_binary_op (gnc_numeric_create(100, 100),
00569                      gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00570                      a, b, "expected %s got %s = %s / %s div exact");
00571 
00572     a = gnc_numeric_create(-100, 100);
00573     b = gnc_numeric_create(-1, 1);
00574     check_binary_op (gnc_numeric_create(100, 100),
00575                      gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00576                      a, b, "expected %s got %s = %s * %s mult exact");
00577 
00578     a = gnc_numeric_create(2, 6);
00579     b = gnc_numeric_create(1, 4);
00580 
00581     check_binary_op (gnc_numeric_create(2, 24),
00582                      gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00583                      a, b, "expected %s got %s = %s * %s for mult exact");
00584 
00585     check_binary_op (gnc_numeric_create(1, 12),
00586                      gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00587                      a, b, "expected %s got %s = %s * %s for mult reduce");
00588 
00589     check_binary_op (gnc_numeric_create(8, 100),
00590                      gnc_numeric_mul(a, b, 100, GNC_HOW_RND_ROUND),
00591                      a, b, "expected %s got %s = %s * %s for mult 100th's");
00592 
00593     check_binary_op (gnc_numeric_create(8, 6),
00594                      gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00595                      a, b, "expected %s got %s = %s / %s for div exact");
00596 
00597     check_binary_op (gnc_numeric_create(4, 3),
00598                      gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00599                      a, b, "expected %s got %s = %s / %s for div reduce");
00600 
00601     check_binary_op (gnc_numeric_create(133, 100),
00602                      gnc_numeric_div(a, b, 100, GNC_HOW_RND_ROUND),
00603                      a, b, "expected %s got %s = %s * %s for div 100th's");
00604 
00605 #if CHECK_ERRORS_TOO
00606     gnc_numeric c;
00607     c = gnc_numeric_mul_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
00608     printf("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
00609            gnc_numeric_print(a), gnc_numeric_print(b),
00610            gnc_numeric_print(c),
00611            gnc_numeric_print(err));
00612 
00613     c = gnc_numeric_div_with_error(a, b, 100, GNC_HOW_RND_ROUND, &err);
00614     printf("div 100ths/error : %s / %s = %s + (error) %s\n\n",
00615            gnc_numeric_print(a), gnc_numeric_print(b),
00616            gnc_numeric_print(c),
00617            gnc_numeric_print(err));
00618 
00619 #endif
00620 
00621     /* Check for math with 2^63 < num*num < 2^64 which previously failed
00622      * see http://bugzilla.gnome.org/show_bug.cgi?id=144980
00623      */
00624     v = 1000000;
00625     a = gnc_numeric_create(1 * v, v);
00626     b = gnc_numeric_create(10000000 * v, v);
00627 
00628     check_binary_op (b,
00629                      gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD),
00630                      a, b, "expected %s got %s = %s * %s for multiply");
00631 
00632     /* Multiply some random numbers.  This test presumes that
00633      * RAND_MAX is approx 2^32
00634      */
00635     for (i = 0; i < NREPS; i++)
00636     {
00637         gint64 deno = 1;
00638         gint64 na = rand();
00639         gint64 nb = rand();
00640         gint64 ne;
00641 
00642         /* avoid 0 */
00643         if (nb / 4 == 0)
00644         {
00645             i--;
00646             continue;
00647         }
00648 
00649         /* avoid overflow; */
00650         na /= 2;
00651         nb /= 2;
00652         ne = na * nb;
00653 
00654         a = gnc_numeric_create(na, deno);
00655         b = gnc_numeric_create(nb, deno);
00656 
00657         check_binary_op_equal (gnc_numeric_create(ne, 1),
00658                                gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00659                                a, b, "expected %s got %s = %s * %s for mult exact");
00660 
00661         /* Force 128-bit math to come into play */
00662         for (j = 1; j < 31; j++)
00663         {
00664             a = gnc_numeric_create(na << j, 1 << j);
00665             b = gnc_numeric_create(nb << j, 1 << j);
00666             check_binary_op (gnc_numeric_create(ne, 1),
00667                              gnc_numeric_mul(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00668                              a, b, "expected %s got %s = %s * %s for mult reduce");
00669         }
00670 
00671         /* Do some hokey random 128-bit division too */
00672         b = gnc_numeric_create(deno, nb);
00673 
00674         check_binary_op_equal (gnc_numeric_create(ne, 1),
00675                                gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT),
00676                                a, b, "expected %s got %s = %s / %s for div exact");
00677 
00678         /* avoid overflow; */
00679         na /= 2;
00680         nb /= 2;
00681         ne = na * nb;
00682         for (j = 1; j < 16; j++)
00683         {
00684             a = gnc_numeric_create(na << j, 1 << j);
00685             b = gnc_numeric_create(1 << j, nb << j);
00686             check_binary_op (gnc_numeric_create(ne, 1),
00687                              gnc_numeric_div(a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE),
00688                              a, b, "expected %s got %s = %s / %s for div reduce");
00689         }
00690     }
00691 
00692     a = gnc_numeric_create(782592055622866ULL, 89025);
00693     b = gnc_numeric_create(2222554708930978ULL, 85568);
00694     /* Dividing the above pair overflows, in that after
00695      * the division the denominator won't fit into a
00696      * 64-bit quantity.  This can be seen from
00697      * the factorization int primes:
00698      * 782592055622866 = 2 * 2283317 * 171371749
00699      * (yes, thats a seven and a nine digit prime)
00700      * 2222554708930978 = 2 * 1111277354465489
00701      * (yes, that's a sixteen-digit prime number)
00702      * 89025 = 3*5*5*1187
00703      * 85568= 64*7*191
00704      * If the rounding method is exact/no-round, then
00705      * an overflow error should be signalled; else the
00706      * divide routine should shift down the results till
00707      * the overflow is eliminated.
00708      *
00709      */
00710     check_binary_op (gnc_numeric_error (GNC_ERROR_OVERFLOW),
00711                      gnc_numeric_div(a, b, GNC_DENOM_AUTO,
00712                                      GNC_HOW_RND_NEVER | GNC_HOW_DENOM_EXACT),
00713                      a, b, "expected %s got %s = %s / %s for div exact");
00714 
00715     check_binary_op (gnc_numeric_create(338441, 1000000),
00716                      gnc_numeric_div(a, b, GNC_DENOM_AUTO,
00717                                      GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND),
00718                      a, b, "expected %s got %s = %s / %s for div round");
00719 
00720     /* The below is a 'typical' value calculation:
00721      * value_frac = value_tot * amt_frace / amt_tot
00722      * and has some typical potential-overflow values.
00723      * 82718 = 2 * 59 * 701
00724      * 47497125586 = 2 * 1489 * 15949337
00725      * 69100955 = 5 * 7 * 11 * 179483
00726      * 32005637020 = 4 * 5 * 7 * 43 * 71 * 103 * 727
00727      */
00728     a = gnc_numeric_create (-47497125586LL, 82718);
00729     b = gnc_numeric_create (-69100955LL, 55739);
00730     c = gnc_numeric_mul (a, b, GNC_DENOM_AUTO, GNC_HOW_DENOM_EXACT);
00731     d = gnc_numeric_create (-32005637020LL, 55739);
00732 
00733     check_binary_op (gnc_numeric_create(-102547458LL, 82718),
00734                      gnc_numeric_div(c, d, 82718,
00735                                      GNC_HOW_DENOM_EXACT),
00736                      c, d, "expected %s got %s = %s / %s for div round");
00737 
00738     /* If we specify GNC_HOW_RND_NEVER, then we shoukld get an error,
00739      * since the exact result won't fit into a 64-bit quantity. */
00740     check_binary_op (gnc_numeric_error (GNC_ERROR_REMAINDER),
00741                      gnc_numeric_div(c, d, 82718,
00742                                      GNC_HOW_DENOM_EXACT | GNC_HOW_RND_NEVER),
00743                      c, d, "expected %s got %s = %s / %s for div round");
00744 
00745     /* A simple irreducible ratio, involving negative numbers */
00746     amt_a = gnc_numeric_create (-6005287905LL, 40595);
00747     amt_tot = gnc_numeric_create (-8744187958LL, 40595);
00748     frac = gnc_numeric_div (amt_a, amt_tot,
00749                             GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
00750 
00751     check_binary_op (gnc_numeric_create(6005287905LL, 8744187958LL),
00752                      frac, amt_a, amt_tot,
00753                      "expected %s got %s = %s / %s for div reduce");
00754 
00755     /* Another overflow-prone condition */
00756     val_tot = gnc_numeric_create (-4280656418LL, 19873);
00757     val_a = gnc_numeric_mul (frac, val_tot,
00758                              gnc_numeric_denom(val_tot),
00759                              GNC_HOW_RND_ROUND | GNC_HOW_DENOM_EXACT);
00760     check_binary_op (gnc_numeric_create(-2939846940LL, 19873),
00761                      val_a, val_tot, frac,
00762                      "expected %s got %s = %s * %s for mult round");
00763 
00764     frac = gnc_numeric_create (396226789777979LL, 328758834367851752LL);
00765     val_tot = gnc_numeric_create (467013515494988LL, 100);
00766     val_a = gnc_numeric_mul (frac, val_tot,
00767                              gnc_numeric_denom(val_tot),
00768                              GNC_HOW_RND_ROUND | GNC_HOW_DENOM_EXACT);
00769     check_binary_op (gnc_numeric_create(562854125307LL, 100),
00770                      val_a, val_tot, frac,
00771                      "expected %s got %s = %s * %s for mult round");
00772 
00773     /* Yet another bug from bugzilla ... */
00774     a = gnc_numeric_create (40066447153986554LL, 4518);
00775     b = gnc_numeric_create (26703286457229LL, 3192);
00776     frac = gnc_numeric_div(a, b,
00777                            GNC_DENOM_AUTO,
00778                            GNC_HOW_DENOM_SIGFIGS(6) |
00779                            GNC_HOW_RND_ROUND);
00780 
00781     check_binary_op (gnc_numeric_create(106007, 100),
00782                      frac, a, b,
00783                      "expected %s got %s = %s / %s for mult sigfigs");
00784 
00785 }
00786 
00787 static void
00788 check_reciprocal(void)
00789 {
00790     gnc_numeric a, b, ans, val;
00791     double flo;
00792 
00793     val = gnc_numeric_create(-60, 20);
00794     check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
00795                     gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
00796                                         GNC_HOW_RND_NEVER),
00797                     val, "expected %s = %s = (%s as RECIP(1))");
00798 
00799     a = gnc_numeric_create(200, 100);
00800     b = gnc_numeric_create(300, 100);
00801 
00802     /* 2 + 3 = 5 */
00803     ans = gnc_numeric_add(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
00804     check_binary_op (gnc_numeric_create(5, -1),
00805                      ans, a, b, "expected %s got %s = %s + %s for reciprocal");
00806 
00807     /* 2 + 3 = 5 */
00808     a = gnc_numeric_create(2, -1);
00809     b = gnc_numeric_create(300, 100);
00810     ans = gnc_numeric_add(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
00811     check_binary_op (gnc_numeric_create(5, -1),
00812                      ans, a, b, "expected %s got %s = %s + %s for reciprocal");
00813 
00814     /* check gnc_numeric_to_double */
00815     flo = gnc_numeric_to_double(gnc_numeric_create(5, -1));
00816     do_test ((5.0 == flo), "reciprocal conversion");
00817 
00818     /* check gnc_numeric_compare */
00819     a = gnc_numeric_create(2, 1);
00820     b = gnc_numeric_create(2, -1);
00821     do_test((0 == gnc_numeric_compare(a, b)), " 2 == 2 ");
00822     a = gnc_numeric_create(2, 1);
00823     b = gnc_numeric_create(3, -1);
00824     do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");
00825     a = gnc_numeric_create(-2, 1);
00826     b = gnc_numeric_create(2, -1);
00827     do_test((-1 == gnc_numeric_compare(a, b)), " -2 < 2 ");
00828     a = gnc_numeric_create(2, -1);
00829     b = gnc_numeric_create(3, -1);
00830     do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");
00831 
00832     /* check for equality */
00833     a = gnc_numeric_create(2, 1);
00834     b = gnc_numeric_create(2, -1);
00835     do_test(gnc_numeric_equal(a, b), " 2 == 2 ");
00836 
00837     /* check gnc_numeric_mul */
00838     a = gnc_numeric_create(2, 1);
00839     b = gnc_numeric_create(3, -1);
00840     ans = gnc_numeric_mul(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
00841     check_binary_op (gnc_numeric_create(6, -1),
00842                      ans, a, b, "expected %s got %s = %s * %s for reciprocal");
00843 
00844     /* check gnc_numeric_div */
00845     /* -60 / 20 = -3 */
00846     a = gnc_numeric_create(-60, 1);
00847     b = gnc_numeric_create(2, -10);
00848     ans = gnc_numeric_div(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
00849     check_binary_op (gnc_numeric_create(-3, -1),
00850                      ans, a, b, "expected %s got %s = %s / %s for reciprocal");
00851 
00852     /* 60 / 20 = 3 */
00853     a = gnc_numeric_create(60, 1);
00854     b = gnc_numeric_create(2, -10);
00855     ans = gnc_numeric_div(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
00856     check_binary_op (gnc_numeric_create(3, -1),
00857                      ans, a, b, "expected %s got %s = %s / %s for reciprocal");
00858 
00859 
00860 }
00861 
00862 /* ======================================================= */
00863 
00864 static void
00865 run_test (void)
00866 {
00867     check_eq_operator ();
00868     check_reduce ();
00869     check_equality_operator ();
00870     check_rounding();
00871     check_double();
00872     check_neg();
00873     check_add_subtract();
00874     check_mult_div ();
00875     check_reciprocal();
00876 }
00877 
00878 int
00879 main (int argc, char **argv)
00880 {
00881     qof_init();
00882     if (cashobjects_register())
00883     {
00884         run_test ();
00885         print_test_results();
00886     }
00887     qof_close();
00888     return get_rv();
00889 }
00890 
00891 /* ======================== END OF FILE ====================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines