|
GnuCash 2.4.99
|
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 ====================== */
1.7.4