X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fdecimal.c;h=6524443eab3d57168325a710d2ac93e05d74671a;hb=e6d98ba2612414fbd67e463442e17de88d868cb1;hp=5ac7b957394b8fad9224fa60285dd26a8186ea2d;hpb=85042b357cb76c1d265f308fd2f9c6b63e3b53af;p=mono.git diff --git a/mono/metadata/decimal.c b/mono/metadata/decimal.c index 5ac7b957394..6524443eab3 100644 --- a/mono/metadata/decimal.c +++ b/mono/metadata/decimal.c @@ -1,30 +1,42 @@ /* - decimal.c - - conversions and numerical operations for the c# type System.Decimal - - Author: Martin Weindel (martin.weindel@t-online.de) - - (C) 2001 by Martin Weindel -*/ + * decimal.c + * + * conversions and numerical operations for the c# type System.Decimal + * + * Author: Martin Weindel (martin.weindel@t-online.de) + * + * (C) 2001 by Martin Weindel + */ /* * machine dependent configuration for * CSharp value type System.Decimal */ +#include "config.h" #include #include -#include #include #include #include +#ifdef HAVE_MEMORY_H +#include +#endif +#ifdef _MSC_VER +#include +#endif + +#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 */ @@ -90,7 +102,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) @@ -101,7 +113,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 */ @@ -391,8 +403,8 @@ DECINLINE static void div192by32(guint64* plo, guint64* pmi, guint64* phi, /* returns upper 32bit for a(192bit) /= b(32bit) a will contain remainder */ -static guint32 div192by96to32withRest(guint64* palo, guint64* pami, guint64* pahi, - guint32 blo, guint32 bmi, guint32 bhi) +DECINLINE static guint32 div192by96to32withRest(guint64* palo, guint64* pami, guint64* pahi, + guint32 blo, guint32 bmi, guint32 bhi) { guint64 rlo, rmi, rhi; /* remainder */ guint64 tlo, thi; /* term */ @@ -419,9 +431,9 @@ static guint32 div192by96to32withRest(guint64* palo, guint64* pami, guint64* pah /* c(128bit) = a(192bit) / b(96bit) b must be >= 2^95 */ -static void div192by96to128(guint64 alo, guint64 ami, guint64 ahi, - guint32 blo, guint32 bmi, guint32 bhi, - guint64* pclo, guint64* pchi) +DECINLINE 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; @@ -455,8 +467,8 @@ 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) +DECINLINE static int normalize128(guint64* pclo, guint64* pchi, int* pScale, + int roundFlag, int roundBit) { guint32 overhang = (guint32)(*pchi >> 32); int scale = *pScale; @@ -511,101 +523,95 @@ DECINLINE static int maxLeftShift(/*[In, Out]*/decimal_repr* pA) DECINLINE static void rshift128(guint64* pclo, guint64* pchi) { *pclo >>= 1; - if (*pchi & 1) *pclo |= LIT_GUINT64_HIGHBIT; + *pclo |= (*pchi & 1) << 63; *pchi >>= 1; } DECINLINE static void lshift96(guint32* pclo, guint32* pcmid, guint32* pchi) { *pchi <<= 1; - if (*pcmid & LIT_GUINT32_HIGHBIT) (*pchi)++; + *pchi |= (*pcmid & LIT_GUINT32_HIGHBIT) >> 31; *pcmid <<= 1; - if (*pclo & LIT_GUINT32_HIGHBIT) (*pcmid)++; + *pcmid |= (*pclo & LIT_GUINT32_HIGHBIT) >> 31; *pclo <<= 1; } DECINLINE static void lshift128(guint64* pclo, guint64* pchi) { *pchi <<= 1; - if (*pclo & LIT_GUINT64_HIGHBIT) (*pchi)++; + *pchi |= (*pclo & LIT_GUINT64_HIGHBIT) >> 63; *pclo <<= 1; } DECINLINE static void rshift192(guint64* pclo, guint64* pcmi, guint64* pchi) { *pclo >>= 1; - if (*pcmi & 1) *pclo |= LIT_GUINT64_HIGHBIT; + *pclo |= (*pcmi & 1) << 63; *pcmi >>= 1; - if (*pchi & 1) *pcmi |= LIT_GUINT64_HIGHBIT; + *pcmi |= (*pchi & 1) << 63; *pchi >>= 1; } +static inline gint +my_g_bit_nth_msf (gsize mask) +{ + /* Mask is expected to be != 0 */ +#if defined(__i386__) && defined(__GNUC__) + int r; + + __asm__("bsrl %1,%0\n\t" + : "=r" (r) : "rm" (mask)); + return r; +#elif defined(__x86_64) && defined(__GNUC__) + guint64 r; + + __asm__("bsrq %1,%0\n\t" + : "=r" (r) : "rm" (mask)); + return r; +#elif defined(__i386__) && defined(_MSC_VER) + unsigned long bIndex = 0; + if (_BitScanReverse (&bIndex, mask)) + return bIndex; + return -1; +#elif defined(__x86_64__) && defined(_MSC_VER) + unsigned long bIndex = 0; + if (_BitScanReverse64 (&bIndex, mask)) + return bIndex; + return -1; +#else + int i; + + i = sizeof (gsize) * 8; + while (i > 0) { + i --; + if (mask & (1UL << i)) + return i; + } + return -1; +#endif +} + /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */ DECINLINE static int log2_32(guint32 a) { - int tlog2 = 0; - if (a == 0) return DECIMAL_LOG_NEGINF; - if ((a >> 16) != 0) { - a >>= 16; - tlog2 += 16; - } - if ((a >> 8) != 0) { - a >>= 8; - tlog2 += 8; - } - if ((a >> 4) != 0) { - a >>= 4; - tlog2 += 4; - } - if ((a >> 2) != 0) { - a >>= 2; - tlog2 += 2; - } - if ((a >> 1) != 0) { - a >>= 1; - tlog2 += 1; - } - tlog2 += (int) a; - - return tlog2; + return my_g_bit_nth_msf (a) + 1; } /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */ DECINLINE static int log2_64(guint64 a) { - int tlog2 = 0; - if (a == 0) return DECIMAL_LOG_NEGINF; - if ((a >> 32) != 0) { - a >>= 32; - tlog2 += 32; - } - if ((a >> 16) != 0) { - a >>= 16; - tlog2 += 16; - } - if ((a >> 8) != 0) { - a >>= 8; - tlog2 += 8; - } - if ((a >> 4) != 0) { - a >>= 4; - tlog2 += 4; - } - if ((a >> 2) != 0) { - a >>= 2; - tlog2 += 2; - } - if ((a >> 1) != 0) { - a >>= 1; - tlog2 += 1; - } - tlog2 += (int) a; - - return tlog2; +#if SIZEOF_VOID_P == 8 + return my_g_bit_nth_msf (a) + 1; +#else + if ((a >> 32) == 0) + return my_g_bit_nth_msf ((guint32)a) + 1; + else + return my_g_bit_nth_msf ((guint32)(a >> 32)) + 1 + 32; +#endif } /* returns log2(a) or DECIMAL_LOG_NEGINF for a = 0 */ @@ -685,11 +691,38 @@ DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int t /* reduce exp */ while (texp > 0 && scale <= maxScale) { overhang = (guint32)(*pchi >> 32); - while (texp > 0 && ((*pclo & 1) == 0 || overhang > (2< 0 && (overhang > (2<> 32); } + */ + if (overhang > 0) { + int msf = my_g_bit_nth_msf (overhang); + int shift = msf - (DECIMAL_MAX_INTFACTORS + 2); + + if (shift >= texp) + shift = texp - 1; + + if (shift > 0) { + texp -= shift; + *pclo = (*pclo >> shift) | ((*pchi & ((1 << shift) - 1)) << (64 - shift)); + *pchi >>= shift; + overhang >>= shift; + + g_assert (texp > 0); + g_assert (overhang > (2 << DECIMAL_MAX_INTFACTORS)); + } + } + while (texp > 0 && (overhang > (2<>= 1; + } if (texp > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS; else i = texp; @@ -770,7 +803,7 @@ gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB) /* 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; + log2Result = MAX (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 */ @@ -798,8 +831,6 @@ gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB) add128(alo, ahi, blo, bhi, &alo, &ahi); } - if (rc != DECIMAL_SUCCESS) return rc; - rc = rescale128(&alo, &ahi,&scaleA, 0, 0, DECIMAL_MAX_SCALE, 1); } @@ -920,7 +951,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 ! * @@ -1027,6 +1064,8 @@ 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: @@ -1047,7 +1086,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) { @@ -1143,6 +1181,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) @@ -1166,6 +1207,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) @@ -1278,8 +1322,8 @@ gint32 mono_decimalMult(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB) return pack128toDecimal(pA, low, mid, scale, sign); } -static int decimalDivSub(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB, - guint64* pclo, guint64* pchi, int* pExp) +static DECINLINE int decimalDivSub(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB, + guint64* pclo, guint64* pchi, int* pExp) { guint64 alo, ami, ahi; guint64 tlo, tmi, thi; @@ -1303,14 +1347,52 @@ static int decimalDivSub(/*[In]*/decimal_repr* pA, /*[In]*/decimal_repr* pB, } /* enlarge dividend to get maximal precision */ - for (ashift = 0; (ahi & LIT_GUINT64_HIGHBIT) == 0; ++ashift) { - lshift128(&ami, &ahi); - } + if (ahi == 0) { + ahi = ami; + ami = 0; + for (ashift = 64; (ahi & LIT_GUINT64_HIGHBIT) == 0; ++ashift) { + ahi <<= 1; + } + } else { + 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); - } + if (bhi == 0) { + + if (bmi == 0) { + guint32 hi_shift; + bhi = blo; + bmi = 0; + blo = 0; + + //g_assert (g_bit_nth_msf (bhi, 32) == my_g_bit_nth_msf (bhi)); + + hi_shift = 31 - my_g_bit_nth_msf (bhi); + bhi <<= hi_shift; + bshift = 64 + hi_shift; + } else { + bhi = bmi; + bmi = blo; + blo = 0; + + for (bshift = 32; (bhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift) { + bhi <<= 1; + bhi |= (bmi & LIT_GUINT32_HIGHBIT) >> 31; + bmi <<= 1; + } + } + } else { + for (bshift = 0; (bhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift) { + bhi <<= 1; + bhi |= (bmi & LIT_GUINT32_HIGHBIT) >> 31; + bmi <<= 1; + bmi |= (blo & LIT_GUINT32_HIGHBIT) >> 31; + blo <<= 1; + } + } thi = ((guint64)bhi)<<32 | bmi; tmi = ((guint64)blo)<<32; @@ -1350,6 +1432,16 @@ gint32 mono_decimalDiv(/*[Out]*/decimal_repr* pC, /*[In]*/decimal_repr* pA, /*[I MONO_ARCH_SAVE_REGS; + /* Check for common cases */ + if (mono_decimalCompare (pA, pB) == 0) + /* One */ + return pack128toDecimal (pC, 1, 0, 0, 0); + pA->signscale.sign = pA->signscale.sign ? 0 : 1; + if (mono_decimalCompare (pA, pB) == 0) + /* Minus one */ + return pack128toDecimal (pC, 1, 0, 0, 1); + pA->signscale.sign = pA->signscale.sign ? 0 : 1; + rc = decimalDivSub(pA, pB, &clo, &chi, &texp); if (rc != DECIMAL_SUCCESS) { if (rc == DECIMAL_FINISHED) rc = DECIMAL_SUCCESS; @@ -1450,6 +1542,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) @@ -1540,3 +1643,6 @@ gint32 mono_decimalSetExponent(/*[In, Out]*/decimal_repr* pA, gint32 texp) return DECIMAL_SUCCESS; } } + +#endif /* DISABLE_DECIMAL */ +