00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "config.h"
00027
00028 #include <glib.h>
00029 #include <math.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033
00034 #include "qofnumeric.h"
00035 #include "qofmath128.c"
00036
00037
00038
00039
00040
00041
00042
00043 inline QofNumericErrorCode
00044 qof_numeric_check (QofNumeric in)
00045 {
00046 if (in.denom != 0)
00047 return QOF_ERROR_OK;
00048 else if (in.num)
00049 {
00050 if ((0 < in.num) || (-4 > in.num))
00051 in.num = (gint64) QOF_ERROR_OVERFLOW;
00052 return (QofNumericErrorCode) in.num;
00053 }
00054 else
00055 return QOF_ERROR_ARG;
00056 }
00057
00058
00059
00060
00061
00062 static inline gint64
00063 qof_numeric_lcd (QofNumeric a, QofNumeric b)
00064 {
00065 QofInt128 lcm;
00066 if (qof_numeric_check (a) || qof_numeric_check (b))
00067 return QOF_ERROR_ARG;
00068 if (b.denom == a.denom)
00069 return a.denom;
00070
00071 if ((b.denom < a.denom) && ((a.denom % b.denom) == 0))
00072 return a.denom;
00073 if ((a.denom < b.denom) && ((b.denom % a.denom) == 0))
00074 return b.denom;
00075 lcm = lcm128 (a.denom, b.denom);
00076 if (lcm.isbig)
00077 return QOF_ERROR_ARG;
00078 return lcm.lo;
00079 }
00080
00081
00082 static inline QofNumeric
00083 reduce128 (QofInt128 n, gint64 d)
00084 {
00085 gint64 t;
00086 gint64 num;
00087 gint64 denom;
00088 QofNumeric out;
00089 QofInt128 red;
00090
00091 t = rem128 (n, d);
00092 num = d;
00093 denom = t;
00094
00095
00096 while (denom > 0)
00097 {
00098 t = num % denom;
00099 num = denom;
00100 denom = t;
00101 }
00102
00103
00104 red = div128 (n, num);
00105 if (red.isbig)
00106 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00107 out.num = red.lo;
00108 if (red.isneg)
00109 out.num = -out.num;
00110 out.denom = d / num;
00111 return out;
00112 }
00113
00114
00115
00116
00117
00118 gboolean
00119 qof_numeric_zero_p (QofNumeric a)
00120 {
00121 if (qof_numeric_check (a))
00122 return 0;
00123 else
00124 {
00125 if ((a.num == 0) && (a.denom != 0))
00126 return 1;
00127 else
00128 return 0;
00129 }
00130 }
00131
00132
00133
00134
00135
00136 gboolean
00137 qof_numeric_negative_p (QofNumeric a)
00138 {
00139 if (qof_numeric_check (a))
00140 return 0;
00141 else
00142 {
00143 if ((a.num < 0) && (a.denom != 0))
00144 return 1;
00145 else
00146 return 0;
00147 }
00148 }
00149
00150
00151
00152
00153
00154 gboolean
00155 qof_numeric_positive_p (QofNumeric a)
00156 {
00157 if (qof_numeric_check (a))
00158 return 0;
00159 else
00160 {
00161 if ((a.num > 0) && (a.denom != 0))
00162 return 1;
00163 else
00164 return 0;
00165 }
00166 }
00167
00168
00169
00170
00171
00172
00173 gint
00174 qof_numeric_compare (QofNumeric a, QofNumeric b)
00175 {
00176 gint64 aa, bb;
00177 QofInt128 l, r;
00178
00179 if (qof_numeric_check (a) || qof_numeric_check (b))
00180 return 0;
00181
00182 if (a.denom == b.denom)
00183 {
00184 if (a.num == b.num)
00185 return 0;
00186 if (a.num > b.num)
00187 return 1;
00188 return -1;
00189 }
00190
00191 if ((a.denom > 0) && (b.denom > 0))
00192 {
00193
00194 l = mult128 (a.num, b.denom);
00195 r = mult128 (b.num, a.denom);
00196 return cmp128 (l, r);
00197 }
00198
00199 if (a.denom < 0)
00200 a.denom *= -1;
00201 if (b.denom < 0)
00202 b.denom *= -1;
00203
00204
00205
00206
00207 aa = a.num * a.denom;
00208 bb = b.num * b.denom;
00209
00210 if (aa == bb)
00211 return 0;
00212 if (aa > bb)
00213 return 1;
00214 return -1;
00215 }
00216
00217
00218
00219
00220
00221
00222 gboolean
00223 qof_numeric_eq (QofNumeric a, QofNumeric b)
00224 {
00225 return ((a.num == b.num) && (a.denom == b.denom));
00226 }
00227
00228
00229
00230
00231
00232 gboolean
00233 qof_numeric_equal (QofNumeric a, QofNumeric b)
00234 {
00235 QofInt128 l, r;
00236
00237 if ((a.denom == b.denom) && (a.denom > 0))
00238 return (a.num == b.num);
00239 if ((a.denom > 0) && (b.denom > 0))
00240 {
00241
00242 l = mult128 (a.num, b.denom);
00243 r = mult128 (b.num, a.denom);
00244 return equal128 (l, r);
00245
00246 #if ALT_WAY_OF_CHECKING_EQUALITY
00247 QofNumeric ra = QofNumeric_reduce (a);
00248 QofNumeric rb = QofNumeric_reduce (b);
00249 if (ra.denom != rb.denom)
00250 return 0;
00251 if (ra.num != rb.num)
00252 return 0;
00253 return 1;
00254 #endif
00255 }
00256 if ((a.denom < 0) && (b.denom < 0))
00257 {
00258 l = mult128 (a.num, -a.denom);
00259 r = mult128 (b.num, -b.denom);
00260 return equal128 (l, r);
00261 }
00262 else
00263 {
00264
00265
00266
00267
00268
00269 if (a.denom < 0)
00270 return ((a.num * -a.denom * b.denom) == b.num);
00271 else
00272 return (a.num == (b.num * a.denom * -b.denom));
00273 }
00274 return ((a.num * b.denom) == (a.denom * b.num));
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284 gint
00285 qof_numeric_same (QofNumeric a, QofNumeric b, gint64 denom, gint how)
00286 {
00287 QofNumeric aconv, bconv;
00288
00289 aconv = qof_numeric_convert (a, denom, how);
00290 bconv = qof_numeric_convert (b, denom, how);
00291
00292 return (qof_numeric_equal (aconv, bconv));
00293 }
00294
00295
00296
00297
00298
00299 QofNumeric
00300 qof_numeric_add (QofNumeric a, QofNumeric b, gint64 denom, gint how)
00301 {
00302 QofNumeric sum;
00303
00304 if (qof_numeric_check (a) || qof_numeric_check (b))
00305 return qof_numeric_error (QOF_ERROR_ARG);
00306
00307 if ((denom == QOF_DENOM_AUTO) &&
00308 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00309 {
00310 if (a.denom == b.denom)
00311 denom = a.denom;
00312 else if (b.num == 0)
00313 {
00314 denom = a.denom;
00315 b.denom = a.denom;
00316 }
00317 else if (a.num == 0)
00318 {
00319 denom = b.denom;
00320 a.denom = b.denom;
00321 }
00322 else
00323 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00324 }
00325
00326 if (a.denom < 0)
00327 {
00328 a.num *= -a.denom;
00329 a.denom = 1;
00330 }
00331
00332 if (b.denom < 0)
00333 {
00334 b.num *= -b.denom;
00335 b.denom = 1;
00336 }
00337
00338
00339 if (a.denom == b.denom)
00340 {
00341 sum.num = a.num + b.num;
00342 sum.denom = a.denom;
00343 }
00344 else
00345 {
00346
00347
00348
00349
00350
00351
00352 gint64 lcd;
00353 QofInt128 ca, cb, cab;
00354
00355 lcd = qof_numeric_lcd (a, b);
00356 if (QOF_ERROR_ARG == lcd)
00357 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00358 ca = mult128 (a.num, lcd / a.denom);
00359 if (ca.isbig)
00360 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00361 cb = mult128 (b.num, lcd / b.denom);
00362 if (cb.isbig)
00363 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00364 cab = add128 (ca, cb);
00365 if (cab.isbig)
00366 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00367 sum.num = cab.lo;
00368 if (cab.isneg)
00369 sum.num = -sum.num;
00370 sum.denom = lcd;
00371 }
00372
00373 if ((denom == QOF_DENOM_AUTO) &&
00374 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00375 {
00376 denom = qof_numeric_lcd (a, b);
00377 how = how & QOF_NUMERIC_RND_MASK;
00378 }
00379
00380 return qof_numeric_convert (sum, denom, how);
00381 }
00382
00383
00384
00385
00386
00387 QofNumeric
00388 qof_numeric_sub (QofNumeric a, QofNumeric b, gint64 denom, gint how)
00389 {
00390 QofNumeric nb;
00391
00392 if (qof_numeric_check (a) || qof_numeric_check (b))
00393 return qof_numeric_error (QOF_ERROR_ARG);
00394
00395 nb = b;
00396 nb.num = -nb.num;
00397 return qof_numeric_add (a, nb, denom, how);
00398 }
00399
00400
00401
00402
00403
00404 QofNumeric
00405 qof_numeric_mul (QofNumeric a, QofNumeric b, gint64 denom, gint how)
00406 {
00407 QofNumeric product, result;
00408 QofInt128 bignume, bigdeno;
00409
00410 if (qof_numeric_check (a) || qof_numeric_check (b))
00411 return qof_numeric_error (QOF_ERROR_ARG);
00412
00413 if ((denom == QOF_DENOM_AUTO) &&
00414 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00415 {
00416 if (a.denom == b.denom)
00417 denom = a.denom;
00418 else if (b.num == 0)
00419 denom = a.denom;
00420 else if (a.num == 0)
00421 denom = b.denom;
00422 else
00423 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00424 }
00425
00426 if ((denom == QOF_DENOM_AUTO) &&
00427 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00428 {
00429 denom = qof_numeric_lcd (a, b);
00430 how = how & QOF_NUMERIC_RND_MASK;
00431 }
00432
00433 if (a.denom < 0)
00434 {
00435 a.num *= -a.denom;
00436 a.denom = 1;
00437 }
00438
00439 if (b.denom < 0)
00440 {
00441 b.num *= -b.denom;
00442 b.denom = 1;
00443 }
00444
00445 bignume = mult128 (a.num, b.num);
00446 bigdeno = mult128 (a.denom, b.denom);
00447 product.num = a.num * b.num;
00448 product.denom = a.denom * b.denom;
00449
00450
00451 if (bignume.isbig || bigdeno.isbig)
00452 {
00453 gint64 tmp;
00454
00455 a = qof_numeric_reduce (a);
00456 b = qof_numeric_reduce (b);
00457 tmp = a.num;
00458 a.num = b.num;
00459 b.num = tmp;
00460 a = qof_numeric_reduce (a);
00461 b = qof_numeric_reduce (b);
00462 bignume = mult128 (a.num, b.num);
00463 bigdeno = mult128 (a.denom, b.denom);
00464 product.num = a.num * b.num;
00465 product.denom = a.denom * b.denom;
00466 }
00467
00468
00469 if (bignume.isbig || bigdeno.isbig)
00470 {
00471
00472
00473
00474 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
00475 {
00476 if (bigdeno.isbig)
00477 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00478 product = reduce128 (bignume, product.denom);
00479 if (qof_numeric_check (product))
00480 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00481 }
00482 else
00483 {
00484 while (bignume.isbig || bigdeno.isbig)
00485 {
00486 bignume = shift128 (bignume);
00487 bigdeno = shift128 (bigdeno);
00488 }
00489 product.num = bignume.lo;
00490 if (bignume.isneg)
00491 product.num = -product.num;
00492
00493 product.denom = bigdeno.lo;
00494 if (0 == product.denom)
00495 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00496 }
00497 }
00498
00499 #if 0
00500 if (product.denom < 0)
00501 {
00502 product.num = -product.num;
00503 product.denom = -product.denom;
00504 }
00505 #endif
00506
00507 result = qof_numeric_convert (product, denom, how);
00508 return result;
00509 }
00510
00511
00512
00513
00514
00515 QofNumeric
00516 qof_numeric_div (QofNumeric a, QofNumeric b, gint64 denom, gint how)
00517 {
00518 QofNumeric quotient;
00519 QofInt128 nume, deno;
00520
00521 if (qof_numeric_check (a) || qof_numeric_check (b))
00522 return qof_numeric_error (QOF_ERROR_ARG);
00523
00524 if ((denom == QOF_DENOM_AUTO) &&
00525 (how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_FIXED)
00526 {
00527 if (a.denom == b.denom)
00528 denom = a.denom;
00529 else if (a.denom == 0)
00530 denom = b.denom;
00531 else
00532 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00533 }
00534
00535 if (a.denom < 0)
00536 {
00537 a.num *= -a.denom;
00538 a.denom = 1;
00539 }
00540
00541 if (b.denom < 0)
00542 {
00543 b.num *= -b.denom;
00544 b.denom = 1;
00545 }
00546
00547 if (a.denom == b.denom)
00548 {
00549 quotient.num = a.num;
00550 quotient.denom = b.num;
00551 }
00552 else
00553 {
00554 gint64 sgn = 1;
00555 if (0 > a.num)
00556 {
00557 sgn = -sgn;
00558 a.num = -a.num;
00559 }
00560 if (0 > b.num)
00561 {
00562 sgn = -sgn;
00563 b.num = -b.num;
00564 }
00565 nume = mult128 (a.num, b.denom);
00566 deno = mult128 (b.num, a.denom);
00567
00568
00569 if (nume.isbig && deno.isbig)
00570 {
00571 QofNumeric ra = qof_numeric_reduce (a);
00572 QofNumeric rb = qof_numeric_reduce (b);
00573 gint64 gcf_nume = gcf64 (ra.num, rb.num);
00574 gint64 gcf_deno = gcf64 (rb.denom, ra.denom);
00575
00576 nume = mult128 (ra.num / gcf_nume, rb.denom / gcf_deno);
00577 deno = mult128 (rb.num / gcf_nume, ra.denom / gcf_deno);
00578 }
00579
00580 if ((0 == nume.isbig) && (0 == deno.isbig))
00581 {
00582 quotient.num = sgn * nume.lo;
00583 quotient.denom = deno.lo;
00584 goto dive_done;
00585 }
00586 else if (0 == deno.isbig)
00587 {
00588 quotient = reduce128 (nume, deno.lo);
00589 if (0 == qof_numeric_check (quotient))
00590 {
00591 quotient.num *= sgn;
00592 goto dive_done;
00593 }
00594 }
00595
00596
00597
00598
00599 if ((how & QOF_NUMERIC_RND_MASK) == QOF_HOW_RND_NEVER)
00600 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00601 while (nume.isbig || deno.isbig)
00602 {
00603 nume = shift128 (nume);
00604 deno = shift128 (deno);
00605 }
00606 quotient.num = sgn * nume.lo;
00607 quotient.denom = deno.lo;
00608 if (0 == quotient.denom)
00609 {
00610 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00611 }
00612 }
00613
00614 if (quotient.denom < 0)
00615 {
00616 quotient.num = -quotient.num;
00617 quotient.denom = -quotient.denom;
00618 }
00619
00620 dive_done:
00621 if ((denom == QOF_DENOM_AUTO) &&
00622 ((how & QOF_NUMERIC_DENOM_MASK) == QOF_HOW_DENOM_LCD))
00623 {
00624 denom = qof_numeric_lcd (a, b);
00625 how = how & QOF_NUMERIC_RND_MASK;
00626 }
00627
00628 return qof_numeric_convert (quotient, denom, how);
00629 }
00630
00631
00632
00633
00634
00635
00636 QofNumeric
00637 qof_numeric_neg (QofNumeric a)
00638 {
00639 if (qof_numeric_check (a))
00640 return qof_numeric_error (QOF_ERROR_ARG);
00641 return qof_numeric_create (-a.num, a.denom);
00642 }
00643
00644
00645
00646
00647
00648
00649 QofNumeric
00650 qof_numeric_abs (QofNumeric a)
00651 {
00652 if (qof_numeric_check (a))
00653 return qof_numeric_error (QOF_ERROR_ARG);
00654 return qof_numeric_create (ABS (a.num), a.denom);
00655 }
00656
00657
00658
00659
00660
00661 QofNumeric
00662 qof_numeric_convert (QofNumeric in, gint64 denom, gint how)
00663 {
00664 QofNumeric out;
00665 QofNumeric temp;
00666 gint64 temp_bc;
00667 gint64 temp_a;
00668 gint64 remainder;
00669 gint64 sign;
00670 gint denom_neg = 0;
00671 gdouble ratio, logratio;
00672 gdouble sigfigs;
00673 QofInt128 nume, newm;
00674
00675 temp.num = 0;
00676 temp.denom = 0;
00677
00678 if (qof_numeric_check (in))
00679 return qof_numeric_error (QOF_ERROR_ARG);
00680
00681 if (denom == QOF_DENOM_AUTO)
00682 {
00683 switch (how & QOF_NUMERIC_DENOM_MASK)
00684 {
00685 default:
00686 case QOF_HOW_DENOM_LCD:
00687 case QOF_HOW_DENOM_EXACT:
00688 return in;
00689 break;
00690
00691 case QOF_HOW_DENOM_REDUCE:
00692
00693 return qof_numeric_reduce (in);
00694 break;
00695
00696 case QOF_HOW_DENOM_FIXED:
00697 if (in.denom != denom)
00698 return qof_numeric_error (QOF_ERROR_DENOM_DIFF);
00699 else
00700 return in;
00701 break;
00702
00703 case QOF_HOW_DENOM_SIGFIG:
00704 ratio = fabs (qof_numeric_to_double (in));
00705 if (ratio < 10e-20)
00706 logratio = 0;
00707 else
00708 {
00709 logratio = log10 (ratio);
00710 logratio = ((logratio > 0.0) ?
00711 (floor (logratio) + 1.0) : (ceil (logratio)));
00712 }
00713 sigfigs = QOF_HOW_GET_SIGFIGS (how);
00714
00715 if (sigfigs - logratio >= 0)
00716 denom = (gint64) (pow (10, sigfigs - logratio));
00717 else
00718 denom = -((gint64) (pow (10, logratio - sigfigs)));
00719
00720 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
00721 break;
00722 }
00723 }
00724
00725
00726 if (in.denom == denom)
00727 return in;
00728 if (in.num == 0)
00729 {
00730 out.num = 0;
00731 out.denom = denom;
00732 return out;
00733 }
00734
00735
00736 if (in.denom < 0)
00737 {
00738 in.num = in.num * (-in.denom);
00739 in.denom = 1;
00740 }
00741
00742 sign = (in.num < 0) ? -1 : 1;
00743
00744
00745
00746 if (denom < 0)
00747 {
00748
00749
00750 denom = -denom;
00751 denom_neg = 1;
00752 temp_a = (in.num < 0) ? -in.num : in.num;
00753 temp_bc = in.denom * denom;
00754 remainder = temp_a % temp_bc;
00755 out.num = temp_a / temp_bc;
00756 out.denom = -denom;
00757 }
00758 else
00759 {
00760
00761
00762
00763 temp.num = denom;
00764 temp.denom = in.denom;
00765 temp = qof_numeric_reduce (temp);
00766
00767
00768
00769
00770
00771
00772
00773 nume = mult128 (in.num, temp.num);
00774 newm = div128 (nume, temp.denom);
00775 remainder = rem128 (nume, temp.denom);
00776
00777 if (newm.isbig)
00778 return qof_numeric_error (QOF_ERROR_OVERFLOW);
00779
00780 out.num = newm.lo;
00781 out.denom = denom;
00782 }
00783
00784 if (remainder)
00785 {
00786 switch (how & QOF_NUMERIC_RND_MASK)
00787 {
00788 case QOF_HOW_RND_FLOOR:
00789 if (sign < 0)
00790 out.num = out.num + 1;
00791 break;
00792
00793 case QOF_HOW_RND_CEIL:
00794 if (sign > 0)
00795 out.num = out.num + 1;
00796 break;
00797
00798 case QOF_HOW_RND_TRUNC:
00799 break;
00800
00801 case QOF_HOW_RND_PROMOTE:
00802 out.num = out.num + 1;
00803 break;
00804
00805 case QOF_HOW_RND_ROUND_HALF_DOWN:
00806 if (denom_neg)
00807 {
00808 if ((2 * remainder) > in.denom * denom)
00809 out.num = out.num + 1;
00810 }
00811 else if ((2 * remainder) > temp.denom)
00812 out.num = out.num + 1;
00813
00814 else if (((2 * remainder) < remainder) &&
00815 (remainder > (temp.denom / 2)))
00816 out.num = out.num + 1;
00817 break;
00818
00819 case QOF_HOW_RND_ROUND_HALF_UP:
00820 if (denom_neg)
00821 {
00822 if ((2 * remainder) >= in.denom * denom)
00823 out.num = out.num + 1;
00824 }
00825 else if ((2 * remainder) >= temp.denom)
00826 out.num = out.num + 1;
00827
00828 else if (((2 * remainder) < remainder) &&
00829 (remainder >= (temp.denom / 2)))
00830 out.num = out.num + 1;
00831 break;
00832
00833 case QOF_HOW_RND_ROUND:
00834 if (denom_neg)
00835 {
00836 if ((2 * remainder) > in.denom * denom)
00837 out.num = out.num + 1;
00838 else if ((2 * remainder) == in.denom * denom)
00839 {
00840 if (out.num % 2)
00841 out.num = out.num + 1;
00842 }
00843 }
00844 else
00845 {
00846 if ((2 * remainder) > temp.denom)
00847 out.num = out.num + 1;
00848
00849 else if (((2 * remainder) < remainder) &&
00850 (remainder > (temp.denom / 2)))
00851 {
00852 out.num = out.num + 1;
00853 }
00854 else if ((2 * remainder) == temp.denom)
00855 {
00856 if (out.num % 2)
00857 out.num = out.num + 1;
00858 }
00859
00860 else if (((2 * remainder) < remainder) &&
00861 (remainder == (temp.denom / 2)))
00862 {
00863 if (out.num % 2)
00864 out.num = out.num + 1;
00865 }
00866 }
00867 break;
00868
00869 case QOF_HOW_RND_NEVER:
00870 return qof_numeric_error (QOF_ERROR_REMAINDER);
00871 break;
00872 }
00873 }
00874
00875 out.num = (sign > 0) ? out.num : (-out.num);
00876
00877 return out;
00878 }
00879
00880
00881
00882
00883
00884
00885
00886
00887 QofNumeric
00888 qof_numeric_reduce (QofNumeric in)
00889 {
00890 gint64 t;
00891 gint64 num = (in.num < 0) ? (-in.num) : in.num;
00892 gint64 denom = in.denom;
00893 QofNumeric out;
00894
00895 if (qof_numeric_check (in))
00896 return qof_numeric_error (QOF_ERROR_ARG);
00897
00898
00899 while (denom > 0)
00900 {
00901 t = num % denom;
00902 num = denom;
00903 denom = t;
00904 }
00905
00906
00907
00908
00909 out.num = in.num / num;
00910 out.denom = in.denom / num;
00911 return out;
00912 }
00913
00914
00915
00916
00917
00918 QofNumeric
00919 qof_numeric_from_double (gdouble in, gint64 denom, gint how)
00920 {
00921 QofNumeric out;
00922 gint64 int_part = 0;
00923 gdouble frac_part;
00924 gint64 frac_int = 0;
00925 gdouble logval;
00926 gdouble sigfigs;
00927
00928 if ((denom == QOF_DENOM_AUTO) && (how & QOF_HOW_DENOM_SIGFIG))
00929 {
00930 if (fabs (in) < 10e-20)
00931 logval = 0;
00932 else
00933 {
00934 logval = log10 (fabs (in));
00935 logval = ((logval > 0.0) ?
00936 (floor (logval) + 1.0) : (ceil (logval)));
00937 }
00938 sigfigs = QOF_HOW_GET_SIGFIGS (how);
00939 if (sigfigs - logval >= 0)
00940 denom = (gint64) (pow (10, sigfigs - logval));
00941 else
00942 denom = -((gint64) (pow (10, logval - sigfigs)));
00943
00944 how = how & ~QOF_HOW_DENOM_SIGFIG & ~QOF_NUMERIC_SIGFIGS_MASK;
00945 }
00946
00947 int_part = (gint64) (floor (fabs (in)));
00948 frac_part = in - (double) int_part;
00949
00950 int_part = int_part * denom;
00951 frac_part = frac_part * (double) denom;
00952
00953 switch (how & QOF_NUMERIC_RND_MASK)
00954 {
00955 case QOF_HOW_RND_FLOOR:
00956 frac_int = (gint64) floor (frac_part);
00957 break;
00958
00959 case QOF_HOW_RND_CEIL:
00960 frac_int = (gint64) ceil (frac_part);
00961 break;
00962
00963 case QOF_HOW_RND_TRUNC:
00964 frac_int = (gint64) frac_part;
00965 break;
00966
00967 case QOF_HOW_RND_ROUND:
00968 case QOF_HOW_RND_ROUND_HALF_UP:
00969 frac_int = (gint64) rint (frac_part);
00970 break;
00971
00972 case QOF_HOW_RND_NEVER:
00973 frac_int = (gint64) floor (frac_part);
00974 if (frac_part != (double) frac_int)
00975 {
00976
00977 }
00978 break;
00979 }
00980
00981 out.num = int_part + frac_int;
00982 out.denom = denom;
00983 return out;
00984 }
00985
00986
00987
00988
00989
00990 gdouble
00991 qof_numeric_to_double (QofNumeric in)
00992 {
00993 if (in.denom > 0)
00994 return (gdouble) in.num / (gdouble) in.denom;
00995 else
00996 return (gdouble) (in.num * -in.denom);
00997 }
00998
00999
01000
01001
01002
01003 QofNumeric
01004 qof_numeric_error (QofNumericErrorCode error_code)
01005 {
01006 return qof_numeric_create (error_code, 0LL);
01007 }
01008
01009
01010
01011
01012
01013 QofNumeric
01014 qof_numeric_add_with_error (QofNumeric a, QofNumeric b,
01015 gint64 denom, gint how, QofNumeric * error)
01016 {
01017
01018 QofNumeric sum = qof_numeric_add (a, b, denom, how);
01019 QofNumeric exact = qof_numeric_add (a, b, QOF_DENOM_AUTO,
01020 QOF_HOW_DENOM_REDUCE);
01021 QofNumeric err = qof_numeric_sub (sum, exact, QOF_DENOM_AUTO,
01022 QOF_HOW_DENOM_REDUCE);
01023
01024 if (error)
01025 *error = err;
01026 return sum;
01027 }
01028
01029
01030
01031
01032
01033 QofNumeric
01034 qof_numeric_sub_with_error (QofNumeric a, QofNumeric b,
01035 gint64 denom, gint how, QofNumeric * error)
01036 {
01037 QofNumeric diff = qof_numeric_sub (a, b, denom, how);
01038 QofNumeric exact = qof_numeric_sub (a, b, QOF_DENOM_AUTO,
01039 QOF_HOW_DENOM_REDUCE);
01040 QofNumeric err = qof_numeric_sub (diff, exact, QOF_DENOM_AUTO,
01041 QOF_HOW_DENOM_REDUCE);
01042 if (error)
01043 *error = err;
01044 return diff;
01045 }
01046
01047
01048
01049
01050
01051 QofNumeric
01052 qof_numeric_mul_with_error (QofNumeric a, QofNumeric b,
01053 gint64 denom, gint how, QofNumeric * error)
01054 {
01055 QofNumeric prod = qof_numeric_mul (a, b, denom, how);
01056 QofNumeric exact = qof_numeric_mul (a, b, QOF_DENOM_AUTO,
01057 QOF_HOW_DENOM_REDUCE);
01058 QofNumeric err = qof_numeric_sub (prod, exact, QOF_DENOM_AUTO,
01059 QOF_HOW_DENOM_REDUCE);
01060 if (error)
01061 *error = err;
01062 return prod;
01063 }
01064
01065
01066
01067
01068
01069
01070 QofNumeric
01071 qof_numeric_div_with_error (QofNumeric a, QofNumeric b,
01072 gint64 denom, gint how, QofNumeric * error)
01073 {
01074 QofNumeric quot = qof_numeric_div (a, b, denom, how);
01075 QofNumeric exact = qof_numeric_div (a, b, QOF_DENOM_AUTO,
01076 QOF_HOW_DENOM_REDUCE);
01077 QofNumeric err = qof_numeric_sub (quot, exact,
01078 QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE);
01079 if (error)
01080 *error = err;
01081 return quot;
01082 }
01083
01084
01085
01086
01087
01088 gchar *
01089 qof_numeric_to_string (QofNumeric n)
01090 {
01091 gchar *result;
01092 gint64 tmpnum = n.num;
01093 gint64 tmpdenom = n.denom;
01094
01095 result =
01096 g_strdup_printf ("%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
01097 tmpdenom);
01098
01099 return result;
01100 }
01101
01102 gchar *
01103 qof_numeric_dbg_to_string (QofNumeric n)
01104 {
01105 static gchar buff[1000];
01106 static gchar *p = buff;
01107 gint64 tmpnum = n.num;
01108 gint64 tmpdenom = n.denom;
01109
01110 p += 100;
01111 if (p - buff >= 1000)
01112 p = buff;
01113
01114 sprintf (p, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, tmpnum,
01115 tmpdenom);
01116
01117 return p;
01118 }
01119
01120 gboolean
01121 qof_numeric_from_string (const gchar * str, QofNumeric * n)
01122 {
01123 size_t num_read;
01124 gint64 tmpnum;
01125 gint64 tmpdenom;
01126
01127 if (!str)
01128 return FALSE;
01129
01130 #ifdef QOF_DEPRECATED
01131
01132 if (sscanf (str, " " QOF_SCANF_LLD "/" QOF_SCANF_LLD "%n",
01133 &tmpnum, &tmpdenom, &num_read) < 2)
01134 {
01135 return FALSE;
01136 }
01137 #else
01138 tmpnum = strtoll (str, NULL, 0);
01139 str = strchr (str, '/');
01140 if (!str)
01141 return FALSE;
01142 str++;
01143 tmpdenom = strtoll (str, NULL, 0);
01144 num_read = strspn (str, "0123456789");
01145 #endif
01146 n->num = tmpnum;
01147 n->denom = tmpdenom;
01148 return TRUE;
01149 }
01150
01151
01152
01153
01154 #ifdef _QOF_NUMERIC_TEST
01155
01156 static gchar *
01157 qof_numeric_print (QofNumeric in)
01158 {
01159 gchar *retval;
01160 if (qof_numeric_check (in))
01161 {
01162 retval =
01163 g_strdup_printf ("<ERROR> [%" G_GINT64_FORMAT " / %"
01164 G_GINT64_FORMAT "]", in.num, in.denom);
01165 }
01166 else
01167 {
01168 retval =
01169 g_strdup_printf ("[%" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
01170 "]", in.num, in.denom);
01171 }
01172 return retval;
01173 }
01174
01175 int
01176 main (void)
01177 {
01178 QofNumeric a = qof_numeric_create (1, 3);
01179 QofNumeric b = qof_numeric_create (1, 4);
01180 QofNumeric c;
01181
01182 QofNumeric err;
01183
01184 c = qof_numeric_add_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
01185 printf ("add 100ths/error : %s + %s = %s + (error) %s\n\n",
01186 qof_numeric_print (a), qof_numeric_print (b),
01187 qof_numeric_print (c), qof_numeric_print (err));
01188
01189 c = qof_numeric_sub_with_error (a, b, 100, QOF_HOW_RND_FLOOR, &err);
01190 printf ("sub 100ths/error : %s - %s = %s + (error) %s\n\n",
01191 qof_numeric_print (a), qof_numeric_print (b),
01192 qof_numeric_print (c), qof_numeric_print (err));
01193
01194 c = qof_numeric_mul_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
01195 printf ("mul 100ths/error : %s * %s = %s + (error) %s\n\n",
01196 qof_numeric_print (a), qof_numeric_print (b),
01197 qof_numeric_print (c), qof_numeric_print (err));
01198
01199 c = qof_numeric_div_with_error (a, b, 100, QOF_HOW_RND_ROUND, &err);
01200 printf ("div 100ths/error : %s / %s = %s + (error) %s\n\n",
01201 qof_numeric_print (a), qof_numeric_print (b),
01202 qof_numeric_print (c), qof_numeric_print (err));
01203
01204 printf ("multiply (EXACT): %s * %s = %s\n",
01205 qof_numeric_print (a), qof_numeric_print (b),
01206 qof_numeric_print (qof_numeric_mul
01207 (a, b, QOF_DENOM_AUTO, QOF_HOW_DENOM_EXACT)));
01208
01209 printf ("multiply (REDUCE): %s * %s = %s\n",
01210 qof_numeric_print (a), qof_numeric_print (b),
01211 qof_numeric_print (qof_numeric_mul
01212 (a, b, QOF_DENOM_AUTO, QOF_HOW_DENOM_REDUCE)));
01213
01214
01215 return 0;
01216 }
01217 #endif
01218
01219