#include <glib.h>
#include <mono/utils/mono-compiler.h>
#include <mono/metadata/exception.h>
+#include <mono/metadata/object-internals.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <intrin.h>
#endif
#include "decimal-ms.h"
+#include "number-ms.h"
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define DECIMAL_LO32(dec) ((dec).v.v.Lo32)
#define DECIMAL_MID32(dec) ((dec).v.v.Mid32)
#define DECIMAL_HI32(dec) ((dec).Hi32)
-#define DECIMAL_LO64_GET(dec) ((dec).v.Lo64)
-#define DECIMAL_LO64_SET(dec,value) {(dec).v.Lo64 = value; }
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+# define DECIMAL_LO64_GET(dec) (((uint64_t)((dec).v.v.Mid32) << 32) | (dec).v.v.Lo32)
+# define DECIMAL_LO64_SET(dec,value) {(dec).v.v.Lo32 = (value); (dec).v.v.Mid32 = ((value) >> 32); }
+#else
+# define DECIMAL_LO64_GET(dec) ((dec).v.Lo64)
+# define DECIMAL_LO64_SET(dec,value) {(dec).v.Lo64 = value; }
+#endif
#define DECIMAL_SETZERO(dec) {DECIMAL_LO32(dec) = 0; DECIMAL_MID32(dec) = 0; DECIMAL_HI32(dec) = 0; DECIMAL_SIGNSCALE(dec) = 0;}
#define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); \
} SPLIT64;
static const SPLIT64 ten_to_eighteen = { 1000000000000000000ULL };
-// Double Bias
-#define DBLBIAS 1022
-// Structure to access an encoded double floating point
-typedef union{
- struct {
-#if BYTE_ORDER == G_BIG_ENDIAN
- unsigned int sign:1;
- unsigned int exp:11;
- unsigned int mantHi:20;
- unsigned int mantLo;
-#else // BIGENDIAN
- unsigned int mantLo;
- unsigned int mantHi:20;
- unsigned int exp:11;
- unsigned int sign:1;
-#endif
- } u;
- double dbl;
-} DoubleStructure;
-
-#if BYTE_ORDER == G_BIG_ENDIAN
-#define DEFDS(Lo, Hi, exp, sign) { {sign, exp, Hi, Lo } }
-#else
-#define DEFDS(Lo, Hi, exp, sign) { {Lo, Hi, exp, sign} }
-#endif
-
-const DoubleStructure ds2to64 = DEFDS(0, 0, DBLBIAS + 65, 0);
-
-// Single floating point Bias
-#define SNGBIAS 126
-
-// Structure to access an encoded single floating point
-typedef struct {
-#if BYTE_ORDER == G_BIG_ENDIAN
- unsigned int sign:1;
- unsigned int exp:8;
- unsigned int mant:23;
-#else
- unsigned int mant:23;
- unsigned int exp:8;
- unsigned int sign:1;
-#endif
-} SingleStructure;
+const MonoDouble_double ds2to64 = { .s = { .sign = 0, .exp = MONO_DOUBLE_BIAS + 65, .mantHi = 0, .mantLo = 0 } };
//
// Data tables
// Decimal multiply
// Returns: MONO_DECIMAL_OVERFLOW or MONO_DECIMAL_OK
static MonoDecimalStatus
-VarDecMul(MonoDecimal * left, MonoDecimal * right, MonoDecimal * result)
+mono_decimal_multiply_result(MonoDecimal * left, MonoDecimal * right, MonoDecimal * result)
{
SPLIT64 tmp;
SPLIT64 tmp2;
}
// Decimal addition
-static MonoDecimalStatus
-VarDecAdd(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_add(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
{
return DecAddSub (left, right, result, 0);
}
// Decimal subtraction
-static MonoDecimalStatus
-VarDecSub(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_sub(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
{
return DecAddSub (left, right, result, DECIMAL_NEG);
}
}
}
-// VarDecDiv - Decimal divide
-static MonoDecimalStatus
-VarDecDiv(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
+// mono_decimal_divide - Decimal divide
+static MonoDecimalStatus G_GNUC_UNUSED
+mono_decimal_divide_result(MonoDecimal *left, MonoDecimal *right, MonoDecimal *result)
{
uint32_t quo[3];
uint32_t quoSave[3];
return MONO_DECIMAL_OK;
}
-// VarDecAbs - Decimal Absolute Value
-static void
-VarDecAbs (MonoDecimal *pdecOprd, MonoDecimal *result)
+// mono_decimal_absolute - Decimal Absolute Value
+static void G_GNUC_UNUSED
+mono_decimal_absolute (MonoDecimal *pdecOprd, MonoDecimal *result)
{
COPYDEC(*result, *pdecOprd);
result->u.u.sign &= ~DECIMAL_NEG;
// Microsoft does not set reserved here
}
-// VarDecFix - Decimal Fix (chop to integer)
+// mono_decimal_fix - Decimal Fix (chop to integer)
static void
-VarDecFix (MonoDecimal *pdecOprd, MonoDecimal *result)
+mono_decimal_fix (MonoDecimal *pdecOprd, MonoDecimal *result)
{
DecFixInt(result, pdecOprd);
}
-
-// VarDecInt - Decimal Int (round down to integer)
+// mono_decimal_round_to_int - Decimal Int (round down to integer)
static void
-VarDecInt (MonoDecimal *pdecOprd, MonoDecimal *result)
+mono_decimal_round_to_int (MonoDecimal *pdecOprd, MonoDecimal *result)
{
if (DecFixInt(result, pdecOprd) != 0 && (result->u.u.sign & DECIMAL_NEG)) {
// We have chopped off a non-zero amount from a negative value. Since
}
}
-
-// VarDecNeg - Decimal Negate
-static void
-VarDecNeg (MonoDecimal *pdecOprd, MonoDecimal *result)
+// mono_decimal_negate - Decimal Negate
+static void G_GNUC_UNUSED
+mono_decimal_negate (MonoDecimal *pdecOprd, MonoDecimal *result)
{
COPYDEC(*result, *pdecOprd);
// Microsoft does not set result->reserved to zero on this case.
// Returns: MONO_DECIMAL_INVALID_ARGUMENT, MONO_DECIMAL_OK
//
static MonoDecimalStatus
-VarDecRound(MonoDecimal *input, int cDecimals, MonoDecimal *result)
+mono_decimal_round_result(MonoDecimal *input, int cDecimals, MonoDecimal *result)
{
uint32_t num[3];
uint32_t rem;
//
// Returns MONO_DECIMAL_OK or MONO_DECIMAL_OVERFLOW
static MonoDecimalStatus
-VarDecFromR4 (float input, MonoDecimal* result)
+mono_decimal_from_float (float input_f, MonoDecimal* result)
{
int exp; // number of bits to left of binary point
int power;
SPLIT64 sdlLo;
SPLIT64 sdlHi;
int lmax, cur; // temps used during scale reduction
-
+ MonoSingle_float input = { .f = input_f };
+
// The most we can scale by is 10^28, which is just slightly more
// than 2^93. So a float with an exponent of -94 could just
// barely reach 0.5, but smaller exponents will always round to zero.
//
- if ((exp = ((SingleStructure *)&input)->exp - SNGBIAS) < -94 ) {
+ if ((exp = input.s.exp - MONO_SINGLE_BIAS) < -94 ) {
DECIMAL_SETZERO(*result);
return MONO_DECIMAL_OK;
}
// the exponent by log10(2). Using scaled integer multiplcation,
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
//
- dbl = fabs(input);
+ dbl = fabs(input.f);
power = 6 - ((exp * 19728) >> 16);
if (power >= 0) {
DECIMAL_SCALE(*result) = power;
}
- DECIMAL_SIGN(*result) = (char)((SingleStructure *)&input)->sign << 7;
+ DECIMAL_SIGN(*result) = (char)input.s.sign << 7;
return MONO_DECIMAL_OK;
}
-//
// Returns MONO_DECIMAL_OK or MONO_DECIMAL_OVERFLOW
static MonoDecimalStatus
-VarDecFromR8 (double input, MonoDecimal *result)
+mono_decimal_from_double (double input_d, MonoDecimal *result)
{
int exp; // number of bits to left of binary point
int power; // power-of-10 scale factor
int lmax, cur; // temps used during scale reduction
uint32_t pwr_cur;
uint32_t quo;
-
+ MonoDouble_double input = { .d = input_d };
// The most we can scale by is 10^28, which is just slightly more
// than 2^93. So a float with an exponent of -94 could just
// barely reach 0.5, but smaller exponents will always round to zero.
//
- if ((exp = ((DoubleStructure *)&input)->u.exp - DBLBIAS) < -94) {
+ if ((exp = input.s.exp - MONO_DOUBLE_BIAS) < -94) {
DECIMAL_SETZERO(*result);
return MONO_DECIMAL_OK;
}
// the exponent by log10(2). Using scaled integer multiplcation,
// log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
//
- dbl = fabs(input);
+ dbl = fabs(input.d);
power = 14 - ((exp * 19728) >> 16);
if (power >= 0) {
DECIMAL_MID32(*result) = sdlMant.u.Hi;
}
- DECIMAL_SIGN(*result) = (char)((DoubleStructure *)&input)->u.sign << 7;
+ DECIMAL_SIGN(*result) = (char)input.s.sign << 7;
return MONO_DECIMAL_OK;
}
// Returns: MONO_DECIMAL_OK, or MONO_DECIMAL_INVALID_ARGUMENT
static MonoDecimalStatus
-VarR8FromDec(MonoDecimal *input, double *result)
+mono_decimal_to_double_result(MonoDecimal *input, double *result)
{
SPLIT64 tmp;
double dbl;
tmp.u.Hi = DECIMAL_MID32(*input);
if ((int32_t)DECIMAL_MID32(*input) < 0)
- dbl = (ds2to64.dbl + (double)(int64_t)tmp.int64 +
- (double)DECIMAL_HI32(*input) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*input)) ;
+ dbl = (ds2to64.d + (double)(int64_t)tmp.int64 +
+ (double)DECIMAL_HI32(*input) * ds2to64.d) / fnDblPower10(DECIMAL_SCALE(*input)) ;
else
dbl = ((double)(int64_t)tmp.int64 +
- (double)DECIMAL_HI32(*input) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*input));
+ (double)DECIMAL_HI32(*input) * ds2to64.d) / fnDblPower10(DECIMAL_SCALE(*input));
if (DECIMAL_SIGN(*input))
dbl = -dbl;
// Returns: MONO_DECIMAL_OK, or MONO_DECIMAL_INVALID_ARGUMENT
static MonoDecimalStatus
-VarR4FromDec(MonoDecimal *input, float *result)
+mono_decimal_to_float_result(MonoDecimal *input, float *result)
{
double dbl;
// Can't overflow; no errors possible.
//
- VarR8FromDec(input, &dbl);
+ mono_decimal_to_double_result(input, &dbl);
*result = (float)dbl;
return MONO_DECIMAL_OK;
}
uint32_t right_sign;
MonoDecimal result;
+ result.Hi32 = 0; // Just to shut up the compiler
+
// First check signs and whether either are zero. If both are
// non-zero and of the same sign, just use subtraction to compare.
//
}
//
- // Signs are different. Used signed byte compares
+ // Signs are different. Use signed byte comparison
//
- if ((char)left_sign > (char)right_sign)
+ if ((signed char)left_sign > (signed char)right_sign)
return MONO_DECIMAL_CMP_GT;
return MONO_DECIMAL_CMP_LT;
}
void
mono_decimal_init_single (MonoDecimal *_this, float value)
{
- if (VarDecFromR4 (value, _this) == MONO_DECIMAL_OVERFLOW)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (mono_decimal_from_float (value, _this) == MONO_DECIMAL_OVERFLOW) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
_this->reserved = 0;
}
void
mono_decimal_init_double (MonoDecimal *_this, double value)
{
- if (VarDecFromR8 (value, _this) == MONO_DECIMAL_OVERFLOW)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (mono_decimal_from_double (value, _this) == MONO_DECIMAL_OVERFLOW) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
_this->reserved = 0;
}
{
MonoDecimal decRes;
- VarDecInt(d, &decRes);
+ mono_decimal_round_to_int(d, &decRes);
// copy decRes into d
COPYDEC(*d, decRes);
{
double dbl;
- if (VarR8FromDec(d, &dbl) != MONO_DECIMAL_OK)
+ if (mono_decimal_to_double_result(d, &dbl) != MONO_DECIMAL_OK)
return 0;
if (dbl == 0.0) {
{
MonoDecimal decRes;
- MonoDecimalStatus status = VarDecMul(d1, d2, &decRes);
- if (status != MONO_DECIMAL_OK)
- mono_raise_exception (mono_get_exception_overflow ());
+ MonoDecimalStatus status = mono_decimal_multiply_result(d1, d2, &decRes);
+ if (status != MONO_DECIMAL_OK) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
COPYDEC(*d1, decRes);
d1->reserved = 0;
MonoDecimal decRes;
// GC is only triggered for throwing, no need to protect result
- if (decimals < 0 || decimals > 28)
- mono_raise_exception (mono_get_exception_argument_out_of_range ("d"));
+ if (decimals < 0 || decimals > 28) {
+ mono_set_pending_exception (mono_get_exception_argument_out_of_range ("d"));
+ return;
+ }
- VarDecRound(d, decimals, &decRes);
+ mono_decimal_round_result(d, decimals, &decRes);
// copy decRes into d
COPYDEC(*d, decRes);
{
double result = 0.0;
// Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
- VarR8FromDec(&d, &result);
+ mono_decimal_to_double_result(&d, &result);
return result;
}
MonoDecimal result;
// The following can not return an error, it only returns INVALID_ARG if the decimals is < 0
- VarDecRound(&d, 0, &result);
+ mono_decimal_round_result(&d, 0, &result);
if (DECIMAL_SCALE(result) != 0) {
d = result;
- VarDecFix (&d, &result);
+ mono_decimal_fix (&d, &result);
}
if (DECIMAL_HI32(result) == 0 && DECIMAL_MID32(result) == 0) {
}
}
- mono_raise_exception (mono_get_exception_overflow ());
- // Not reachable
+ mono_set_pending_exception (mono_get_exception_overflow ());
return 0;
}
{
float result = 0.0f;
// Note: this can fail if the input is an invalid decimal, but for compatibility we should return 0
- VarR4FromDec(&d, &result);
+ mono_decimal_to_float_result(&d, &result);
return result;
}
{
MonoDecimal decRes;
- VarDecFix(d, &decRes);
+ mono_decimal_fix(d, &decRes);
// copy decRes into d
COPYDEC(*d, decRes);
// The addition carried above 96 bits. Divide the result by 10,
// dropping the scale factor.
//
- if (DECIMAL_SCALE(result) == 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (DECIMAL_SCALE(result) == 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
DECIMAL_SCALE(result)--;
sdlTmp.u.Lo = DECIMAL_HI32(result);
num[1] = DECIMAL_MID32(result);
num[2] = DECIMAL_HI32(result);
DECIMAL_SCALE(result) = (uint8_t)ScaleResult(num, hi_prod, DECIMAL_SCALE(result));
- if (DECIMAL_SCALE(result) == (uint8_t)-1)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (DECIMAL_SCALE(result) == (uint8_t)-1) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
DECIMAL_LO32(result) = num[0];
DECIMAL_MID32(result) = num[1];
if (divisor[1] == 0 && divisor[2] == 0) {
// Divisor is only 32 bits. Easy divide.
//
- if (divisor[0] == 0)
- mono_raise_exception (mono_get_exception_divide_by_zero ());
+ if (divisor[0] == 0) {
+ mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+ return;
+ }
quo[0] = DECIMAL_LO32(*left);
quo[1] = DECIMAL_MID32(*left);
(tmp > divisor[0] || (quo[0] & 1)))) {
RoundUp:
if (!Add32To96(quo, 1)) {
- if (scale == 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (scale == 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
scale--;
OverflowUnscale(quo, TRUE);
break;
break;
}
- if (cur_scale < 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (cur_scale < 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
HaveScale:
pwr = power10[cur_scale];
scale += cur_scale;
- if (IncreaseScale(quo, pwr) != 0)
- mono_raise_exception (mono_get_exception_overflow ());
-
+ if (IncreaseScale(quo, pwr) != 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
sdlTmp.int64 = DivMod64by32(UInt32x32To64(rem[0], pwr), divisor[0]);
rem[0] = sdlTmp.u.Hi;
if (!Add32To96(quo, sdlTmp.u.Lo)) {
- if (scale == 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (scale == 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
scale--;
OverflowUnscale(quo, (rem[0] != 0));
break;
break;
}
- if (cur_scale < 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (cur_scale < 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
HaveScale64:
pwr = power10[cur_scale];
scale += cur_scale;
- if (IncreaseScale(quo, pwr) != 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (IncreaseScale(quo, pwr) != 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
rem[2] = 0; // rem is 64 bits, IncreaseScale uses 96
IncreaseScale(rem, pwr);
tmp = Div96By64(rem, sdlDivisor);
if (!Add32To96(quo, tmp)) {
- if (scale == 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (scale == 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
scale--;
OverflowUnscale(quo, (rem[0] != 0 || rem[1] != 0));
break;
break;
}
- if (cur_scale < 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (cur_scale < 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
HaveScale96:
pwr = power10[cur_scale];
scale += cur_scale;
- if (IncreaseScale(quo, pwr) != 0)
- mono_raise_exception (mono_get_exception_overflow ());
-
+ if (IncreaseScale(quo, pwr) != 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
+
rem[3] = IncreaseScale(rem, pwr);
tmp = Div128By96(rem, divisor);
if (!Add32To96(quo, tmp)) {
- if (scale == 0)
- mono_raise_exception (mono_get_exception_overflow ());
+ if (scale == 0) {
+ mono_set_pending_exception (mono_get_exception_overflow ());
+ return;
+ }
scale--;
OverflowUnscale(quo, (rem[0] != 0 || rem[1] != 0 || rem[2] != 0 || rem[3] != 0));
}
#define DECIMAL_PRECISION 29
-#define NUMBER_MAXDIGITS 50
-typedef struct {
- int32_t precision;
- int32_t scale;
- int32_t sign;
- uint16_t digits[NUMBER_MAXDIGITS + 1];
- uint16_t* allDigits;
-} CLRNumber;
int
mono_decimal_from_number (void *from, MonoDecimal *target)
{
- CLRNumber *number = (CLRNumber *) from;
+ MonoNumber *number = (MonoNumber *) from;
uint16_t* p = number->digits;
MonoDecimal d;
int e = number->scale;