[Gnucash-changes] start of quick-n-dirty 128-bit math lib
Linas Vepstas
linas at cvs.gnucash.org
Sat May 29 20:18:35 EDT 2004
Log Message:
-----------
start of quick-n-dirty 128-bit math lib
Modified Files:
--------------
gnucash/src/engine:
gnc-numeric.c
Revision Data
-------------
Index: gnc-numeric.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/gnc-numeric.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -Lsrc/engine/gnc-numeric.c -Lsrc/engine/gnc-numeric.c -u -r1.30 -r1.31
--- src/engine/gnc-numeric.c
+++ src/engine/gnc-numeric.c
@@ -40,6 +40,108 @@
/* static short module = MOD_ENGINE; */
+/* =============================================================== */
+/* Quick-n-dirty 128-bit math lib */
+
+typedef struct {
+ gint64 hi;
+ guint64 lo;
+} gncint128;
+
+static inline gncint128
+mult (gint64 a, gint64 b)
+{
+ gncint128 prod;
+ short aneg=0, bneg=0;
+
+ if (0>a)
+ {
+ aneg = 1;
+ a = -a;
+ }
+
+ if (0>b)
+ {
+ bneg = 1;
+ b = -b;
+ }
+
+ guint64 a1 = a >> 32;
+ guint64 a0 = a - (a1<<32);
+
+ guint64 b1 = b >> 32;
+ guint64 b0 = b - (b1<<32);
+
+ guint64 d = a0*b0;
+ guint64 d1 = d >> 32;
+ guint64 d0 = d - (d1<<32);
+
+ guint64 e = a0*b1;
+ guint64 e1 = e >> 32;
+ guint64 e0 = e - (e1<<32);
+
+ guint64 f = a1*b0;
+ guint64 f1 = f >> 32;
+ guint64 f0 = f - (f1<<32);
+
+ guint64 g = a1*b1;
+ guint64 g1 = g >> 32;
+ guint64 g0 = g - (g1<<32);
+
+ guint64 sum = d1+e0+f0;
+ guint64 carry = 0;
+ /* Can't say 1<<32 cause cpp will goof it up; 1ULL<<32 might work */
+ guint64 roll = 1<<30;
+ roll <<= 2;
+
+ guint64 pmax = roll-1;
+ while (pmax < sum)
+ {
+ sum -= roll;
+ carry ++;
+ }
+
+ prod.lo = d0 + (sum<<32);
+ prod.hi = carry + e1 + f1 + g0 + (g1<<32);
+
+ if (aneg) prod.hi = -prod.hi;
+ if (bneg) prod.hi = -prod.hi;
+
+ return prod;
+}
+
+#ifdef TEST_128_BIT_MULT
+void pr (gint64 a, gint64 b)
+{
+ gncint128 prod = mult (a,b);
+ printf ("%lld * %lld = %lld %llu (0x%llx %llx)\n", a,b, prod.hi, prod.lo, prod.hi, prod.lo);
+}
+
+main ()
+{
+ pr (2,2);
+
+ gint64 x = 1<<30;
+ x <<= 2;
+
+ pr (x,x);
+ pr (x+1,x);
+ pr (x+1,x+1);
+
+ pr (x,-x);
+ pr (-x,-x);
+ pr (x-1,x);
+ pr (x-1,x-1);
+ pr (x-2,x-2);
+
+ x <<= 1;
+ pr (x,x);
+ pr (x,-x);
+}
+#endif /* TEST_128_BIT_MULT */
+
+/* =============================================================== */
+
#if 0
static const char * _numeric_error_strings[] =
{
@@ -53,6 +155,7 @@
static gint64 gnc_numeric_lcd(gnc_numeric a, gnc_numeric b);
+/* =============================================================== */
/* This function is small, simple, and used everywhere below,
* lets try to inline it.
*/
More information about the gnucash-changes
mailing list