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