GnuCash 2.4.99
qofmath128.c
00001 /********************************************************************
00002  * qofmath128.c -- an 128-bit integer library                       *
00003  * Copyright (C) 2004 Linas Vepstas <linas@linas.org>               *
00004  *                                                                  *
00005  * This program is free software; you can redistribute it and/or    *
00006  * modify it under the terms of the GNU General Public License as   *
00007  * published by the Free Software Foundation; either version 2 of   *
00008  * the License, or (at your option) any later version.              *
00009  *                                                                  *
00010  * This program is distributed in the hope that it will be useful,  *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00013  * GNU General Public License for more details.                     *
00014  *                                                                  *
00015  * You should have received a copy of the GNU General Public License*
00016  * along with this program; if not, contact:                        *
00017  *                                                                  *
00018  * Free Software Foundation           Voice:  +1-617-542-5942       *
00019  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00020  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00021  *                                                                  *
00022  *******************************************************************/
00023 
00024 #include "config.h"
00025 #include "qofmath128-p.h"
00026 
00027 #include <glib.h>
00028 
00029 /* =============================================================== */
00030 /*
00031  *  Quick-n-dirty 128-bit integer math lib.   Things seem to mostly
00032  *  work, and have been tested, but not comprehensively tested.
00033  */
00034 
00035 #define HIBIT (0x8000000000000000ULL)
00036 
00040 qofint128
00041 mult128 (gint64 a, gint64 b)
00042 {
00043     qofint128 prod;
00044     guint64 a0, a1;
00045     guint64 b0, b1;
00046     guint64 d, d0, d1;
00047     guint64 e, e0, e1;
00048     guint64 f, f0, f1;
00049     guint64 g, g0, g1;
00050     guint64 sum, carry, roll, pmax;
00051 
00052     prod.isneg = 0;
00053     if (0 > a)
00054     {
00055         prod.isneg = !prod.isneg;
00056         a = -a;
00057     }
00058 
00059     if (0 > b)
00060     {
00061         prod.isneg = !prod.isneg;
00062         b = -b;
00063     }
00064 
00065     a1 = a >> 32;
00066     a0 = a - (a1 << 32);
00067 
00068     b1 = b >> 32;
00069     b0 = b - (b1 << 32);
00070 
00071     d = a0 * b0;
00072     d1 = d >> 32;
00073     d0 = d - (d1 << 32);
00074 
00075     e = a0 * b1;
00076     e1 = e >> 32;
00077     e0 = e - (e1 << 32);
00078 
00079     f = a1 * b0;
00080     f1 = f >> 32;
00081     f0 = f - (f1 << 32);
00082 
00083     g = a1 * b1;
00084     g1 = g >> 32;
00085     g0 = g - (g1 << 32);
00086 
00087     sum = d1 + e0 + f0;
00088     carry = 0;
00089     /* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
00090     roll = 1 << 30;
00091     roll <<= 2;
00092 
00093     pmax = roll - 1;
00094     while (pmax < sum)
00095     {
00096         sum -= roll;
00097         carry ++;
00098     }
00099 
00100     prod.lo = d0 + (sum << 32);
00101     prod.hi = carry + e1 + f1 + g0 + (g1 << 32);
00102     // prod.isbig = (prod.hi || (sum >> 31));
00103     prod.isbig = prod.hi || (prod.lo >> 63);
00104 
00105     return prod;
00106 }
00107 
00109 qofint128
00110 shift128 (qofint128 x)
00111 {
00112     guint64 sbit = x.hi & 0x1;
00113     x.hi >>= 1;
00114     x.lo >>= 1;
00115     x.isbig = 0;
00116     if (sbit)
00117     {
00118         x.lo |= HIBIT;
00119         x.isbig = 1;
00120         return x;
00121     }
00122     if (x.hi)
00123     {
00124         x.isbig = 1;
00125     }
00126     return x;
00127 }
00128 
00130 qofint128
00131 shiftleft128 (qofint128 x)
00132 {
00133     guint64 sbit;
00134     sbit = x.lo & HIBIT;
00135     x.hi <<= 1;
00136     x.lo <<= 1;
00137     x.isbig = 0;
00138     if (sbit)
00139     {
00140         x.hi |= 1;
00141         x.isbig = 1;
00142         return x;
00143     }
00144     if (x.hi)
00145     {
00146         x.isbig = 1;
00147     }
00148     return x;
00149 }
00150 
00152 qofint128
00153 inc128 (qofint128 a)
00154 {
00155     if (0 == a.isneg)
00156     {
00157         a.lo ++;
00158         if (0 == a.lo)
00159         {
00160             a.hi ++;
00161         }
00162     }
00163     else
00164     {
00165         if (0 == a.lo)
00166         {
00167             a.hi --;
00168         }
00169         a.lo --;
00170     }
00171 
00172     a.isbig = (a.hi != 0) || (a.lo >> 63);
00173     return a;
00174 }
00175 
00179 qofint128
00180 div128 (qofint128 n, gint64 d)
00181 {
00182     qofint128 quotient;
00183     int i;
00184     guint64 remainder = 0;
00185 
00186     quotient = n;
00187     if (0 > d)
00188     {
00189         d = -d;
00190         quotient.isneg = !quotient.isneg;
00191     }
00192 
00193     /* Use grade-school long division algorithm */
00194     for (i = 0; i < 128; i++)
00195     {
00196         guint64 sbit = HIBIT & quotient.hi;
00197         remainder <<= 1;
00198         if (sbit) remainder |= 1;
00199         quotient = shiftleft128 (quotient);
00200         if (remainder >= d)
00201         {
00202             remainder -= d;
00203             quotient.lo |= 1;
00204         }
00205     }
00206 
00207     /* compute the carry situation */
00208     quotient.isbig = (quotient.hi || (quotient.lo >> 63));
00209 
00210     return quotient;
00211 }
00212 
00218 gint64
00219 rem128 (qofint128 n, gint64 d)
00220 {
00221     qofint128 quotient = div128 (n, d);
00222 
00223     qofint128 mu = mult128 (quotient.lo, d);
00224 
00225     gint64 nn = 0x7fffffffffffffffULL & n.lo;
00226     gint64 rr = 0x7fffffffffffffffULL & mu.lo;
00227     return nn - rr;
00228 }
00229 
00231 gboolean
00232 equal128 (qofint128 a, qofint128 b)
00233 {
00234     if (a.lo != b.lo) return 0;
00235     if (a.hi != b.hi) return 0;
00236     if (a.isneg != b.isneg) return 0;
00237     return 1;
00238 }
00239 
00241 int
00242 cmp128 (qofint128 a, qofint128 b)
00243 {
00244     if ((0 == a.isneg) && b.isneg) return 1;
00245     if (a.isneg && (0 == b.isneg)) return -1;
00246     if (0 == a.isneg)
00247     {
00248         if (a.hi > b.hi) return 1;
00249         if (a.hi < b.hi) return -1;
00250         if (a.lo > b.lo) return 1;
00251         if (a.lo < b.lo) return -1;
00252         return 0;
00253     }
00254 
00255     if (a.hi > b.hi) return -1;
00256     if (a.hi < b.hi) return 1;
00257     if (a.lo > b.lo) return -1;
00258     if (a.lo < b.lo) return 1;
00259     return 0;
00260 }
00261 
00263 guint64
00264 gcf64(guint64 num, guint64 denom)
00265 {
00266     guint64   t;
00267 
00268     t =  num % denom;
00269     num = denom;
00270     denom = t;
00271 
00272     /* The strategy is to use Euclid's algorithm */
00273     while (0 != denom)
00274     {
00275         t = num % denom;
00276         num = denom;
00277         denom = t;
00278     }
00279     /* num now holds the GCD (Greatest Common Divisor) */
00280     return num;
00281 }
00282 
00284 qofint128
00285 lcm128 (guint64 a, guint64 b)
00286 {
00287     guint64 gcf = gcf64 (a, b);
00288     b /= gcf;
00289     return mult128 (a, b);
00290 }
00291 
00293 qofint128
00294 add128 (qofint128 a, qofint128 b)
00295 {
00296     qofint128 sum;
00297     if (a.isneg == b.isneg)
00298     {
00299         sum.isneg = a.isneg;
00300         sum.hi = a.hi + b.hi;
00301         sum.lo = a.lo + b.lo;
00302         if ((sum.lo < a.lo) || (sum.lo < b.lo))
00303         {
00304             sum.hi ++;
00305         }
00306         sum.isbig = sum.hi || (sum.lo >> 63);
00307         return sum;
00308     }
00309     if ((b.hi > a.hi) ||
00310             ((b.hi == a.hi) && (b.lo > a.lo)))
00311     {
00312         qofint128 tmp = a;
00313         a = b;
00314         b = tmp;
00315     }
00316 
00317     sum.isneg = a.isneg;
00318     sum.hi = a.hi - b.hi;
00319     sum.lo = a.lo - b.lo;
00320 
00321     if (sum.lo > a.lo)
00322     {
00323         sum.hi --;
00324     }
00325 
00326     sum.isbig = sum.hi || (sum.lo >> 63);
00327     return sum;
00328 }
00329 
00330 
00331 #ifdef TEST_128_BIT_MULT
00332 
00333 static void pr (gint64 a, gint64 b)
00334 {
00335     qofint128 prod = mult128 (a, b);
00336     printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " = %"
00337             G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " (0x%"
00338             G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x) %hd\n",
00339             a, b, prod.hi, prod.lo, prod.hi, prod.lo, prod.isbig);
00340 }
00341 
00342 static void prd (gint64 a, gint64 b, gint64 c)
00343 {
00344     qofint128 prod = mult128 (a, b);
00345     qofint128 quot = div128 (prod, c);
00346     gint64 rem = rem128 (prod, c);
00347     printf ("%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT
00348             " = %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " + %"
00349             G_GINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x %"
00350             G_GINT64_MODIFIER "x) %hd\n",
00351             a, b, c, quot.hi, quot.lo, rem, quot.hi, quot.lo, quot.isbig);
00352 }
00353 
00354 int main ()
00355 {
00356     gint64 x;
00357     qofint128 n;
00358     gint64 d;
00359     qofint128 quot;
00360     int i;
00361 
00362     pr (2, 2);
00363 
00364     x = 1 << 30;
00365     x <<= 2;
00366 
00367     pr (x, x);
00368     pr (x + 1, x);
00369     pr (x + 1, x + 1);
00370 
00371     pr (x, -x);
00372     pr (-x, -x);
00373     pr (x - 1, x);
00374     pr (x - 1, x - 1);
00375     pr (x - 2, x - 2);
00376 
00377     x <<= 1;
00378     pr (x, x);
00379     pr (x, -x);
00380 
00381     pr (1000000, G_GINT64_CONSTANT(10000000000000));
00382 
00383     prd (x, x, 2);
00384     prd (x, x, 3);
00385     prd (x, x, 4);
00386     prd (x, x, 5);
00387     prd (x, x, 6);
00388 
00389     x <<= 29;
00390     prd (3, x, 3);
00391     prd (6, x, 3);
00392     prd (99, x, 3);
00393     prd (100, x, 5);
00394     prd (540, x, 5);
00395     prd (777, x, 7);
00396     prd (1111, x, 11);
00397 
00398     /* Really test division */
00399     n.hi = 0xdd91;
00400     n.lo = 0x6c5abefbb9e13480ULL;
00401 
00402     d = 0x2ae79964d3ae1d04ULL;
00403 
00404     for (i = 0; i < 20; i++)
00405     {
00406 
00407         quot = div128 (n, d);
00408         printf ("%d result = %" G_GINT64_MODIFIER "x %" G_GINT64_MODIFIER "x\n",
00409                 i, quot.hi, quot.lo);
00410         d >>= 1;
00411         n = shift128 (n);
00412     }
00413     return 0;
00414 }
00415 
00416 #endif /* TEST_128_BIT_MULT */
00417 
00418 /* ======================== END OF FILE =================== */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines