/*
- 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
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
#ifndef DISABLE_DECIMAL
__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;
+#elif defined(__s390x__) && defined(__NOT_YET)
+ guint64 r;
+
+ __asm__("\tlrvgr\t%1,%1\n"
+ "\tflogr\t%0,%1\n"
+ "\tjz\t0f\n"
+ "\tlghi\t%0,-1\n"
+ "0:\n"
+ : "=r" (r) : "r" (mask) : "cc");
#else
- return g_bit_nth_msf (mask, sizeof (gsize) * 8);
+ int i;
+
+ i = sizeof (gsize) * 8;
+ while (i > 0) {
+ i --;
+ if (mask & (1UL << i))
+ return i;
+ }
+ return -1;
#endif
}
DECINLINE static int rescale128(guint64* pclo, guint64* pchi, int* pScale, int texp,
int minScale, int maxScale, int roundFlag)
{
- guint32 factor, overhang, prev_lo;
+ guint32 factor, overhang;
int scale, i, rc, roundBit = 0;
PRECONDITION(texp >= 0);
overhang = (guint32)(*pchi >> 32);
}
*/
-
- prev_lo = *pclo;
- /*
- * FIXME: This code seems to cause crashes on the x86 buildbot during the
- * System.Data.DataSetExtensions tests.
- */
if (overhang > 0) {
int msf = my_g_bit_nth_msf (overhang);
int shift = msf - (DECIMAL_MAX_INTFACTORS + 2);
if (shift > 0) {
texp -= shift;
- prev_lo = (*pclo >> (shift - 1));
*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<<DECIMAL_MAX_INTFACTORS) || (*pclo & 1) == 0)) {
- --texp;
- prev_lo = *pclo;
+ if (--texp == 0) roundBit = (int)(*pclo & 1);
rshift128(pclo, pchi);
overhang >>= 1;
}
- if (texp == 0)
- roundBit = (int)(prev_lo & 1);
if (texp > DECIMAL_MAX_INTFACTORS) i = DECIMAL_MAX_INTFACTORS;
else i = texp;
return normalize128(pclo, pchi, pScale, roundFlag, roundBit);
}
+guint32 rest;
+static void trimExcessScale(guint64* pclo, guint64* pchi, int* pScale)
+{
+ guint64 ilo = *pclo, lastlo;
+ guint64 ihi = *pchi, lasthi;
+ int scale = *pScale;
+ int i = 0, roundBit;
+
+ while (scale > 0) {
+ scale--;
+ i++;
+ lastlo = ilo;
+ lasthi = ihi;
+
+ roundBit = div128by32(&ilo, &ihi, 10, &rest);
+ if (rest != 0){
+ i--;
+ if (i == 0)
+ return;
+
+ *pclo = lastlo;
+ *pchi = lasthi;
+ *pScale = scale+1;
+ return;
+ }
+ }
+}
+
/* performs a += b */
gint32 mono_decimalIncr(/*[In, Out]*/decimal_repr* pA, /*[In]*/decimal_repr* pB)
{
PRECONDITION(digits <= 15);
sign = ((*p & LIT_GUINT64_HIGHBIT) != 0) ? 1 : 0;
+
+ // Exponent
k = ((guint16)((*p) >> 52)) & 0x7FF;
+
+ // 1-bit followed by the fraction component from the float
alo = (*p & LIT_GUINT64(0xFFFFFFFFFFFFF)) | LIT_GUINT64(0x10000000000000);
ahi = 0;
}
scale = 0;
- rc = rescale128(&alo, &ahi, &scale, -texp, 0, DECIMAL_MAX_SCALE, 0);
+ rc = rescale128(&alo, &ahi, &scale, -texp, 0, DECIMAL_MAX_SCALE, 1);
if (rc != DECIMAL_SUCCESS) return rc;
sigDigits = calcDigits(alo, ahi);
}
}
+ //
+ // Turn the double 0.6 which at this point is:
+ // 0.6000000000000000
+ // into:
+ // 0.6
+ //
+ trimExcessScale (&alo, &ahi, &scale);
+
return pack128toDecimal(pA, alo, ahi, scale, sign);
}
}
}
+ // Set correct scale for zeros decimal (000 input is 0.00)
+ if (sigLen < 0 && len > decrDecimal)
+ sigLen = len;
+
scale = sigLen - decrDecimal;
if (i < len) { /* too much digits, we must round */
if (rc != DECIMAL_SUCCESS) return rc;
}
- if (alo == 0 && ahi == 0) {
- DECINIT(pA);
+ if (alo == 0 && ahi == 0 && scale <= 0) {
return DECIMAL_SUCCESS;
} else {
return pack128toDecimal(pA, alo, ahi, sigLen - decrDecimal, sign);