added last changes
authorMartin Weindel <mweindel@mono-cvs.ximian.com>
Tue, 13 Nov 2001 18:34:45 +0000 (18:34 -0000)
committerMartin Weindel <mweindel@mono-cvs.ximian.com>
Tue, 13 Nov 2001 18:34:45 +0000 (18:34 -0000)
svn path=/trunk/mono/; revision=1344

mono/metadata/decimal.c
mono/metadata/decimal.h

index 55bf5d7f5e9866d111664653e33ab478e6de68a0..bd19108e258474ec85ad78c0cdd8ec9dc2e4f142 100644 (file)
@@ -72,16 +72,6 @@ typedef unsigned __int64 guint64; /* that's normally defined in glib */
 #define INVARIANT_TEST(p)
 #endif //#ifdef _DEBUG
 
-/*
-void DECSIGNATURE printdec(decimal_repr* pA)
-{
-    printf("sign=%d scale=%d %u %u %u\n", (int)pA->signscale.sign, (int) pA->signscale.scale,
-        pA->hi32, pA->mid32, pA->lo32);
-}
-*/
-
-#define DECIMAL_REPR_CONSTANT(ss, hi, mid, lo)  {{ss}, hi, lo, mid}
-
 #define DECIMAL_MAX_SCALE 28
 #define DECIMAL_MAX_INTFACTORS 9
 
@@ -92,6 +82,7 @@ void DECSIGNATURE printdec(decimal_repr* pA)
 #define DECIMAL_INTERNAL_ERROR 3
 #define DECIMAL_INVALID_BITS 4
 #define DECIMAL_DIVIDE_BY_ZERO 5
+#define DECIMAL_BUFFER_OVERFLOW 6
 
 /* some MACROS */
 #define DECINIT(src) memset(src, 0, sizeof(decimal_repr))
@@ -106,6 +97,8 @@ void DECSIGNATURE printdec(decimal_repr* pA)
 
 #define DECNEGATE(p1) (p1)->signscale.sign = 1 - (p1)->signscale.sign
 
+#define LIT_DEC128(hi, mid, lo) { (((guint64)mid)<<32 | lo), hi }
+
 #define DECTO128(pd, lo, hi) \
        lo = (((guint64)(pd)->mid32) << 32) | (pd)->lo32; \
     hi = (pd)->hi32;
@@ -116,47 +109,52 @@ void DECSIGNATURE printdec(decimal_repr* pA)
 
 #define DECIMAL_LOG_NEGINF -1000
 
-static guint32 constantsIntFactors[DECIMAL_MAX_INTFACTORS+1] = {
+static guint32 constantsDecadeInt32Factors[DECIMAL_MAX_INTFACTORS+1] = {
     LIT_GUINT32(1), LIT_GUINT32(10), LIT_GUINT32(100), LIT_GUINT32(1000), 
     LIT_GUINT32(10000), LIT_GUINT32(100000), LIT_GUINT32(1000000), 
     LIT_GUINT32(10000000), LIT_GUINT32(100000000), LIT_GUINT32(1000000000)
 };
 
-static decimal_repr constantsFactors[DECIMAL_MAX_SCALE+1] = {
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 1), /* == 1 */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 10), /* == 10 */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 100), /* == 100 */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 1000), /* == 1e3m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 10000), /* == 1e4m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 100000), /* == 1e5m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 1000000), /* == 1e6m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 10000000), /* == 1e7m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 100000000), /* == 1e8m */
-    DECIMAL_REPR_CONSTANT(0, 0, 0, 1000000000), /* == 1e9m */
-    DECIMAL_REPR_CONSTANT(0, 0, 2, 1410065408), /* == 1e10m */
-    DECIMAL_REPR_CONSTANT(0, 0, 23, 1215752192), /* == 1e11m */
-    DECIMAL_REPR_CONSTANT(0, 0, 232, 3567587328U), /* == 1e12m */
-    DECIMAL_REPR_CONSTANT(0, 0, 2328, 1316134912), /* == 1e13m */
-    DECIMAL_REPR_CONSTANT(0, 0, 23283, 276447232), /* == 1e14m */
-    DECIMAL_REPR_CONSTANT(0, 0, 232830, 2764472320U), /* == 1e15m */
-    DECIMAL_REPR_CONSTANT(0, 0, 2328306, 1874919424), /* == 1e16m */
-    DECIMAL_REPR_CONSTANT(0, 0, 23283064, 1569325056), /* == 1e17m */
-    DECIMAL_REPR_CONSTANT(0, 0, 232830643, 2808348672U), /* == 1e18m */
-    DECIMAL_REPR_CONSTANT(0, 0, 2328306436U, 2313682944U), /* == 1e19m */
-    DECIMAL_REPR_CONSTANT(0, 5, 1808227885, 1661992960), /* == 1e20m */
-    DECIMAL_REPR_CONSTANT(0, 54, 902409669, 3735027712U), /* == 1e21m */
-    DECIMAL_REPR_CONSTANT(0, 542, 434162106, 2990538752U), /* == 1e22m */
-    DECIMAL_REPR_CONSTANT(0, 5421, 46653770, 4135583744U), /* == 1e23m */
-    DECIMAL_REPR_CONSTANT(0, 54210, 466537709, 2701131776U), /* == 1e24m */
-    DECIMAL_REPR_CONSTANT(0, 542101, 370409800, 1241513984), /* == 1e25m */
-    DECIMAL_REPR_CONSTANT(0, 5421010, 3704098002U, 3825205248U), /* == 1e26m */
-    DECIMAL_REPR_CONSTANT(0, 54210108, 2681241660U, 3892314112U), /* == 1e27m */
-    DECIMAL_REPR_CONSTANT(0, 542101086, 1042612833, 268435456), /* == 1e28m */
+typedef struct {
+    guint64 lo;
+    guint64 hi;
+} dec128_repr;
+
+static dec128_repr dec128decadeFactors[DECIMAL_MAX_SCALE+1] = {
+    LIT_DEC128( 0, 0, 1u), /* == 1 */
+    LIT_DEC128( 0, 0, 10u), /* == 10 */
+    LIT_DEC128( 0, 0, 100u), /* == 100 */
+    LIT_DEC128( 0, 0, 1000u), /* == 1e3m */
+    LIT_DEC128( 0, 0, 10000u), /* == 1e4m */
+    LIT_DEC128( 0, 0, 100000u), /* == 1e5m */
+    LIT_DEC128( 0, 0, 1000000u), /* == 1e6m */
+    LIT_DEC128( 0, 0, 10000000u), /* == 1e7m */
+    LIT_DEC128( 0, 0, 100000000u), /* == 1e8m */
+    LIT_DEC128( 0, 0, 1000000000u), /* == 1e9m */
+    LIT_DEC128( 0, 2u, 1410065408u), /* == 1e10m */
+    LIT_DEC128( 0, 23u, 1215752192u), /* == 1e11m */
+    LIT_DEC128( 0, 232u, 3567587328u), /* == 1e12m */
+    LIT_DEC128( 0, 2328u, 1316134912u), /* == 1e13m */
+    LIT_DEC128( 0, 23283u, 276447232u), /* == 1e14m */
+    LIT_DEC128( 0, 232830u, 2764472320u), /* == 1e15m */
+    LIT_DEC128( 0, 2328306u, 1874919424u), /* == 1e16m */
+    LIT_DEC128( 0, 23283064u, 1569325056u), /* == 1e17m */
+    LIT_DEC128( 0, 232830643u, 2808348672u), /* == 1e18m */
+    LIT_DEC128( 0, 2328306436u, 2313682944u), /* == 1e19m */
+    LIT_DEC128( 5u, 1808227885u, 1661992960u), /* == 1e20m */
+    LIT_DEC128( 54u, 902409669u, 3735027712u), /* == 1e21m */
+    LIT_DEC128( 542u, 434162106u, 2990538752u), /* == 1e22m */
+    LIT_DEC128( 5421u, 46653770u, 4135583744u), /* == 1e23m */
+    LIT_DEC128( 54210u, 466537709u, 2701131776u), /* == 1e24m */
+    LIT_DEC128( 542101u, 370409800u, 1241513984u), /* == 1e25m */
+    LIT_DEC128( 5421010u, 3704098002u, 3825205248u), /* == 1e26m */
+    LIT_DEC128( 54210108u, 2681241660u, 3892314112u), /* == 1e27m */
+    LIT_DEC128( 542101086u, 1042612833u, 268435456u), /* == 1e28m */
 };
 
 /* 192 bit addition: c = a + b 
    addition is modulo 2**128, any carry is lost */
-static DECINLINE void add128(guint64 alo, guint64 ahi,
+DECINLINE static void add128(guint64 alo, guint64 ahi,
                              guint64 blo, guint64 bhi,
                              guint64* pclo, guint64* pchi)
 {
@@ -170,7 +168,7 @@ static DECINLINE void add128(guint64 alo, guint64 ahi,
 
 /* 128 bit subtraction: c = a - b
    subtraction is modulo 2**128, any carry is lost */
-static DECINLINE void sub128(guint64 alo, guint64 ahi,
+DECINLINE static void sub128(guint64 alo, guint64 ahi,
                              guint64 blo, guint64 bhi,
                              guint64* pclo, guint64* pchi)
 {
@@ -186,7 +184,7 @@ static DECINLINE void sub128(guint64 alo, guint64 ahi,
 
 /* 192 bit addition: c = a + b 
    addition is modulo 2**192, any carry is lost */
-static DECINLINE void add192(guint64 alo, guint64 ami, guint64 ahi,
+DECINLINE static void add192(guint64 alo, guint64 ami, guint64 ahi,
                              guint64 blo, guint64 bmi, guint64 bhi,
                              guint64* pclo, guint64* pcmi, guint64* pchi)
 {
@@ -205,7 +203,7 @@ static DECINLINE void add192(guint64 alo, guint64 ami, guint64 ahi,
 
 /* 192 bit subtraction: c = a - b
    subtraction is modulo 2**192, any carry is lost */
-static DECINLINE void sub192(guint64 alo, guint64 ami, guint64 ahi,
+DECINLINE static void sub192(guint64 alo, guint64 ami, guint64 ahi,
                              guint64 blo, guint64 bmi, guint64 bhi,
                              guint64* pclo, guint64* pcmi, guint64* pchi)
 {
@@ -225,7 +223,7 @@ static DECINLINE void sub192(guint64 alo, guint64 ami, guint64 ahi,
 }
 
 /* multiplication c(192bit) = a(96bit) * b(96bit) */
-static DECINLINE void mult96by96to192(guint32 alo, guint32 ami, guint32 ahi,
+DECINLINE static void mult96by96to192(guint32 alo, guint32 ami, guint32 ahi,
                                       guint32 blo, guint32 bmi, guint32 bhi,
                                       guint64* pclo, guint64* pcmi, guint64* pchi)
 {
@@ -273,7 +271,7 @@ static DECINLINE void mult96by96to192(guint32 alo, guint32 ami, guint32 ahi,
 }
 
 /* multiplication c(128bit) = a(96bit) * b(32bit) */
-static DECINLINE void mult96by32to128(guint32 alo, guint32 ami, guint32 ahi,
+DECINLINE static void mult96by32to128(guint32 alo, guint32 ami, guint32 ahi,
                                       guint32 factor,
                                       guint64* pclo, guint64* pchi)
 {
@@ -295,20 +293,20 @@ static DECINLINE void mult96by32to128(guint32 alo, guint32 ami, guint32 ahi,
 }
 
 /* multiplication c(128bit) *= b(32bit) */
-static DECINLINE int mult128by32(guint64* pclo, guint64* pchi, guint32 factor, int roundBit)
+DECINLINE static int mult128by32(guint64* pclo, guint64* pchi, guint32 factor, int roundBit)
 {
     guint64 a;
     guint32 h0, h1;
 
     a = ((guint64)(guint32)(*pclo)) * factor;
-       if (roundBit) a += factor / 2;
+    if (roundBit) a += factor / 2;
     h0 = (guint32) a;
 
     a >>= 32;
     a += (*pclo >> 32) * factor;
     h1 = (guint32) a;
 
-       *pclo = ((guint64)h1) << 32 | h0;
+    *pclo = ((guint64)h1) << 32 | h0;
 
     a >>= 32;
     a += ((guint64)(guint32)(*pchi)) * factor;
@@ -318,14 +316,27 @@ static DECINLINE int mult128by32(guint64* pclo, guint64* pchi, guint32 factor, i
     a += (*pchi >> 32) * factor;
     h1 = (guint32) a;
 
-       *pchi = ((guint64)h1) << 32 | h0;
+    *pchi = ((guint64)h1) << 32 | h0;
 
-       return ((a >> 32) == 0) ? DECIMAL_SUCCESS : DECIMAL_OVERFLOW;
+    return ((a >> 32) == 0) ? DECIMAL_SUCCESS : DECIMAL_OVERFLOW;
+}
+
+DECINLINE static int mult128DecadeFactor(guint64* pclo, guint64* pchi, int powerOfTen)
+{
+    int index, rc;
+
+    while (powerOfTen > 0) {
+        index = (powerOfTen >= DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : powerOfTen;
+        powerOfTen -= index;
+        rc = mult128by32(pclo, pchi, constantsDecadeInt32Factors[index], 0);
+        if (rc != DECIMAL_SUCCESS) return rc;
+    }
+    return DECIMAL_SUCCESS;
 }
 
 /* division: x(128bit) /= factor(32bit) 
    returns roundBit */
-static DECINLINE int div128by32(guint64* plo, guint64* phi, guint32 factor, guint32* pRest)
+DECINLINE static int div128by32(guint64* plo, guint64* phi, guint32 factor, guint32* pRest)
 {
     guint64 a, b, c, h;
 
@@ -350,15 +361,15 @@ static DECINLINE int div128by32(guint64* plo, guint64* phi, guint32 factor, guin
     a -= c * factor;
     *plo = b << 32 | (guint32)c;
 
-       if (pRest) *pRest = (guint32) a;
+    if (pRest) *pRest = (guint32) a;
 
-       a <<= 1;
-       return (a > factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
+    a <<= 1;
+    return (a > factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
 }
 
 /* division: x(192bit) /= factor(32bit) 
    no rest and no rounding*/
-static DECINLINE void div192by32(guint64* plo, guint64* pmi, guint64* phi,
+DECINLINE static void div192by32(guint64* plo, guint64* pmi, guint64* phi,
                                  guint32 factor)
 {
     guint64 a, b, c, h;
@@ -399,14 +410,14 @@ static DECINLINE void div192by32(guint64* plo, guint64* pmi, guint64* phi,
 
 /* returns upper 32bit for a(192bit) /= b(32bit)
    a will contain remainder */
-static DECINLINE guint32 div192by96to32withRest(guint64* palo, guint64* pami, guint64* pahi, 
-                                                                                               guint32 blo, guint32 bmi, guint32 bhi)
+static guint32 div192by96to32withRest(guint64* palo, guint64* pami, guint64* pahi, 
+                                      guint32 blo, guint32 bmi, guint32 bhi)
 {
     guint64 rlo, rmi, rhi; /* remainder */
     guint64 tlo, thi; /* term */
-       guint32 c;
+    guint32 c;
 
-       rlo = *palo; rmi = *pami; rhi = *pahi;
+    rlo = *palo; rmi = *pami; rhi = *pahi;
     if (rhi >= (((guint64)bhi) << 32)) {
         c = LIT_GUINT32(0xFFFFFFFF);
     } else {
@@ -418,701 +429,786 @@ static DECINLINE guint32 div192by96to32withRest(guint64* palo, guint64* pami, gu
         c--;
         add192(rlo, rmi, rhi, 0, (((guint64)bmi)<<32) | blo, bhi, &rlo, &rmi, &rhi);
     }
-       *palo = rlo ; *pami = rmi ; *pahi = rhi;
+    *palo = rlo ; *pami = rmi ; *pahi = rhi;
 
-       POSTCONDITION(rhi >> 32 == 0);
+    POSTCONDITION(rhi >> 32 == 0);
 
-       return c;
+    return c;
 }
 
 /* c(128bit) = a(192bit) / b(96bit) 
    b must be >= 2^95 */
-static DECINLINE void div192by96to128(guint64 alo, guint64 ami, guint64 ahi,
-                                    guint32 blo, guint32 bmi, guint32 bhi,
-                                    guint64* pclo, guint64* pchi)
+static void div192by96to128(guint64 alo, guint64 ami, guint64 ahi,
+                            guint32 blo, guint32 bmi, guint32 bhi,
+                            guint64* pclo, guint64* pchi)
 {
     guint64 rlo, rmi, rhi; /* remainder */
-       guint32 h, c;
+    guint32 h, c;
 
     PRECONDITION(ahi < (((guint64)bhi) << 32 | bmi) 
-               || (ahi == (((guint64)bhi) << 32 | bmi) && (ami >> 32) > blo));
+        || (ahi == (((guint64)bhi) << 32 | bmi) && (ami >> 32) > blo));
 
     /* high 32 bit*/
-       rlo = alo; rmi = ami; rhi = ahi;
-       h = div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
+    rlo = alo; rmi = ami; rhi = ahi;
+    h = div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
 
     /* mid 32 bit*/
     rhi = (rhi << 32) | (rmi >> 32); rmi = (rmi << 32) | (rlo >> 32); rlo <<= 32;
-       *pchi = (((guint64)h) << 32) | div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
+    *pchi = (((guint64)h) << 32) | div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
 
     /* low 32 bit */
     rhi = (rhi << 32) | (rmi >> 32); rmi = (rmi << 32) | (rlo >> 32); rlo <<= 32;
-       h = div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
+    h = div192by96to32withRest(&rlo, &rmi, &rhi, blo, bmi, bhi);
 
     /* estimate lowest 32 bit (two last bits may be wrong) */
     if (rhi >= bhi) {
         c = LIT_GUINT32(0xFFFFFFFF);
     } else {
-               rhi <<= 32;
+        rhi <<= 32;
         c = (guint32) (rhi / bhi);
     }
-       *pclo = (((guint64)h) << 32) | c;
+    *pclo = (((guint64)h) << 32) | c;
 }
 
-static DECINLINE void roundUp128(guint64* pclo, guint64* pchi) {
-       if (++(*pclo) == 0) ++(*pchi);
+DECINLINE static void roundUp128(guint64* pclo, guint64* pchi) {
+    if (++(*pclo) == 0) ++(*pchi);
 }
 
 static int normalize128(guint64* pclo, guint64* pchi, int* pScale, 
-                                               int roundFlag, int roundBit)
+                        int roundFlag, int roundBit)
 {
-       guint32 overhang = (guint32)(*pchi >> 32);
-       int scale = *pScale;
-       int deltaScale;
-
-       while (overhang != 0) {
-           for (deltaScale = 1; deltaScale < DECIMAL_MAX_INTFACTORS; deltaScale++)
-               {
-                       if (overhang < constantsIntFactors[deltaScale]) break;
-           }
-
-               scale -= deltaScale;
-               if (scale < 0) return DECIMAL_OVERFLOW;
-
-               roundBit = div128by32(pclo, pchi, constantsIntFactors[deltaScale], 0);
-
-               overhang = (guint32)(*pchi >> 32);
-               if (roundFlag && roundBit && *pclo == (guint64)-1 && (gint32)*pchi == (gint32)-1) {
-                       overhang = 1;
-               }
-       }
-
-       *pScale = scale;
-
-       if (roundFlag && roundBit) {
-               roundUp128(pclo, pchi);
-               TEST((*pchi >> 32) == 0);
-       }
-       
-       return DECIMAL_SUCCESS;
+    guint32 overhang = (guint32)(*pchi >> 32);
+    int scale = *pScale;
+    int deltaScale;
+
+    while (overhang != 0) {
+        for (deltaScale = 1; deltaScale < DECIMAL_MAX_INTFACTORS; deltaScale++)
+        {
+            if (overhang < constantsDecadeInt32Factors[deltaScale]) break;
+        }
+
+        scale -= deltaScale;
+        if (scale < 0) return DECIMAL_OVERFLOW;
+
+        roundBit = div128by32(pclo, pchi, constantsDecadeInt32Factors[deltaScale], 0);
+
+        overhang = (guint32)(*pchi >> 32);
+        if (roundFlag && roundBit && *pclo == (guint64)-1 && (gint32)*pchi == (gint32)-1) {
+            overhang = 1;
+        }
+    }
+
+    *pScale = scale;
+
+    if (roundFlag && roundBit) {
+        roundUp128(pclo, pchi);
+        TEST((*pchi >> 32) == 0);
+    }
+    
+    return DECIMAL_SUCCESS;
 }
 
-static DECINLINE int maxLeftShift(/*[In, Out]*/decimal_repr* pA)
+DECINLINE static int maxLeftShift(/*[In, Out]*/decimal_repr* pA)
 {
-       guint64 lo64 = (((guint64)(pA->mid32)) << 32) | pA->lo32;
-       guint32 hi32 = pA->hi32;
-       int shift;
-
-       for (shift = 0; ((gint32)hi32) >= 0 && shift < 96; shift++) {
-               hi32 <<= 1;
-               if (((gint64)lo64) < 0) hi32++;
-               lo64 <<= 1;
-       }
+    guint64 lo64 = (((guint64)(pA->mid32)) << 32) | pA->lo32;
+    guint32 hi32 = pA->hi32;
+    int shift;
+
+    for (shift = 0; ((gint32)hi32) >= 0 && shift < 96; shift++) {
+        hi32 <<= 1;
+        if (((gint64)lo64) < 0) hi32++;
+        lo64 <<= 1;
+    }
 
-       pA->lo32 = (guint32) lo64;
-       pA->mid32 = (guint32)(lo64>>32);
-       pA->hi32 = hi32;
+    pA->lo32 = (guint32) lo64;
+    pA->mid32 = (guint32)(lo64>>32);
+    pA->hi32 = hi32;
 
-       return shift;
+    return shift;
 }
 
-static DECINLINE void rshift128(guint64* pclo, guint64* pchi)
+DECINLINE static void rshift128(guint64* pclo, guint64* pchi)
 {
-       *pclo >>= 1;
-       if (*pchi & 1) *pclo |= LIT_GUINT64_HIGHBIT;
-       *pchi >>= 1;
+    *pclo >>= 1;
+    if (*pchi & 1) *pclo |= LIT_GUINT64_HIGHBIT;
+    *pchi >>= 1;
 }
 
-static DECINLINE void lshift96(guint32* pclo, guint32* pcmid, guint32* pchi)
+DECINLINE static void lshift96(guint32* pclo, guint32* pcmid, guint32* pchi)
 {
-       *pchi <<= 1;
-       if (*pcmid & LIT_GUINT32_HIGHBIT) (*pchi)++;
-       *pcmid <<= 1;
-       if (*pclo & LIT_GUINT32_HIGHBIT) (*pcmid)++;
-       *pclo <<= 1;
+    *pchi <<= 1;
+    if (*pcmid & LIT_GUINT32_HIGHBIT) (*pchi)++;
+    *pcmid <<= 1;
+    if (*pclo & LIT_GUINT32_HIGHBIT) (*pcmid)++;
+    *pclo <<= 1;
 }
 
-static DECINLINE void lshift128(guint64* pclo, guint64* pchi)
+DECINLINE static void lshift128(guint64* pclo, guint64* pchi)
 {
-       *pchi <<= 1;
-       if (*pclo & LIT_GUINT64_HIGHBIT) (*pchi)++;
-       *pclo <<= 1;
+    *pchi <<= 1;
+    if (*pclo & LIT_GUINT64_HIGHBIT) (*pchi)++;
+    *pclo <<= 1;
 }
 
-static DECINLINE void rshift192(guint64* pclo, guint64* pcmi, guint64* pchi)
+DECINLINE static void rshift192(guint64* pclo, guint64* pcmi, guint64* pchi)
 {
-       *pclo >>= 1;
-       if (*pcmi & 1) *pclo |= LIT_GUINT64_HIGHBIT;
-       *pcmi >>= 1;
-       if (*pchi & 1) *pcmi |= LIT_GUINT64_HIGHBIT;
-       *pchi >>= 1;
+    *pclo >>= 1;
+    if (*pcmi & 1) *pclo |= LIT_GUINT64_HIGHBIT;
+    *pcmi >>= 1;
+    if (*pchi & 1) *pcmi |= LIT_GUINT64_HIGHBIT;
+    *pchi >>= 1;
 }
 
 /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */
-static int DECINLINE log2_32(guint32 a)
+DECINLINE static int log2_32(guint32 a)
 {
-       int log2 = 0;
-
-       if (a == 0) return DECIMAL_LOG_NEGINF;
-
-       if ((a >> 16) != 0) {
-               a >>= 16;
-               log2 += 16;
-       }
-       if ((a >> 8) != 0) {
-               a >>= 8;
-               log2 += 8;
-       }
-       if ((a >> 4) != 0) {
-               a >>= 4;
-               log2 += 4;
-       }
-       if ((a >> 2) != 0) {
-               a >>= 2;
-               log2 += 2;
-       }
-       if ((a >> 1) != 0) {
-               a >>= 1;
-               log2 += 1;
-       }
-       log2 += (int) a;
-
-       return log2;
+    int log2 = 0;
+
+    if (a == 0) return DECIMAL_LOG_NEGINF;
+
+    if ((a >> 16) != 0) {
+        a >>= 16;
+        log2 += 16;
+    }
+    if ((a >> 8) != 0) {
+        a >>= 8;
+        log2 += 8;
+    }
+    if ((a >> 4) != 0) {
+        a >>= 4;
+        log2 += 4;
+    }
+    if ((a >> 2) != 0) {
+        a >>= 2;
+        log2 += 2;
+    }
+    if ((a >> 1) != 0) {
+        a >>= 1;
+        log2 += 1;
+    }
+    log2 += (int) a;
+
+    return log2;
 }
 
 /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */
-static int DECINLINE log2_64(guint64 a)
+DECINLINE static int log2_64(guint64 a)
 {
-       int log2 = 0;
-
-       if (a == 0) return DECIMAL_LOG_NEGINF;
-
-       if ((a >> 32) != 0) {
-               a >>= 32;
-               log2 += 32;
-       }
-       if ((a >> 16) != 0) {
-               a >>= 16;
-               log2 += 16;
-       }
-       if ((a >> 8) != 0) {
-               a >>= 8;
-               log2 += 8;
-       }
-       if ((a >> 4) != 0) {
-               a >>= 4;
-               log2 += 4;
-       }
-       if ((a >> 2) != 0) {
-               a >>= 2;
-               log2 += 2;
-       }
-       if ((a >> 1) != 0) {
-               a >>= 1;
-               log2 += 1;
-       }
-       log2 += (int) a;
-
-       return log2;
+    int log2 = 0;
+
+    if (a == 0) return DECIMAL_LOG_NEGINF;
+
+    if ((a >> 32) != 0) {
+        a >>= 32;
+        log2 += 32;
+    }
+    if ((a >> 16) != 0) {
+        a >>= 16;
+        log2 += 16;
+    }
+    if ((a >> 8) != 0) {
+        a >>= 8;
+        log2 += 8;
+    }
+    if ((a >> 4) != 0) {
+        a >>= 4;
+        log2 += 4;
+    }
+    if ((a >> 2) != 0) {
+        a >>= 2;
+        log2 += 2;
+    }
+    if ((a >> 1) != 0) {
+        a >>= 1;
+        log2 += 1;
+    }
+    log2 += (int) a;
+
+    return log2;
 }
 
 /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */
-static int DECINLINE log2_128(guint64 alo, guint64 ahi)
+DECINLINE static int log2_128(guint64 alo, guint64 ahi)
 {
-       if (ahi == 0) return log2_64(alo);
-       else return log2_64(ahi) + 64;
+    if (ahi == 0) return log2_64(alo);
+    else return log2_64(ahi) + 64;
 }
 
 /* returns a upper limit for log2(a) considering scale */
-static int DECINLINE log2withScale_128(guint64 alo, guint64 ahi, int scale)
+DECINLINE static int log2withScale_128(guint64 alo, guint64 ahi, int scale)
 {
-       int log2 = log2_128(alo, ahi);
-       if (log2 < 0) log2 = 0;
-       return log2 - (scale * 33219) / 10000;
+    int log2 = log2_128(alo, ahi);
+    if (log2 < 0) log2 = 0;
+    return log2 - (scale * 33219) / 10000;
 }
 
-static DECINLINE int pack128toDecimal(/*[Out]*/decimal_repr* pA, guint64 alo, guint64 ahi,
-                                                                         int scale, int sign)
+DECINLINE static int pack128toDecimal(/*[Out]*/decimal_repr* pA, guint64 alo, guint64 ahi,
+                                      int scale, int sign)
 {
-       PRECONDITION((ahi >> 32) == 0);
-       PRECONDITION(sign == 0 || sign == 1);
-       PRECONDITION(scale >= 0 && scale <= DECIMAL_MAX_SCALE);
+    PRECONDITION((ahi >> 32) == 0);
+    PRECONDITION(sign == 0 || sign == 1);
+    PRECONDITION(scale >= 0 && scale <= DECIMAL_MAX_SCALE);
 
-       if (scale < 0 || scale > DECIMAL_MAX_SCALE || (ahi >> 32) != 0) {
-               return DECIMAL_OVERFLOW;
-       }
+    if (scale < 0 || scale > DECIMAL_MAX_SCALE || (ahi >> 32) != 0) {
+        return DECIMAL_OVERFLOW;
+    }
 
-       pA->lo32 = (guint32) alo;       
-       pA->mid32 = (guint32) (alo >> 32);      
-       pA->hi32 = (guint32) ahi;
-       pA->signscale.sign = sign;
-       pA->signscale.scale = scale;
+    pA->lo32 = (guint32) alo;   
+    pA->mid32 = (guint32) (alo >> 32);  
+    pA->hi32 = (guint32) ahi;
+    pA->signscale.sign = sign;
+    pA->signscale.scale = scale;
 
-       return DECIMAL_SUCCESS;
+    return DECIMAL_SUCCESS;
 }
 
-static DECINLINE int adjustScale128(guint64* palo, guint64* pahi, int deltaScale)
+DECINLINE static int adjustScale128(guint64* palo, guint64* pahi, int deltaScale)
 {
-       int index, rc;
-
-       if (deltaScale < 0) {
-               deltaScale *= -1;
-               if (deltaScale > DECIMAL_MAX_SCALE) return DECIMAL_INTERNAL_ERROR;
-               while (deltaScale > 0) {
-                       index = (deltaScale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : deltaScale;
-                       deltaScale -= index;
-                       div128by32(palo, pahi, constantsIntFactors[index], 0);
-               }
+    int index, rc;
+
+    if (deltaScale < 0) {
+        deltaScale *= -1;
+        if (deltaScale > DECIMAL_MAX_SCALE) return DECIMAL_INTERNAL_ERROR;
+        while (deltaScale > 0) {
+            index = (deltaScale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : deltaScale;
+            deltaScale -= index;
+            div128by32(palo, pahi, constantsDecadeInt32Factors[index], 0);
+        }
     } else if (deltaScale > 0) {
-               if (deltaScale > DECIMAL_MAX_SCALE) return DECIMAL_INTERNAL_ERROR;
-               while (deltaScale > 0) {
-                       index = (deltaScale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : deltaScale;
-                       deltaScale -= index;
-                       rc = mult128by32(palo, pahi, constantsIntFactors[index], 0);
-                       if (rc != DECIMAL_SUCCESS) return rc;
-               }
+        if (deltaScale > DECIMAL_MAX_SCALE) return DECIMAL_INTERNAL_ERROR;
+        while (deltaScale > 0) {
+            index = (deltaScale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : deltaScale;
+            deltaScale -= index;
+            rc = mult128by32(palo, pahi, constantsDecadeInt32Factors[index], 0);
+            if (rc != DECIMAL_SUCCESS) return rc;
+        }
     }
     
-       return DECIMAL_SUCCESS;
+    return DECIMAL_SUCCESS;
 }
 
 /* input: c * 10^-(*pScale) * 2^-exp
    output: c * 10^-(*pScale) with 
    minScale <= *pScale <= maxScale and (chi >> 32) == 0 */
-static int DECINLINE rescale128(guint64* pclo, guint64* pchi, int* pScale, int exp,
-                                                int minScale, int maxScale, int roundFlag)
+DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int exp,
+                                int minScale, int maxScale, int roundFlag)
 {
-       guint32 factor, overhang;
-       int scale, i, rc, roundBit = 0;
-
-       PRECONDITION(exp >= 0);
-
-       scale = *pScale;
-
-       if (exp > 0) {
-               /* reduce exp */
-               while (exp > 0 && scale <= maxScale) {
-                       overhang = (guint32)(*pchi >> 32);
-                       while (exp > 0 && ((*pclo & 1) == 0 || overhang > (2<<DECIMAL_MAX_INTFACTORS))) {
-                               if (--exp == 0) roundBit = (int)(*pclo & 1);
-                               rshift128(pclo, pchi);
-                               overhang = (guint32)(*pchi >> 32);
-                       }
-
-                       if (exp > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
-                       else i = exp;
-                       if (scale + i > maxScale) i = maxScale - scale;
-                       if (i == 0) break;
-                       exp -= i;
-                       scale += i;
-                       factor = constantsIntFactors[i] >> i; /* 10^i/2^i=5^i */
-                       mult128by32(pclo, pchi, factor, 0);
-       //printf("3: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -exp));
-               }
-
-               while (exp > 0) {
-                       if (--exp == 0) roundBit = (int)(*pclo & 1);
-                       rshift128(pclo, pchi);
-               }
-       }
-
-       TEST(exp == 0);
-
-       while (scale > maxScale) {
-               i = scale - maxScale;
-               if (i > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
-               scale -= i;
-               roundBit = div128by32(pclo, pchi, constantsIntFactors[i], 0);
-       }
-
-       while (scale < minScale) {
-               if (!roundFlag) roundBit = 0;
-               i = minScale - scale;
-               if (i > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
-               scale += i;
-               rc = mult128by32(pclo, pchi, constantsIntFactors[i], roundBit);
-               if (rc != DECIMAL_SUCCESS) return rc;
-               roundBit = 0;
-       }
-
-       TEST(scale >= 0 && scale <= DECIMAL_MAX_SCALE);
-
-       *pScale = scale;
-
-       return normalize128(pclo, pchi, pScale, roundFlag, roundBit);
+    guint32 factor, overhang;
+    int scale, i, rc, roundBit = 0;
+
+    PRECONDITION(exp >= 0);
+
+    scale = *pScale;
+
+    if (exp > 0) {
+        /* reduce exp */
+        while (exp > 0 && scale <= maxScale) {
+            overhang = (guint32)(*pchi >> 32);
+            while (exp > 0 && ((*pclo & 1) == 0 || overhang > (2<<DECIMAL_MAX_INTFACTORS))) {
+                if (--exp == 0) roundBit = (int)(*pclo & 1);
+                rshift128(pclo, pchi);
+                overhang = (guint32)(*pchi >> 32);
+            }
+
+            if (exp > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
+            else i = exp;
+            if (scale + i > maxScale) i = maxScale - scale;
+            if (i == 0) break;
+            exp -= i;
+            scale += i;
+            factor = constantsDecadeInt32Factors[i] >> i; /* 10^i/2^i=5^i */
+            mult128by32(pclo, pchi, factor, 0);
+    //printf("3: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -exp));
+        }
+
+        while (exp > 0) {
+            if (--exp == 0) roundBit = (int)(*pclo & 1);
+            rshift128(pclo, pchi);
+        }
+    }
+
+    TEST(exp == 0);
+
+    while (scale > maxScale) {
+        i = scale - maxScale;
+        if (i > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
+        scale -= i;
+        roundBit = div128by32(pclo, pchi, constantsDecadeInt32Factors[i], 0);
+    }
+
+    while (scale < minScale) {
+        if (!roundFlag) roundBit = 0;
+        i = minScale - scale;
+        if (i > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
+        scale += i;
+        rc = mult128by32(pclo, pchi, constantsDecadeInt32Factors[i], roundBit);
+        if (rc != DECIMAL_SUCCESS) return rc;
+        roundBit = 0;
+    }
+
+    TEST(scale >= 0 && scale <= DECIMAL_MAX_SCALE);
+
+    *pScale = scale;
+
+    return normalize128(pclo, pchi, pScale, roundFlag, roundBit);
 }
 
 /* performs a += b */
 gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
 {
-       guint64 alo, ahi, blo, bhi;
+    guint64 alo, ahi, blo, bhi;
     int log2A, log2B, log2Result, log10Result, rc;
-       int subFlag, sign, scaleA, scaleB;
+    int subFlag, sign, scaleA, scaleB;
 
-       DECTO128(pA, alo, ahi);
-       DECTO128(pB, blo, bhi);
+    DECTO128(pA, alo, ahi);
+    DECTO128(pB, blo, bhi);
 
-       sign = pA->signscale.sign;
+    sign = pA->signscale.sign;
     subFlag = sign - (int)pB->signscale.sign;
-       scaleA = pA->signscale.scale;
-       scaleB = pB->signscale.scale;
+    scaleA = pA->signscale.scale;
+    scaleB = pB->signscale.scale;
     if (scaleA == scaleB) {
         /* same scale, that's easy */
         if (subFlag) {
             sub128(alo, ahi, blo, bhi, &alo, &ahi);
-                       if (ahi & LIT_GUINT64_HIGHBIT) {
-                               alo--;
-                               alo = ~alo;
-                               if (alo == 0) ahi--;
-                               ahi = ~ahi;
-                               sign = !sign;
-                       }
+            if (ahi & LIT_GUINT64_HIGHBIT) {
+                alo--;
+                alo = ~alo;
+                if (alo == 0) ahi--;
+                ahi = ~ahi;
+                sign = !sign;
+            }
         } else {
             add128(alo, ahi, blo, bhi, &alo, &ahi);
         }
-               rc = normalize128(&alo, &ahi, &scaleA, 1, 0);
+        rc = normalize128(&alo, &ahi, &scaleA, 1, 0);
     } else {
-               /* scales must be adjusted */
+        /* scales must be adjusted */
         /* Estimate log10 and scale of result for adjusting scales */
         log2A = log2withScale_128(alo, ahi, scaleA);
         log2B = log2withScale_128(blo, bhi, scaleB);
         log2Result = (log2A >= log2B) ? log2A : log2B;
         if (!subFlag) log2Result++; /* result can have one bit more */
-               log10Result = (log2Result * 1000) / 3322 + 1;
-               /* we will calculate in 128bit, so we may need to adjust scale */
-               if (scaleB > scaleA) scaleA = scaleB;
+        log10Result = (log2Result * 1000) / 3322 + 1;
+        /* we will calculate in 128bit, so we may need to adjust scale */
+        if (scaleB > scaleA) scaleA = scaleB;
         if (scaleA + log10Result > DECIMAL_MAX_SCALE + 7) {
-                       /* this may not fit in 128bit, so limit it */
+            /* this may not fit in 128bit, so limit it */
             scaleA = DECIMAL_MAX_SCALE + 7 - log10Result;
         }
 
-               rc = adjustScale128(&alo, &ahi, scaleA - (int)pA->signscale.scale);
-               if (rc != DECIMAL_SUCCESS) return rc;
+        rc = adjustScale128(&alo, &ahi, scaleA - (int)pA->signscale.scale);
+        if (rc != DECIMAL_SUCCESS) return rc;
         rc = adjustScale128(&blo, &bhi, scaleA - scaleB);
-               if (rc != DECIMAL_SUCCESS) return rc;
+        if (rc != DECIMAL_SUCCESS) return rc;
 
-               if (subFlag) {
+        if (subFlag) {
             sub128(alo, ahi, blo, bhi, &alo, &ahi);
-                       if (ahi & LIT_GUINT64_HIGHBIT) {
-                               alo--;
-                               alo = ~alo;
-                               if (alo == 0) ahi--;
-                               ahi = ~ahi;
-                               sign = !sign;
-                       }
-               } else {
+            if (ahi & LIT_GUINT64_HIGHBIT) {
+                alo--;
+                alo = ~alo;
+                if (alo == 0) ahi--;
+                ahi = ~ahi;
+                sign = !sign;
+            }
+        } else {
             add128(alo, ahi, blo, bhi, &alo, &ahi);
         }
 
-               if (rc != DECIMAL_SUCCESS) return rc;
+        if (rc != DECIMAL_SUCCESS) return rc;
 
-               rc = rescale128(&alo, &ahi,&scaleA, 0, 0, DECIMAL_MAX_SCALE, 1);
+        rc = rescale128(&alo, &ahi,&scaleA, 0, 0, DECIMAL_MAX_SCALE, 1);
     }
 
-       if (rc != DECIMAL_SUCCESS) return rc;
+    if (rc != DECIMAL_SUCCESS) return rc;
 
-       return pack128toDecimal(pA, alo, ahi, scaleA, sign);
+    return pack128toDecimal(pA, alo, ahi, scaleA, sign);
 }
 
 /* performs a += factor * constants[index] */
 static int incMultConstant128(guint64* palo, guint64* pahi, int index, int factor)
 {
-       guint64 blo, bhi, h;
+    guint64 blo, bhi, h;
 
     PRECONDITION(index >= 0 && index <= DECIMAL_MAX_SCALE);
     PRECONDITION(factor > 0 && factor <= 9);
 
-       DECTO128(constantsFactors + index, blo, bhi);
-       if (factor != 1) {
-               h = bhi;
-               mult128by32(&blo, &bhi, factor, 0);
-               if (h > bhi) return DECIMAL_OVERFLOW;
-       }
-       h = *pahi;
-       add128(*palo, *pahi, blo, bhi, palo, pahi);
-       if (h > *pahi) return DECIMAL_OVERFLOW;
+    blo = dec128decadeFactors[index].lo;
+    h = bhi = dec128decadeFactors[index].hi;
+    if (factor != 1) {
+        mult128by32(&blo, &bhi, factor, 0);
+        if (h > bhi) return DECIMAL_OVERFLOW;
+    }
+    h = *pahi;
+    add128(*palo, *pahi, blo, bhi, palo, pahi);
+    if (h > *pahi) return DECIMAL_OVERFLOW;
     return DECIMAL_SUCCESS;
 }
 
-gint32 mono_double2decimal(/*[Out]*/decimal_repr* pA, double val, gint32 digits)
+DECINLINE static void div128DecadeFactor(guint64* palo, guint64* pahi, int powerOfTen)
 {
-    int i, dec, decrDecimal, dummySign, roundPos, roundFlag, rc;
-    char ecvtcopy[40]; /* we should need maximal room for 16 digits */
-    char buf[40]; /* we should need maximal room for 29 digits */
-    char* p;
-    char* ps;
-    gint32 sign = val < 0 ? 1 : 0;
-    decimal_repr roundAdd;
-    MonoString *mstring;
+    int index, roundBit = 0;
 
-    DECINIT(pA);
+    while (powerOfTen > 0) {
+        index = (powerOfTen > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : powerOfTen;
+        powerOfTen -= index;
+        roundBit = div128by32(palo, pahi, constantsDecadeInt32Factors[index], 0);
+    }
+
+    if (roundBit) roundUp128(palo, pahi);
+}
 
-    /* floating point number must be convert to the decimal system for rounding anyway 
-       so we use conversion to character representation as starting point.
-       We ask for more than the significant digits, as we must round
-       according to banker's rule finally */
-    /* FIXME: the following 2 lines must be made thread safe (access to global buffer of ecvt) */
-    p = ecvt(val, digits+4, &dec, &dummySign);
-    strcpy(ecvtcopy, p);
-    ps = ecvtcopy;
-
-    /*test printf("%s  %d  digits:%d\n", ps, dec, digits);*/
-    /* determine round position */
-    roundPos = dec + DECIMAL_MAX_SCALE;
-    if (roundPos > digits) roundPos = digits; /* maximal sigificant digits */
-
-    /* build decimal string */
-    p = buf;
-    /* leading zeros for numbers < 1 */
-    for (i = dec; i < 0; i++)
-        *p++ = '0';
-
-    /* significant digits */
-    for (i = 0; i < roundPos; i++)
-        *p++ = *ps++;
-
-    /* trailing zeros for numbers > 1 */
-    for (i = roundPos; i < dec; i++)
-        *p++ = '0';
-
-    /* end of string */
-    *p++ = 0;
-
-    /* position of decimal point */
-    if (dec > 0) {
-        decrDecimal = dec;
+/* calc significant digits of mantisse */
+DECINLINE static int calcDigits(guint64 alo, guint64 ahi)
+{
+    int log2 = 0;
+    int log10;
+
+    if (ahi == 0) {
+        if (alo == 0) {
+            return 0; /* zero has no signficant digits */
+        } else {
+            log2 = log2_64(alo);
+        }
     } else {
-        decrDecimal = 0; /* as we have added leading zero digits */
+        log2 = 64 + log2_64(ahi);
     }
 
-    /* convert string to decimal */
-    mstring = mono_string_new (buf);
-    rc = mono_string2decimal(pA, mstring, decrDecimal, sign);
-    /* FIXME: we currently leak the string: mono_string_free (mstring); */
-    if (rc != DECIMAL_SUCCESS) return rc;
+    log10 = (log2 * 1000) / 3322;
+    /* we need an exact floor value of log10(a) */
+    if (dec128decadeFactors[log10].hi > ahi
+            || (dec128decadeFactors[log10].hi == ahi
+                    && dec128decadeFactors[log10].lo > alo)) {
+        --log10;
+    }
+    return log10+1;
+}
 
-    /* do we need to upround according to banker's rule ? */
-    if (*ps <= '4') {
-        roundFlag = 0;
-    } else if (*ps >= '6') {
-        roundFlag = 1;
-    } else { /* banker's rule for case '5' */
-        roundFlag = ((*(ps-1) - '0') % 2 == 1);
+gint32 mono_double2decimal(/*[Out]*/decimal_repr* pA, double val, gint32 digits)
+{
+    guint64 alo, ahi;
+    guint64* p = (guint64*)(&val);
+    int sigDigits, sign, exp, rc, scale;
+    guint16 k;
+
+    PRECONDITION(digits <= 15);
+
+    sign = ((*p & LIT_GUINT64_HIGHBIT) != 0) ? 1 : 0;
+    k = ((guint16)((*p) >> 52)) & 0x7FF;
+    alo = (*p & LIT_GUINT64(0xFFFFFFFFFFFFF)) | LIT_GUINT64(0x10000000000000);
+    ahi = 0;
+
+    exp = (k & 0x7FF) - 0x3FF;
+    if (k == 0x7FF || exp >= 96) return DECIMAL_OVERFLOW; /* NaNs, SNaNs, Infinities or >= 2^96 */
+    if (k == 0 || exp <= -94) { /* Subnormals, Zeros or < 2^-94 */
+        DECINIT(pA); /* return zero */
+        return DECIMAL_SUCCESS;
     }
-    if (roundFlag) {
-        /*test printf("round!!! dec=%d  decrDecimal=%d  roundPos=%d  scale=%d\n", dec, decrDecimal, roundPos, pA->signscale.scale); printdec(pA); printdec(&roundAdd);*/
-        DECCOPY(&roundAdd, constantsFactors + dec + pA->signscale.scale - roundPos);
-        roundAdd.ss32 = pA->ss32;
-        /* perform rounding */
-        mono_decimalIncr(pA, &roundAdd);
+
+    exp -= 52;
+    if (exp > 0) {
+        for (; exp > 0; exp--) {
+            lshift128(&alo, &ahi);
+        }
     }
 
-    return DECIMAL_SUCCESS;
+    scale = 0;
+    rc = rescale128(&alo, &ahi, &scale, -exp, 0, DECIMAL_MAX_SCALE, 0);
+    if (rc != DECIMAL_SUCCESS) return rc;
+
+    sigDigits = calcDigits(alo, ahi);
+    /* too much digits, then round */
+    if (sigDigits > digits) {
+        div128DecadeFactor(&alo, &ahi, sigDigits - digits);
+        scale -= sigDigits - digits;
+        /* check value, may be 10^(digits+1) caused by rounding */
+        if (ahi == dec128decadeFactors[digits].hi
+            && alo == dec128decadeFactors[digits].lo) {
+            div128by32(&alo, &ahi, 10, 0);
+            scale--;
+        }
+        if (scale < 0) {
+            rc = mult128DecadeFactor(&alo, &ahi, -scale);
+            if (rc != DECIMAL_SUCCESS) return rc;
+            scale = 0;
+        }
+    }
+
+    return pack128toDecimal(pA, alo, ahi, scale, sign);
 }
 
-/* converts string to decimal */
+/** 
+ * converts a digit string to decimal
+ * The significant digits must be passed as an integer in buf !
+ *
+ * 1. Example:
+ *   if you want to convert the number 123.456789012345678901234 to decimal
+ *     buf := "123456789012345678901234"
+ *     decrDecimal := 3
+ *     sign := 0
+ *
+ * 2. Example:
+ *   you want to convert -79228162514264337593543950335 to decimal
+ *     buf := "79228162514264337593543950335"
+ *     decrDecimal := 29
+ *     sign := 1
+ *
+ * 3. Example:
+ *   you want to convert -7922816251426433759354395033.250000000000001 to decimal
+ *     buf := "7922816251426433759354395033250000000000001"
+ *     decrDecimal := 29
+ *     sign := 1
+ *     returns (decimal)-7922816251426433759354395033.3
+ *
+ * 4. Example:
+ *   you want to convert -7922816251426433759354395033.250000000000000 to decimal
+ *     buf := "7922816251426433759354395033250000000000000"
+ *     decrDecimal := 29
+ *     sign := 1
+ *     returns (decimal)-7922816251426433759354395033.2
+ *
+ * 5. Example:
+ *   you want to convert -7922816251426433759354395033.150000000000000 to decimal
+ *     buf := "7922816251426433759354395033150000000000000"
+ *     decrDecimal := 29
+ *     sign := 1
+ *     returns (decimal)-7922816251426433759354395033.2
+ *
+ * Uses banker's rule for rounding if there are more digits than can be
+ * represented by the significant
+ */
 gint32 mono_string2decimal(/*[Out]*/decimal_repr* pA, MonoString* str, gint32 decrDecimal, gint32 sign)
 {
-       guint64 alo, ahi;
-    int len, n, rc, i;
-    gushort *buf;
+    gushort *buf = mono_string_chars(str);
+    gushort *p;
+    guint64 alo, ahi;
+    int n, rc, i, len, sigLen = -1, firstNonZero;
+    int scale, roundBit = 0;
 
     alo = ahi = 0;
-       DECINIT(pA);
+    DECINIT(pA);
 
-       buf = mono_string_chars (str);
-    len = str->length;
-    if (len > DECIMAL_MAX_SCALE+1) {
-        return DECIMAL_OVERFLOW;
-    }
+    for (p = buf, len = 0; *p != 0; len++, p++) { }
 
-    for (i = 0; i < len; i++) {
-        n = buf[i] - '0';
+    for (p = buf, i = 0; *p != 0; i++, p++) {
+        n = *p - '0';
         if (n < 0 || n > 9) {
             return DECIMAL_INVALID_CHARACTER;
         }
         if (n) {
-            rc = incMultConstant128(&alo, &ahi, len - 1 - i, n);
+            if (sigLen < 0) {
+                firstNonZero = i;
+                sigLen = (len - firstNonZero > DECIMAL_MAX_SCALE+1)
+                    ? DECIMAL_MAX_SCALE+1+firstNonZero : len;
+                if (decrDecimal > sigLen+1) return DECIMAL_OVERFLOW;
+            }
+            if (i >= sigLen) break;
+            rc = incMultConstant128(&alo, &ahi, sigLen - 1 - i, n);
             if (rc != DECIMAL_SUCCESS) {
                 return rc;
             }
         }
     }
 
-       if (alo == 0 && ahi == 0) {
-               DECINIT(pA);
-               return DECIMAL_SUCCESS;
-       } else {
-               return pack128toDecimal(pA, alo, ahi, len - decrDecimal, sign);
-       }
-}
+    scale = sigLen - decrDecimal;
 
-/* calc significant digits of mantisse */
-static int DECINLINE calcDigits(/*[In]*/decimal_repr* pA)
-{
-       guint32 a;
-       int log2 = 0;
-       int log10;
-       decimal_repr* pConst;
-
-       a = pA->hi32;
-       if (a == 0) {
-               a = pA->mid32;
-               if (a == 0) {
-                       a = pA->lo32;
-                       if (a ==  0) return 0; /* zero has no signficant digits */
-               } else {
-                       log2 = 32;
-               }
-       } else {
-               log2 = 64;
-       }
-
-       log2 += log2_32(a); /* get floor value of log2(a) */
-
-       log10 = (log2 * 1000) / 3322;
-       /* we need an exact floor value of log10(a) */
-       pConst = constantsFactors + log10;
-       if (pConst->hi32 > pA->hi32 
-               || (pConst->hi32 == pA->hi32 && (pConst->mid32 > pA->mid32
-               || (pConst->mid32 == pA->mid32 && pConst->lo32 > pA->lo32)))) {
-               --log10;
-       }
-       return log10+1;
+    if (i < len) { /* too much digits, we must round */
+        n = buf[i] - '0';
+        if (n < 0 || n > 9) {
+            return DECIMAL_INVALID_CHARACTER;
+        }
+        if (n > 5) roundBit = 1;
+        else if (n == 5) { /* we must take a nearer look */
+            n = buf[i-1] - '0';
+            for (++i; i < len; ++i) {
+                if (buf[i] != '0') break; /* we are greater than .5 */
+            }
+            if (i < len /* greater than exactly .5 */
+                || n % 2 == 1) { /* exactly .5, use banker's rule for rounding */
+                roundBit = 1;
+            }
+        }
+    }
+
+    if (ahi != 0) {
+        rc = normalize128(&alo, &ahi, &scale, 1, roundBit);
+        if (rc != DECIMAL_SUCCESS) return rc;
+    }
+
+    if (alo == 0 && ahi == 0) {
+        DECINIT(pA);
+        return DECIMAL_SUCCESS;
+    } else {
+        return pack128toDecimal(pA, alo, ahi, sigLen - decrDecimal, sign);
+    }
 }
 
-/* params:
-         pA         decimal instance to convert     
-      digits     < 0: use decimals instead
-                    = 0: gets mantisse as integer
-                    > 0: gets at most <digits> digits, rounded according to banker's rule if necessary
-         decimals   only used if digits < 0
-                    >= 0: number
-      buf        pointer to result buffer
-         bufSize    size of buffer
-         pDecPos    receives insert position of decimal point relative to start of buffer
-         pSign      receives sign */
-void mono_decimal2string(/*[In]*/decimal_repr* pA, int digits, int decimals,
-                                                                MonoArray* buf, gint32 bufSize, gint32* pDecPos, gint32* pSign)
+/**
+ * returns minimal number of digit string to represent decimal
+ * No leading or trailing zeros !
+ * Examples:
+ * *pA == 0            =>   buf = "", *pDecPos = 0, *pSign = 0
+ * *pA == 12.34        =>   buf = "1234", *pDecPos = 2, *pSign = 0
+ * *pA == -1000.0000   =>   buf = "1", *pDecPos = 4, *pSign = 1
+ * *pA == -0.00000076  =>   buf = "76", *pDecPos = -6, *pSign = 0
+ * 
+ * Parameters:
+ *    pA         decimal instance to convert     
+ *    digits     < 0: use decimals instead
+ *               = 0: gets mantisse as integer
+ *               > 0: gets at most <digits> digits, rounded according to banker's rule if necessary
+ *    decimals   only used if digits < 0
+ *               >= 0: number of decimal places
+ *    buf        pointer to result buffer
+ *    bufSize    size of buffer
+ *    pDecPos    receives insert position of decimal point relative to start of buffer
+ *    pSign      receives sign
+ */
+
+gint32 mono_decimal2string(/*[In]*/decimal_repr* pA, gint32 digits, gint32 decimals,
+                                   MonoArray* pArray, gint32 bufSize, gint32* pDecPos, gint32* pSign)
 {
-       decimal_repr aa;
-       guint64 alo, ahi;
+    guint16 tmp[41];
+    guint16 *buf = (guint16*) mono_array_addr(pArray, guint16, 0);
+    guint16 *q, *p = tmp;
+    decimal_repr aa;
+    guint64 alo, ahi;
     guint32 rest;
-    int i, scale, sigDigits;
-    gushort* p = (gushort*) mono_array_addr (buf, gushort, 0);
-    gushort *tail;
-
-       scale = pA->signscale.scale;
-       sigDigits = calcDigits(pA);
-
-       if (digits < 0) { /* use decimals ? */
-               if (0 <= decimals && decimals < scale) {
-                       digits = sigDigits - scale + decimals;
-                       if (digits == 0) digits = -1; /* no digits */
-               } else {
-                       digits = 0; /* use all you can get */
-               }
-       } 
-
-       if (digits > 0 && digits <= DECIMAL_MAX_SCALE) { /* significant digits */
-               if (sigDigits > digits) { /* we need to round decimal number */
-                       DECCOPY(&aa, pA);
-                       aa.signscale.scale = DECIMAL_MAX_SCALE;
-                       mono_decimalRound(&aa, DECIMAL_MAX_SCALE - sigDigits + digits);
-                       sigDigits += calcDigits(&aa) - digits;
-                       DECTO128(&aa, alo, ahi);
-               } else {
-                       DECTO128(pA, alo, ahi);
-               }
-       } else {
-               DECTO128(pA, alo, ahi);
-       }
-
-       if (digits >= 0) {
-           /* get digits starting from the tail */
-               for (i = 0; (alo != 0 || ahi != 0) && i < bufSize-1; i++) {
-                       div128by32(&alo, &ahi, 10, &rest);
-                       *p++ = '0' + (char) rest;
-               }
-               tail = p - 1;
-               *p = 0;
-       }
-
-    /* reverse string */
-       p = (gushort*) mono_array_addr (buf, gushort, 0);
-       while (p < tail) {
-               gushort c = *p;
-               *p = *tail;
-               p++;
-               *tail = c;
-               --tail;
-       }
-       if (digits > 0 && digits < bufSize) 
-               mono_array_set (buf, gushort, digits, 0);
-
-    *pDecPos = sigDigits - scale;
-    *pSign = pA->signscale.sign;
-}
+    gint32 sigDigits, d;
+    int i, scale, len;
 
-static DECINLINE void div128DecimalFactor(guint64* palo, guint64* pahi, int powerOfTen)
-{
-    int index, roundBit = 0;
+    scale = pA->signscale.scale;
+    DECTO128(pA, alo, ahi);
+    sigDigits = calcDigits(alo, ahi); /* significant digits */
+
+    /* calc needed digits (without leading or trailing zeros) */
+    d = (digits == 0) ? sigDigits : digits;
+    if (d < 0) { /* use decimals ? */
+        if (0 <= decimals && decimals < scale) {
+            d = sigDigits - scale + decimals;
+        } else {
+            d = sigDigits; /* use all you can get */
+        }
+    } 
+
+    if (sigDigits > d) { /* we need to round decimal number */
+        DECCOPY(&aa, pA);
+        aa.signscale.scale = DECIMAL_MAX_SCALE;
+        mono_decimalRound(&aa, DECIMAL_MAX_SCALE - sigDigits + d);
+        DECTO128(&aa, alo, ahi);
+        sigDigits += calcDigits(alo, ahi) - d;
+    }
 
-    while (powerOfTen > 0) {
-               index = (powerOfTen > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : powerOfTen;
-               powerOfTen -= index;
-               roundBit = div128by32(palo, pahi, constantsIntFactors[index], 0);
+    len = 0;
+    if (d > 0) {
+        /* get digits starting from the tail */
+        for (; (alo != 0 || ahi != 0) && len < 40; len++) {
+            div128by32(&alo, &ahi, 10, &rest);
+            *p++ = '0' + (char) rest;
+        }
     }
+    *p = 0;
+
+    if (len >= bufSize) return DECIMAL_BUFFER_OVERFLOW;
+
+    /* now we have the minimal count of digits, 
+       extend to wished count of digits or decimals */
+    q = buf;
+    if (digits >= 0) { /* count digits */
+        if (digits >= bufSize) return DECIMAL_BUFFER_OVERFLOW;
+        if (len == 0) {
+            /* zero or rounded to zero */
+            *pDecPos = 1;
+        } else {
+            /* copy significant digits */
+            for (i = 0; i < len; i++) {
+                *q++ = *(--p);
+            }
+            *pDecPos = sigDigits - scale;
+        }
+        /* add trailing zeros */
+        for (i = len; i < digits; i++) {
+            *q++ = '0';
+        }
+    } else { /* count decimals */
+        if (scale >= sigDigits) { /* add leading zeros */
+            if (decimals+2 >= bufSize) return DECIMAL_BUFFER_OVERFLOW;
+            *pDecPos = 1;
+            for (i = 0; i <= scale - sigDigits; i++) {
+                *q++ = '0';
+            }
+        } else {
+            if (sigDigits - scale + decimals+1 >= bufSize) return DECIMAL_BUFFER_OVERFLOW;
+            *pDecPos = sigDigits - scale;
+        }
+        /* copy significant digits */
+        for (i = 0; i < len; i++) {
+            *q++ = *(--p);
+        }
+        /* add trailing zeros */
+        for (i = scale; i < decimals; i++) {
+            *q++ = '0';
+        }
+    }
+    *q = 0;
 
-       if (roundBit) roundUp128(palo, pahi);
+    *pSign = (sigDigits > 0) ? pA->signscale.sign : 0; /* zero has positive sign */
+
+    return DECIMAL_SUCCESS;
 }
 
+/**
+ * converts a decimal to an UInt64 without rounding
+ */
 gint32 mono_decimal2UInt64(/*[In]*/decimal_repr* pA, guint64* pResult)
 {
-       guint64 alo, ahi;
+    guint64 alo, ahi;
     int scale;
 
-       DECTO128(pA, alo, ahi);
+    DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
-       if (scale > 0) {
-               div128DecimalFactor(&alo, &ahi, scale);
-       }
+    if (scale > 0) {
+        div128DecadeFactor(&alo, &ahi, scale);
+    }
 
-       /* overflow if integer too large or < 0 */
+    /* overflow if integer too large or < 0 */
     if (ahi != 0 || (alo != 0 && pA->signscale.sign)) return DECIMAL_OVERFLOW;
 
-       *pResult = alo;
+    *pResult = alo;
     return DECIMAL_SUCCESS;
 }
 
+/**
+ * converts a decimal to an Int64 without rounding
+ */
 gint32 mono_decimal2Int64(/*[In]*/decimal_repr* pA, gint64* pResult)
 {
-       guint64 alo, ahi;
+    guint64 alo, ahi;
     int sign, scale;
 
-       DECTO128(pA, alo, ahi);
+    DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
-       if (scale > 0) {
-               div128DecimalFactor(&alo, &ahi, scale);
-       }
+    if (scale > 0) {
+        div128DecadeFactor(&alo, &ahi, scale);
+    }
 
     if (ahi != 0) return DECIMAL_OVERFLOW;
 
-       sign = pA->signscale.sign;
-       if (sign && alo != 0) {
-               if (alo > LIT_GUINT64_HIGHBIT) return DECIMAL_OVERFLOW;
-               *pResult = (gint64) ~(alo-1);
-       } else {
-               if (alo & LIT_GUINT64_HIGHBIT) return DECIMAL_OVERFLOW;
-               *pResult = (gint64) alo;
-       }
+    sign = pA->signscale.sign;
+    if (sign && alo != 0) {
+        if (alo > LIT_GUINT64_HIGHBIT) return DECIMAL_OVERFLOW;
+        *pResult = (gint64) ~(alo-1);
+    } else {
+        if (alo & LIT_GUINT64_HIGHBIT) return DECIMAL_OVERFLOW;
+        *pResult = (gint64) alo;
+    }
 
     return DECIMAL_SUCCESS;
 }
 
 void mono_decimalFloorAndTrunc(/*[In, Out]*/decimal_repr* pA, gint32 floorFlag)
 {
-       guint64 alo, ahi;
+    guint64 alo, ahi;
     guint32 factor, rest;
     int scale, sign, index;
     int hasRest = 0;
@@ -1120,38 +1216,38 @@ void mono_decimalFloorAndTrunc(/*[In, Out]*/decimal_repr* pA, gint32 floorFlag)
     scale = pA->signscale.scale;
     if (scale == 0) return; /* nothing to do */
 
-       DECTO128(pA, alo, ahi);
-       sign = pA->signscale.sign;
+    DECTO128(pA, alo, ahi);
+    sign = pA->signscale.sign;
 
     while (scale > 0) {
-               index = (scale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : scale;
-               factor = constantsIntFactors[index];
-               scale -= index;
-               div128by32(&alo, &ahi, factor, &rest);
-               hasRest = hasRest || (rest != 0);
-       }
+        index = (scale > DECIMAL_MAX_INTFACTORS) ? DECIMAL_MAX_INTFACTORS : scale;
+        factor = constantsDecadeInt32Factors[index];
+        scale -= index;
+        div128by32(&alo, &ahi, factor, &rest);
+        hasRest = hasRest || (rest != 0);
+    }
 
     if (floorFlag && hasRest && sign) { /* floor: if negative, we must round up */
-               roundUp128(&alo, &ahi);
+        roundUp128(&alo, &ahi);
     }
 
-       pack128toDecimal(pA, alo, ahi, 0, sign);
+    pack128toDecimal(pA, alo, ahi, 0, sign);
 }
 
 void mono_decimalRound(/*[In, Out]*/decimal_repr* pA, gint32 decimals)
 {
-       guint64 alo, ahi;
+    guint64 alo, ahi;
     int scale, sign;
 
-       DECTO128(pA, alo, ahi);
+    DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
-       sign = pA->signscale.sign;
+    sign = pA->signscale.sign;
     if (scale > decimals) {
-               div128DecimalFactor(&alo, &ahi, scale - decimals);
-               scale = decimals;
-       }
-       
-       pack128toDecimal(pA, alo, ahi, scale, sign);
+        div128DecadeFactor(&alo, &ahi, scale - decimals);
+        scale = decimals;
+    }
+    
+    pack128toDecimal(pA, alo, ahi, scale, sign);
 }
 
 gint32 mono_decimalMult(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
@@ -1163,12 +1259,12 @@ gint32 mono_decimalMult(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
     mult96by96to192(pA->lo32, pA->mid32, pA->hi32, pB->lo32, pB->mid32, pB->hi32,
         &low, &mid, &high);
 
-       /* adjust scale and sign */
-       scale = (int)pA->signscale.scale + (int)pB->signscale.scale;
-       sign = pA->signscale.sign ^ pB->signscale.sign;
+    /* adjust scale and sign */
+    scale = (int)pA->signscale.scale + (int)pB->signscale.scale;
+    sign = pA->signscale.sign ^ pB->signscale.sign;
 
     /* first scaling step */
-    factor = constantsIntFactors[DECIMAL_MAX_INTFACTORS];
+    factor = constantsDecadeInt32Factors[DECIMAL_MAX_INTFACTORS];
     while (high != 0 || (mid>>32) >= factor) {
         if (high < 100) {
             factor /= 1000; /* we need some digits for final rounding */
@@ -1180,262 +1276,262 @@ gint32 mono_decimalMult(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
         div192by32(&low, &mid, &high, factor);
     }
 
-       /* second and final scaling */
-       rc = rescale128(&low, &mid, &scale, 0, 0, DECIMAL_MAX_SCALE, 1);
-       if (rc != DECIMAL_SUCCESS) return rc;
+    /* second and final scaling */
+    rc = rescale128(&low, &mid, &scale, 0, 0, DECIMAL_MAX_SCALE, 1);
+    if (rc != DECIMAL_SUCCESS) return rc;
 
-       return pack128toDecimal(pA, low, mid, scale, sign);
+    return pack128toDecimal(pA, low, mid, scale, sign);
 }
 
-static int DECINLINE decimalDivSub(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB,
-                                                                        guint64* pclo, guint64* pchi, int* pExp)
+static int decimalDivSub(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB,
+                         guint64* pclo, guint64* pchi, int* pExp)
 {
-       guint64 alo, ami, ahi;
-       guint64 tlo, tmi, thi;
-       guint32 blo, bmi, bhi;
-       int ashift, bshift, extraBit, exp;
-
-       ahi = (((guint64)(pA->hi32)) << 32) | pA->mid32;
-       ami = ((guint64)(pA->lo32)) << 32;
-       alo = 0;
-       blo = pB->lo32;
-       bmi = pB->mid32;
-       bhi = pB->hi32;
-
-       if (blo == 0 && bmi == 0 && bhi == 0) {
-               return DECIMAL_DIVIDE_BY_ZERO;
-       }
-
-       if (ami == 0 && ahi == 0) {
-               *pclo = *pchi = 0;
-               return DECIMAL_FINISHED;
-       }
-
-       /* enlarge dividend to get maximal precision */
-       for (ashift = 0; (ahi & LIT_GUINT64_HIGHBIT) == 0; ++ashift) {
-               lshift128(&ami, &ahi);
-       }
-
-       /* ensure that divisor is at least 2^95 */
-       for (bshift = 0; (bhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift) {
-               lshift96(&blo, &bmi, &bhi);
-       }
-
-       thi = ((guint64)bhi)<<32 | bmi;
-       tmi = ((guint64)blo)<<32;
-       tlo = 0;
-       if (ahi > thi || (ahi == thi && ami >= tmi)) {
-               sub192(alo, ami, ahi, tlo, tmi, thi, &alo, &ami, &ahi);
-               extraBit = 1;
-       } else {
-               extraBit = 0;
-       }
-
-       div192by96to128(alo, ami, ahi, blo, bmi, bhi, pclo, pchi);
-       exp = 128 + ashift - bshift;
-
-       if (extraBit) {
-               rshift128(pclo, pchi);
-               *pchi += LIT_GUINT64_HIGHBIT;
-               exp--;
-       }
-
-       /* try loss free right shift */
-       while (exp > 0 && (*pclo & 1) == 0) {
-               /* right shift */
-               rshift128(pclo, pchi);
-               exp--;
-       }
-
-       *pExp = exp;
-
-       return DECIMAL_SUCCESS;
+    guint64 alo, ami, ahi;
+    guint64 tlo, tmi, thi;
+    guint32 blo, bmi, bhi;
+    int ashift, bshift, extraBit, exp;
+
+    ahi = (((guint64)(pA->hi32)) << 32) | pA->mid32;
+    ami = ((guint64)(pA->lo32)) << 32;
+    alo = 0;
+    blo = pB->lo32;
+    bmi = pB->mid32;
+    bhi = pB->hi32;
+
+    if (blo == 0 && bmi == 0 && bhi == 0) {
+        return DECIMAL_DIVIDE_BY_ZERO;
+    }
+
+    if (ami == 0 && ahi == 0) {
+        *pclo = *pchi = 0;
+        return DECIMAL_FINISHED;
+    }
+
+    /* enlarge dividend to get maximal precision */
+    for (ashift = 0; (ahi & LIT_GUINT64_HIGHBIT) == 0; ++ashift) {
+        lshift128(&ami, &ahi);
+    }
+
+    /* ensure that divisor is at least 2^95 */
+    for (bshift = 0; (bhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift) {
+        lshift96(&blo, &bmi, &bhi);
+    }
+
+    thi = ((guint64)bhi)<<32 | bmi;
+    tmi = ((guint64)blo)<<32;
+    tlo = 0;
+    if (ahi > thi || (ahi == thi && ami >= tmi)) {
+        sub192(alo, ami, ahi, tlo, tmi, thi, &alo, &ami, &ahi);
+        extraBit = 1;
+    } else {
+        extraBit = 0;
+    }
+
+    div192by96to128(alo, ami, ahi, blo, bmi, bhi, pclo, pchi);
+    exp = 128 + ashift - bshift;
+
+    if (extraBit) {
+        rshift128(pclo, pchi);
+        *pchi += LIT_GUINT64_HIGHBIT;
+        exp--;
+    }
+
+    /* try loss free right shift */
+    while (exp > 0 && (*pclo & 1) == 0) {
+        /* right shift */
+        rshift128(pclo, pchi);
+        exp--;
+    }
+
+    *pExp = exp;
+
+    return DECIMAL_SUCCESS;
 }
 
 gint32 mono_decimalDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
 {
-       guint64 clo, chi; /* result */
-       int scale, exp, rc;
+    guint64 clo, chi; /* result */
+    int scale, exp, rc;
 
-       rc = decimalDivSub(pA, pB, &clo, &chi, &exp);
-       if (rc != DECIMAL_SUCCESS) {
-               if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
-               return rc;
-       }
+    rc = decimalDivSub(pA, pB, &clo, &chi, &exp);
+    if (rc != DECIMAL_SUCCESS) {
+        if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
+        return rc;
+    }
 
-       /* adjust scale and sign */
-       scale = (int)pA->signscale.scale - (int)pB->signscale.scale;
+    /* adjust scale and sign */
+    scale = (int)pA->signscale.scale - (int)pB->signscale.scale;
 
-       //test: printf("0: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -exp));
-       rc = rescale128(&clo, &chi, &scale, exp, 0, DECIMAL_MAX_SCALE, 1);
-       if (rc != DECIMAL_SUCCESS) return rc;
+    //test: printf("0: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -exp));
+    rc = rescale128(&clo, &chi, &scale, exp, 0, DECIMAL_MAX_SCALE, 1);
+    if (rc != DECIMAL_SUCCESS) return rc;
 
-       return pack128toDecimal(pC, clo, chi, scale, pA->signscale.sign ^ pB->signscale.sign);
+    return pack128toDecimal(pC, clo, chi, scale, pA->signscale.sign ^ pB->signscale.sign);
 }
 
 gint32 mono_decimalIntDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
 {
-       guint64 clo, chi; /* result */
-       int scale, exp, rc;
+    guint64 clo, chi; /* result */
+    int scale, exp, rc;
 
-       rc = decimalDivSub(pA, pB, &clo, &chi, &exp);
-       if (rc != DECIMAL_SUCCESS) {
-               if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
-               return rc;
-       }
+    rc = decimalDivSub(pA, pB, &clo, &chi, &exp);
+    if (rc != DECIMAL_SUCCESS) {
+        if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
+        return rc;
+    }
 
-       /* calc scale  */
-       scale = (int)pA->signscale.scale - (int)pB->signscale.scale;
+    /* calc scale  */
+    scale = (int)pA->signscale.scale - (int)pB->signscale.scale;
 
-       /* truncate result to integer */
-       rc = rescale128(&clo, &chi, &scale, exp, 0, 0, 0);
-       if (rc != DECIMAL_SUCCESS) return rc;
+    /* truncate result to integer */
+    rc = rescale128(&clo, &chi, &scale, exp, 0, 0, 0);
+    if (rc != DECIMAL_SUCCESS) return rc;
 
-       return pack128toDecimal(pC, clo, chi, scale, pA->signscale.sign);
+    return pack128toDecimal(pC, clo, chi, scale, pA->signscale.sign);
 }
 
 /* approximation for log2 of a 
    If q is the exact value for log2(a), then q <= decimalLog2(a) <= q+1 */
-static int DECINLINE decimalLog2(/*[In]*/decimal_repr* pA)
+DECINLINE static int decimalLog2(/*[In]*/decimal_repr* pA)
 {
-       int log2;
-       int scale = pA->signscale.scale;
+    int log2;
+    int scale = pA->signscale.scale;
 
-       if (pA->hi32 != 0) log2 = 64 + log2_32(pA->hi32);
-       else if (pA->mid32 != 0) log2 = 32 + log2_32(pA->mid32);
-       else log2 = log2_32(pA->lo32);
+    if (pA->hi32 != 0) log2 = 64 + log2_32(pA->hi32);
+    else if (pA->mid32 != 0) log2 = 32 + log2_32(pA->mid32);
+    else log2 = log2_32(pA->lo32);
 
-       if (log2 != DECIMAL_LOG_NEGINF) {
-               log2 -= (scale * 33219) / 10000;
-       }
+    if (log2 != DECIMAL_LOG_NEGINF) {
+        log2 -= (scale * 33219) / 10000;
+    }
 
-       return log2;
+    return log2;
 }
 
-static DECINLINE int decimalIsZero(/*[In]*/decimal_repr* pA)
+DECINLINE static int decimalIsZero(/*[In]*/decimal_repr* pA)
 {
-       return (pA->lo32 == 0 && pA->mid32 == 0 && pA->hi32 == 0);
+    return (pA->lo32 == 0 && pA->mid32 == 0 && pA->hi32 == 0);
 }
 
 gint32 mono_decimalCompare(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
 {
-       int log2a, log2b, delta, sign;
-       decimal_repr aa;
+    int log2a, log2b, delta, sign;
+    decimal_repr aa;
 
-       sign = (pA->signscale.sign) ? -1 : 1;
+    sign = (pA->signscale.sign) ? -1 : 1;
 
-       if (pA->signscale.sign ^ pB->signscale.sign) {
-               return (decimalIsZero(pA) && decimalIsZero(pB)) ? 0 : sign;
-       }
+    if (pA->signscale.sign ^ pB->signscale.sign) {
+        return (decimalIsZero(pA) && decimalIsZero(pB)) ? 0 : sign;
+    }
 
-       /* try fast comparison via log2 */
-       log2a = decimalLog2(pA);
-       log2b = decimalLog2(pB);
-       delta = log2a - log2b;
-        /* decimalLog2 is not exact, so we can say nothing 
-           if abs(delta) <= 1 */
-       if (delta < -1) return -sign;
-       if (delta > 1) return sign;
+    /* try fast comparison via log2 */
+    log2a = decimalLog2(pA);
+    log2b = decimalLog2(pB);
+    delta = log2a - log2b;
+     /* decimalLog2 is not exact, so we can say nothing 
+        if abs(delta) <= 1 */
+    if (delta < -1) return -sign;
+    if (delta > 1) return sign;
 
-       DECCOPY(&aa, pA);
-       DECNEGATE(&aa);
-       mono_decimalIncr(&aa, pB);
+    DECCOPY(&aa, pA);
+    DECNEGATE(&aa);
+    mono_decimalIncr(&aa, pB);
 
-       if (decimalIsZero(&aa)) return 0;
+    if (decimalIsZero(&aa)) return 0;
 
-       return (aa.signscale.sign) ? 1 : -1;
+    return (aa.signscale.sign) ? 1 : -1;
 }
 
 /* d=(-1)^sign * n * 2^(k-52) with sign (1bit), k(11bit), n-2^52(52bit) */  
-static DECINLINE void buildIEEE754Double(double* pd, int sign, int exp, guint64 mantisse)
+DECINLINE static void buildIEEE754Double(double* pd, int sign, int exp, guint64 mantisse)
 {
-       guint64* p = (guint64*) pd;
+    guint64* p = (guint64*) pd;
 
-       PRECONDITION(sign == 0 || sign == 1);
-       *p = (((guint64)sign) << 63) | (((guint64)((1023+exp)&0x7ff)) << 52) | mantisse;
+    PRECONDITION(sign == 0 || sign == 1);
+    *p = (((guint64)sign) << 63) | (((guint64)((1023+exp)&0x7ff)) << 52) | mantisse;
 }
 
 double mono_decimal2double(/*[In]*/decimal_repr* pA)
 {
-       double d;
-       guint64 alo, ahi, mantisse;
-       guint32 overhang, factor, roundBits;
-       int scale, exp, log5, i;
-
-       ahi = (((guint64)(pA->hi32)) << 32) | pA->mid32;
-       alo = ((guint64)(pA->lo32)) << 32;
-
-       /* special case zero */
-       if (ahi == 0 && alo == 0) return 0.0;
-
-       exp = 0;
-       scale = pA->signscale.scale;
-
-       /* transform n * 10^-scale and exp = 0 => m * 2^-exp and scale = 0 */
-       while (scale > 0) {
-               while ((ahi & LIT_GUINT64_HIGHBIT) == 0) {
-                       lshift128(&alo, &ahi);
-                       exp++;
-               }
-
-               overhang = (guint32) (ahi >> 32);
-               if (overhang >= 5) {
-                       /* estimate log5 */
-                       log5 = (log2_32(overhang) * 1000) / 2322; /* ln(5)/ln(2) = 2.3219... */
-                       if (log5 < DECIMAL_MAX_INTFACTORS) {
-                               /* get maximal factor=5^i, so that overhang / factor >= 1 */
-                               factor = constantsIntFactors[log5] >> log5; /* 5^n = 10^n/2^n */
-                               i = log5 + overhang / factor;
-                       } else {
-                               i = DECIMAL_MAX_INTFACTORS; /* we have only constants up to 10^DECIMAL_MAX_INTFACTORS */
-                       }
-                       if (i > scale) i = scale;
-                       factor = constantsIntFactors[i] >> i; /* 5^n = 10^n/2^n */
-                       /* n * 10^-scale * 2^-exp => m * 10^-(scale-i) * 2^-(exp+i) with m = n * 5^-i */
-                       div128by32(&alo, &ahi, factor, 0);
-                       scale -= i;
-                       exp += i;
-               }
-       }
-
-       /* normalize significand (highest bit should be 1) */
-       while ((ahi & LIT_GUINT64_HIGHBIT) == 0) {
-               lshift128(&alo, &ahi);
-               exp++;
-       }
-
-       /* round to nearest even */
-       roundBits = (guint32)ahi & 0x7ff;
-       ahi += 0x400;
-       if ((ahi & LIT_GUINT64_HIGHBIT) == 0) { /* overflow ? */
-               ahi >>= 1;
-               exp++;
-       } else if ((roundBits & 0x400) == 0) ahi &= ~1;
-
-       /* 96 bit => 1 implizit bit and 52 explicit bits */
+    double d;
+    guint64 alo, ahi, mantisse;
+    guint32 overhang, factor, roundBits;
+    int scale, exp, log5, i;
+
+    ahi = (((guint64)(pA->hi32)) << 32) | pA->mid32;
+    alo = ((guint64)(pA->lo32)) << 32;
+
+    /* special case zero */
+    if (ahi == 0 && alo == 0) return 0.0;
+
+    exp = 0;
+    scale = pA->signscale.scale;
+
+    /* transform n * 10^-scale and exp = 0 => m * 2^-exp and scale = 0 */
+    while (scale > 0) {
+        while ((ahi & LIT_GUINT64_HIGHBIT) == 0) {
+            lshift128(&alo, &ahi);
+            exp++;
+        }
+
+        overhang = (guint32) (ahi >> 32);
+        if (overhang >= 5) {
+            /* estimate log5 */
+            log5 = (log2_32(overhang) * 1000) / 2322; /* ln(5)/ln(2) = 2.3219... */
+            if (log5 < DECIMAL_MAX_INTFACTORS) {
+                /* get maximal factor=5^i, so that overhang / factor >= 1 */
+                factor = constantsDecadeInt32Factors[log5] >> log5; /* 5^n = 10^n/2^n */
+                i = log5 + overhang / factor;
+            } else {
+                i = DECIMAL_MAX_INTFACTORS; /* we have only constants up to 10^DECIMAL_MAX_INTFACTORS */
+            }
+            if (i > scale) i = scale;
+            factor = constantsDecadeInt32Factors[i] >> i; /* 5^n = 10^n/2^n */
+            /* n * 10^-scale * 2^-exp => m * 10^-(scale-i) * 2^-(exp+i) with m = n * 5^-i */
+            div128by32(&alo, &ahi, factor, 0);
+            scale -= i;
+            exp += i;
+        }
+    }
+
+    /* normalize significand (highest bit should be 1) */
+    while ((ahi & LIT_GUINT64_HIGHBIT) == 0) {
+        lshift128(&alo, &ahi);
+        exp++;
+    }
+
+    /* round to nearest even */
+    roundBits = (guint32)ahi & 0x7ff;
+    ahi += 0x400;
+    if ((ahi & LIT_GUINT64_HIGHBIT) == 0) { /* overflow ? */
+        ahi >>= 1;
+        exp++;
+    } else if ((roundBits & 0x400) == 0) ahi &= ~1;
+
+    /* 96 bit => 1 implizit bit and 52 explicit bits */
     mantisse = (ahi & ~LIT_GUINT64_HIGHBIT) >> 11;
 
-       buildIEEE754Double(&d, pA->signscale.sign, -exp+95, mantisse);
+    buildIEEE754Double(&d, pA->signscale.sign, -exp+95, mantisse);
 
-       return d;
+    return d;
 }
 
 /* a *= 10^exp */
 gint32 mono_decimalSetExponent(/*[In, Out]*/decimal_repr* pA, gint32 exp)
 {
-       guint64 alo, ahi;
-       int rc;
-       int scale = pA->signscale.scale;
-
-       scale -= exp;
-
-       if (scale < 0 || scale > DECIMAL_MAX_SCALE)     {
-               DECTO128(pA, alo, ahi);
-               rc = rescale128(&alo, &ahi, &scale, 0, 0, DECIMAL_MAX_SCALE, 1);
-               if (rc != DECIMAL_SUCCESS) return rc;
-               return pack128toDecimal(pA, alo, ahi, scale, pA->signscale.sign);
-       } else {
-               pA->signscale.scale = scale;
-               return DECIMAL_SUCCESS;
-       }
+    guint64 alo, ahi;
+    int rc;
+    int scale = pA->signscale.scale;
+
+    scale -= exp;
+
+    if (scale < 0 || scale > DECIMAL_MAX_SCALE) {
+        DECTO128(pA, alo, ahi);
+        rc = rescale128(&alo, &ahi, &scale, 0, 0, DECIMAL_MAX_SCALE, 1);
+        if (rc != DECIMAL_SUCCESS) return rc;
+        return pack128toDecimal(pA, alo, ahi, scale, pA->signscale.sign);
+    } else {
+        pA->signscale.scale = scale;
+        return DECIMAL_SUCCESS;
+    }
 }
index e3bda72d81265d4a723cca8145b2960f5f8fb979..383449fdc7e1d9f665c53218cc466520b98d34e9 100644 (file)
@@ -1,30 +1,27 @@
 #include "mono/metadata/object.h"
 
 /* representation for C# type decimal */
-/* FIXME: handling of little/big endian. This is the layout of MSC */
+/* This is the layout of MSC */
 typedef struct
 {
        union {
                guint32 ss32;
-               struct {
-                       unsigned int reserved1 : 16;
-                       unsigned int scale : 8; 
-                       unsigned int reserved2 : 7;
-                       unsigned int sign : 1; 
+           struct {
+                   unsigned int reserved1 : 16;
+               unsigned int scale : 8; 
+                   unsigned int reserved2 : 7;
+               unsigned int sign : 1; 
                } signscale;
        } u;
-       guint32 hi32;
-       guint32 lo32;
-       guint32 mid32;
+    guint32 hi32;
+    guint32 lo32;
+    guint32 mid32;
 } decimal_repr;
 
 
 /* function prototypes */
 gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB);
 gint32 mono_double2decimal(/*[Out]*/decimal_repr* pA, double val, gint32 digits);
-gint32 mono_string2decimal(/*[Out]*/decimal_repr* pA, MonoString* str, gint32 decrDecimal, gint32 sign);
-void mono_decimal2string(/*[In]*/decimal_repr* pA, int digits, int decimals,
-                                                                MonoArray* buf, gint32 bufSize, gint32* pDecPos, gint32* pSign);
 gint32 mono_decimal2UInt64(/*[In]*/decimal_repr* pD, guint64* pResult);
 gint32 mono_decimal2Int64(/*[In]*/decimal_repr* pD, gint64* pResult);
 void mono_decimalFloorAndTrunc(/*[In, Out]*/decimal_repr* pD, gint32 floorFlag);
@@ -35,3 +32,8 @@ gint32 mono_decimalIntDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /
 gint32 mono_decimalCompare(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB);
 double mono_decimal2double(/*[In]*/decimal_repr* pA);
 gint32 mono_decimalSetExponent(/*[In, Out]*/decimal_repr* pA, gint32 exp);
+
+gint32 mono_string2decimal(/*[Out]*/decimal_repr* pA, /*[In]*/MonoString* s, gint32 decrDecimal, gint32 sign);
+gint32 mono_decimal2string(/*[In]*/decimal_repr* pA, int digits, int decimals,
+                        /*[Out]*/MonoArray* pArray, gint32 bufSize, gint32* pDecPos, gint32* pSign);
+