* roottypes.cs: Rename from tree.cs.
[mono.git] / mono / metadata / decimal.c
index f9ba3ed75948ebac38cc5649e4a0e2a1848e5c2d..704c5dd5afd16ad478ef1f19fffbfc9b2eb8e7c7 100644 (file)
  * CSharp value type System.Decimal
  */
 
+#include "config.h"
+#include <mono/metadata/exception.h>
 #include <stdio.h>
 #include <memory.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
 
+#ifndef DISABLE_DECIMAL
+
 /* needed for building microsoft dll */
+#ifdef __GNUC__
 #define DECINLINE __inline
+#else
+#define DECINLINE
+#endif
 
 #define LIT_GUINT32(x) x
-#define LIT_GUINT64(x) x##L
+#define LIT_GUINT64(x) x##LL
 
 
 /* we need a UInt64 type => guint64 */
@@ -50,7 +58,7 @@
 #define POSTCONDITION(flag)  
 #define TEST(flag)
 #define INVARIANT_TEST(p)
-#endif //#ifdef _DEBUG
+#endif /*#ifdef _DEBUG*/
 
 #define DECIMAL_MAX_SCALE 28
 #define DECIMAL_MAX_INTFACTORS 9
@@ -89,7 +97,7 @@
 
 #define DECIMAL_LOG_NEGINF -1000
 
-static guint32 constantsDecadeInt32Factors[DECIMAL_MAX_INTFACTORS+1] = {
+static const 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)
@@ -100,7 +108,7 @@ typedef struct {
     guint64 hi;
 } dec128_repr;
 
-static dec128_repr dec128decadeFactors[DECIMAL_MAX_SCALE+1] = {
+static const 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 */
@@ -344,7 +352,7 @@ DECINLINE static int div128by32(guint64* plo, guint64* phi, guint32 factor, guin
     if (pRest) *pRest = (guint32) a;
 
     a <<= 1;
-    return (a > factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
+    return (a >= factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
 }
 
 /* division: x(192bit) /= factor(32bit) 
@@ -698,7 +706,7 @@ DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int t
             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, -texp));
+    /*printf("3: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -texp));*/
         }
 
         while (texp > 0) {
@@ -740,6 +748,8 @@ gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
     int log2A, log2B, log2Result, log10Result, rc;
     int subFlag, sign, scaleA, scaleB;
 
+    MONO_ARCH_SAVE_REGS;
+
     DECTO128(pA, alo, ahi);
     DECTO128(pB, blo, bhi);
 
@@ -917,7 +927,13 @@ gint32 mono_double2decimal(/*[Out]*/decimal_repr* pA, double val, gint32 digits)
     return pack128toDecimal(pA, alo, ahi, scale, sign);
 }
 
-/** 
+/**
+ * mono_string2decimal:
+ * @decimal_repr:
+ * @str:
+ * @decrDecimal:
+ * @sign:
+ *
  * converts a digit string to decimal
  * The significant digits must be passed as an integer in buf !
  *
@@ -1024,10 +1040,12 @@ gint32 mono_string2decimal(/*[Out]*/decimal_repr* pA, MonoString* str, gint32 de
 }
 
 /**
+ * mono_decimal2string:
+ * @
  * returns minimal number of digit string to represent decimal
  * No leading or trailing zeros !
  * Examples:
- * *pA == 0            =>   buf = "", *pDecPos = 0, *pSign = 0
+ * *pA == 0            =>   buf = "", *pDecPos = 1, *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
@@ -1044,7 +1062,6 @@ gint32 mono_string2decimal(/*[Out]*/decimal_repr* pA, MonoString* str, gint32 de
  *    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)
 {
@@ -1057,6 +1074,8 @@ gint32 mono_decimal2string(/*[In]*/decimal_repr* pA, gint32 digits, gint32 decim
     gint32 sigDigits, d;
     int i, scale, len;
 
+    MONO_ARCH_SAVE_REGS;
+
     scale = pA->signscale.scale;
     DECTO128(pA, alo, ahi);
     sigDigits = calcDigits(alo, ahi); /* significant digits */
@@ -1138,6 +1157,9 @@ gint32 mono_decimal2string(/*[In]*/decimal_repr* pA, gint32 digits, gint32 decim
 }
 
 /**
+ * mono_decimal2UInt64:
+ * @pA
+ * @pResult
  * converts a decimal to an UInt64 without rounding
  */
 gint32 mono_decimal2UInt64(/*[In]*/decimal_repr* pA, guint64* pResult)
@@ -1145,6 +1167,8 @@ gint32 mono_decimal2UInt64(/*[In]*/decimal_repr* pA, guint64* pResult)
     guint64 alo, ahi;
     int scale;
 
+    MONO_ARCH_SAVE_REGS;
+
     DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
     if (scale > 0) {
@@ -1159,6 +1183,9 @@ gint32 mono_decimal2UInt64(/*[In]*/decimal_repr* pA, guint64* pResult)
 }
 
 /**
+ * mono_decimal2Int64:
+ * @pA:
+ * pResult:
  * converts a decimal to an Int64 without rounding
  */
 gint32 mono_decimal2Int64(/*[In]*/decimal_repr* pA, gint64* pResult)
@@ -1166,6 +1193,8 @@ gint32 mono_decimal2Int64(/*[In]*/decimal_repr* pA, gint64* pResult)
     guint64 alo, ahi;
     int sign, scale;
 
+    MONO_ARCH_SAVE_REGS;
+
     DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
     if (scale > 0) {
@@ -1193,6 +1222,8 @@ void mono_decimalFloorAndTrunc(/*[In, Out]*/decimal_repr* pA, gint32 floorFlag)
     int scale, sign, idx;
     int hasRest = 0;
 
+    MONO_ARCH_SAVE_REGS;
+
     scale = pA->signscale.scale;
     if (scale == 0) return; /* nothing to do */
 
@@ -1219,6 +1250,8 @@ void mono_decimalRound(/*[In, Out]*/decimal_repr* pA, gint32 decimals)
     guint64 alo, ahi;
     int scale, sign;
 
+    MONO_ARCH_SAVE_REGS;
+
     DECTO128(pA, alo, ahi);
     scale = pA->signscale.scale;
     sign = pA->signscale.sign;
@@ -1236,6 +1269,8 @@ gint32 mono_decimalMult(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
     guint32 factor;
     int scale, sign, rc;
 
+    MONO_ARCH_SAVE_REGS;
+
     mult96by96to192(pA->lo32, pA->mid32, pA->hi32, pB->lo32, pB->mid32, pB->hi32,
         &low, &mid, &high);
 
@@ -1333,6 +1368,8 @@ gint32 mono_decimalDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[I
     guint64 clo, chi; /* result */
     int scale, texp, rc;
 
+    MONO_ARCH_SAVE_REGS;
+
     rc = decimalDivSub(pA, pB, &clo, &chi, &texp);
     if (rc != DECIMAL_SUCCESS) {
         if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
@@ -1342,7 +1379,7 @@ gint32 mono_decimalDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[I
     /* 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));
+    /*test: printf("0: %.17e\n", (((double)chi) * pow(2,64) + clo) * pow(10, -scale) * pow(2, -exp));*/
     rc = rescale128(&clo, &chi, &scale, texp, 0, DECIMAL_MAX_SCALE, 1);
     if (rc != DECIMAL_SUCCESS) return rc;
 
@@ -1354,6 +1391,8 @@ gint32 mono_decimalIntDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /
     guint64 clo, chi; /* result */
     int scale, texp, rc;
 
+    MONO_ARCH_SAVE_REGS;
+
     rc = decimalDivSub(pA, pB, &clo, &chi, &texp);
     if (rc != DECIMAL_SUCCESS) {
         if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS;
@@ -1398,6 +1437,8 @@ gint32 mono_decimalCompare(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
     int log2a, log2b, delta, sign;
     decimal_repr aa;
 
+    MONO_ARCH_SAVE_REGS;
+
     sign = (pA->signscale.sign) ? -1 : 1;
 
     if (pA->signscale.sign ^ pB->signscale.sign) {
@@ -1429,6 +1470,17 @@ DECINLINE static void buildIEEE754Double(double* pd, int sign, int texp, guint64
 
     PRECONDITION(sign == 0 || sign == 1);
     *p = (((guint64)sign) << 63) | (((guint64)((1023+texp)&0x7ff)) << 52) | mantisse;
+#ifdef ARM_FPU_FPA
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+    {
+           guint32 temp;
+           guint32 *t = (guint32*)p;
+           temp = t [0];
+           t [0] = t [1];
+           t [1] = temp;
+    }
+#endif
+#endif
 }
 
 double mono_decimal2double(/*[In]*/decimal_repr* pA)
@@ -1438,6 +1490,8 @@ double mono_decimal2double(/*[In]*/decimal_repr* pA)
     guint32 overhang, factor, roundBits;
     int scale, texp, log5, i;
 
+    MONO_ARCH_SAVE_REGS;
+
     ahi = (((guint64)(pA->hi32)) << 32) | pA->mid32;
     alo = ((guint64)(pA->lo32)) << 32;
 
@@ -1485,7 +1539,7 @@ double mono_decimal2double(/*[In]*/decimal_repr* pA)
     ahi += 0x400;
     if ((ahi & LIT_GUINT64_HIGHBIT) == 0) { /* overflow ? */
         ahi >>= 1;
-        texp++;
+       texp--;
     } else if ((roundBits & 0x400) == 0) ahi &= ~1;
 
     /* 96 bit => 1 implizit bit and 52 explicit bits */
@@ -1503,6 +1557,8 @@ gint32 mono_decimalSetExponent(/*[In, Out]*/decimal_repr* pA, gint32 texp)
     int rc;
     int scale = pA->signscale.scale;
 
+    MONO_ARCH_SAVE_REGS;
+
     scale -= texp;
 
     if (scale < 0 || scale > DECIMAL_MAX_SCALE) {
@@ -1515,3 +1571,6 @@ gint32 mono_decimalSetExponent(/*[In, Out]*/decimal_repr* pA, gint32 texp)
         return DECIMAL_SUCCESS;
     }
 }
+
+#endif /* DISABLE_DECIMAL */
+