diff options
author | Pent Ploompuu <kaalikas@gmail.com> | 2018-07-17 18:41:39 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2018-07-17 08:41:39 -0700 |
commit | 2b50bba8131acca2ab535e144796941ad93487b7 (patch) | |
tree | 5c3f9901749fceb1aa1e14c67665a76b5a9ee408 /src/classlibnative | |
parent | 624f72d55a92e49aef3c3cd6e69150fa3b085fac (diff) | |
download | coreclr-2b50bba8131acca2ab535e144796941ad93487b7.tar.gz coreclr-2b50bba8131acca2ab535e144796941ad93487b7.tar.bz2 coreclr-2b50bba8131acca2ab535e144796941ad93487b7.zip |
Move Decimal to shared (#18948)
* Move Decimal to shared
* Remove DecimalCanonicalize{Internal}
Diffstat (limited to 'src/classlibnative')
-rw-r--r-- | src/classlibnative/bcltype/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/classlibnative/bcltype/currency.cpp | 42 | ||||
-rw-r--r-- | src/classlibnative/bcltype/currency.h | 24 | ||||
-rw-r--r-- | src/classlibnative/bcltype/decimal.cpp | 2534 | ||||
-rw-r--r-- | src/classlibnative/bcltype/decimal.h | 52 | ||||
-rw-r--r-- | src/classlibnative/bcltype/number.cpp | 26 | ||||
-rw-r--r-- | src/classlibnative/bcltype/number.h | 1 |
7 files changed, 3 insertions, 2678 deletions
diff --git a/src/classlibnative/bcltype/CMakeLists.txt b/src/classlibnative/bcltype/CMakeLists.txt index 62cf9682c3..41cf3cffb5 100644 --- a/src/classlibnative/bcltype/CMakeLists.txt +++ b/src/classlibnative/bcltype/CMakeLists.txt @@ -8,8 +8,6 @@ set(BCLTYPE_SOURCES arraynative.cpp arrayhelpers.cpp bignum.cpp - currency.cpp - decimal.cpp diyfp.cpp grisu3.cpp number.cpp diff --git a/src/classlibnative/bcltype/currency.cpp b/src/classlibnative/bcltype/currency.cpp deleted file mode 100644 index 4506105e25..0000000000 --- a/src/classlibnative/bcltype/currency.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: Currency.cpp -// - -// - -#include "common.h" -#include "object.h" -#include "excep.h" -#include "frames.h" -#include "vars.hpp" -#include "currency.h" -#include "string.h" - - -FCIMPL2_IV(void, COMCurrency::DoToDecimal, DECIMAL * result, CY c) -{ - FCALL_CONTRACT; - - // GC could only happen when exception is thrown, no need to protect result - HELPER_METHOD_FRAME_BEGIN_0(); - - _ASSERTE(result); - HRESULT hr = VarDecFromCy(c, result); - if (FAILED(hr)) - { - // Didn't expect to get here. Update code for this HR. - _ASSERTE(S_OK == hr); - COMPlusThrowHR(hr); - } - - if (FAILED(DecimalCanonicalize(result))) - COMPlusThrow(kOverflowException, W("Overflow_Currency")); - - result->wReserved = 0; - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND diff --git a/src/classlibnative/bcltype/currency.h b/src/classlibnative/bcltype/currency.h deleted file mode 100644 index a1ba64e463..0000000000 --- a/src/classlibnative/bcltype/currency.h +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: Currency.h -// - -// - -#ifndef _CURRENCY_H_ -#define _CURRENCY_H_ - -#include <oleauto.h> -#include <pshpack1.h> - -class COMCurrency -{ -public: - static FCDECL2_IV(void, DoToDecimal, DECIMAL * result, CY c); -}; - -#include <poppack.h> - -#endif // _CURRENCY_H_ diff --git a/src/classlibnative/bcltype/decimal.cpp b/src/classlibnative/bcltype/decimal.cpp deleted file mode 100644 index 729b19f334..0000000000 --- a/src/classlibnative/bcltype/decimal.cpp +++ /dev/null @@ -1,2534 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: decimal.cpp -// - -// - -#include "common.h" -#include "object.h" -#include "excep.h" -#include "frames.h" -#include "vars.hpp" -#include "decimal.h" -#include "string.h" - -LONG g_OLEAUT32_Loaded = 0; - -unsigned int DecDivMod1E9(DECIMAL* value); -void DecMul10(DECIMAL* value); -void DecAddInt32(DECIMAL* value, unsigned int i); - -#define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); DECIMAL_LO64_SET(dest, DECIMAL_LO64_GET(src));} - -FCIMPL2_IV(void, COMDecimal::InitSingle, DECIMAL *_this, float value) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - _ASSERTE(_this != NULL); - HRESULT hr = VarDecFromR4(value, _this); - if (FAILED(hr)) - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - _this->wReserved = 0; -} -FCIMPLEND - -FCIMPL2_IV(void, COMDecimal::InitDouble, DECIMAL *_this, double value) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - _ASSERTE(_this != NULL); - HRESULT hr = VarDecFromR8(value, _this); - if (FAILED(hr)) - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - _this->wReserved = 0; -} -FCIMPLEND - - -#ifdef _MSC_VER -// C4702: unreachable code on IA64 retail -#pragma warning(push) -#pragma warning(disable:4702) -#endif -FCIMPL2(INT32, COMDecimal::DoCompare, DECIMAL * d1, DECIMAL * d2) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - HRESULT hr = VarDecCmp(d1, d2); - if (FAILED(hr) || (int)hr == VARCMP_NULL) { - _ASSERTE(!"VarDecCmp failed in Decimal::Compare"); - FCThrowRes(kOverflowException, W("Overflow_Decimal")); - } - - INT32 retVal = ((int)hr) - 1; - FC_GC_POLL_RET (); - return retVal; -} -FCIMPLEND -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -FCIMPL1(void, COMDecimal::DoFloor, DECIMAL * d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL decRes; - HRESULT hr; - hr = VarDecInt(d, &decRes); - - // VarDecInt can't overflow, as of source for OleAut32 build 4265. - // It only returns NOERROR - _ASSERTE(hr==NOERROR); - - // copy decRes into d - COPYDEC(*d, decRes) - d->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - -FCIMPL3(void, COMDecimal::DoMultiply, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL decRes; - - // GC is only triggered for throwing, no need to protect result - HRESULT hr = VarDecMul(d1, d2, &decRes); - if (FAILED(hr)) { - *overflowed = true; - FC_GC_POLL(); - return; - } - - // copy decRes into d1 - COPYDEC(*d1, decRes) - d1->wReserved = 0; - *overflowed = false; - FC_GC_POLL(); -} -FCIMPLEND - - -FCIMPL2(void, COMDecimal::DoMultiplyThrow, DECIMAL * d1, DECIMAL * d2) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL decRes; - - // GC is only triggered for throwing, no need to protect result - HRESULT hr = VarDecMul(d1, d2, &decRes); - if (FAILED(hr)) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - - // copy decRes into d1 - COPYDEC(*d1, decRes) - d1->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - -FCIMPL2(void, COMDecimal::DoRound, DECIMAL * d, INT32 decimals) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL decRes; - - // GC is only triggered for throwing, no need to protect result - if (decimals < 0 || decimals > 28) - FCThrowArgumentOutOfRangeVoid(W("decimals"), W("ArgumentOutOfRange_DecimalRound")); - HRESULT hr = VarDecRound(d, decimals, &decRes); - if (FAILED(hr)) - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - - // copy decRes into d - COPYDEC(*d, decRes) - d->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - -FCIMPL2_IV(void, COMDecimal::DoToCurrency, CY * result, DECIMAL d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - // GC is only triggered for throwing, no need to protect result - HRESULT hr = VarCyFromDec(&d, result); - if (FAILED(hr)) { - _ASSERTE(hr != E_INVALIDARG); - FCThrowResVoid(kOverflowException, W("Overflow_Currency")); - } -} -FCIMPLEND - -FCIMPL1(double, COMDecimal::ToDouble, FC_DECIMAL d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - 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); - return result; -} -FCIMPLEND - -FCIMPL1(INT32, COMDecimal::ToInt32, FC_DECIMAL d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL result; - HRESULT hr = VarDecRound(&d, 0, &result); - if (FAILED(hr)) - FCThrowRes(kOverflowException, W("Overflow_Decimal")); - - result.wReserved = 0; - - if( DECIMAL_SCALE(result) != 0) { - d = result; - VarDecFix(&d, &result); - } - - if (DECIMAL_HI32(result) == 0 && DECIMAL_MID32(result) == 0) { - INT32 i = DECIMAL_LO32(result); - if ((INT16)DECIMAL_SIGNSCALE(result) >= 0) { - if (i >= 0) return i; - } - else { - // Int32.MinValue is represented as sign being negative - // and Lo32 being 0x80000000 (-ve number). Return that as is without - // reversing the sign of the number. - if(i == 0x80000000) return i; - i = -i; - if (i <= 0) return i; - } - } - FCThrowRes(kOverflowException, W("Overflow_Int32")); -} -FCIMPLEND - -FCIMPL1(float, COMDecimal::ToSingle, FC_DECIMAL d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - 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); - return result; -} -FCIMPLEND - -FCIMPL1(void, COMDecimal::DoTruncate, DECIMAL * d) -{ - FCALL_CONTRACT; - - ENSURE_OLEAUT32_LOADED(); - - DECIMAL decRes; - - VarDecFix(d, &decRes); - - // copy decRes into d - COPYDEC(*d, decRes) - d->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - -int COMDecimal::NumberToDecimal(NUMBER* number, DECIMAL* value) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(number != NULL); - _ASSERTE(value != NULL); - - DECIMAL d; - d.wReserved = 0; - DECIMAL_SIGNSCALE(d) = 0; - DECIMAL_HI32(d) = 0; - DECIMAL_LO32(d) = 0; - DECIMAL_MID32(d) = 0; - wchar_t* p = number->digits; - _ASSERT(p != NULL); - int e = number->scale; - if (!*p) { - // To avoid risking an app-compat issue with pre 4.5 (where some app was illegally using Reflection to examine the internal scale bits), we'll only force - // the scale to 0 if the scale was previously positive - if (e > 0) { - e = 0; - } - } else { - if (e > DECIMAL_PRECISION) return 0; - while ((e > 0 || (*p && e > -28)) && - (DECIMAL_HI32(d) < 0x19999999 || (DECIMAL_HI32(d) == 0x19999999 && - (DECIMAL_MID32(d) < 0x99999999 || (DECIMAL_MID32(d) == 0x99999999 && - (DECIMAL_LO32(d) < 0x99999999 || (DECIMAL_LO32(d) == 0x99999999 && *p <= '5'))))))) { - DecMul10(&d); - if (*p) DecAddInt32(&d, *p++ - '0'); - e--; - } - if (*p++ >= '5') { - bool round = true; - if (*(p-1) == '5' && *(p-2) % 2 == 0) { // Check if previous digit is even, only if the when we are unsure whether hows to do Banker's rounding - // For digits > 5 we will be roundinp up anyway. - int count = 20; // Look at the next 20 digits to check to round - while (*p == '0' && count != 0) { - p++; - count--; - } - if (*p == '\0' || count == 0) - round = false;// Do nothing - } - - if (round) { - DecAddInt32(&d, 1); - if ((DECIMAL_HI32(d) | DECIMAL_MID32(d) | DECIMAL_LO32(d)) == 0) { - DECIMAL_HI32(d) = 0x19999999; - DECIMAL_MID32(d) = 0x99999999; - DECIMAL_LO32(d) = 0x9999999A; - e++; - } - } - } - } - if (e > 0) return 0; - if (e <= -DECIMAL_PRECISION) - { - // Parsing a large scale zero can give you more precision than fits in the decimal. - // This should only happen for actual zeros or very small numbers that round to zero. - DECIMAL_SIGNSCALE(d) = 0; - DECIMAL_HI32(d) = 0; - DECIMAL_LO32(d) = 0; - DECIMAL_MID32(d) = 0; - DECIMAL_SCALE(d) = (DECIMAL_PRECISION - 1); - } - else - { - DECIMAL_SCALE(d) = static_cast<BYTE>(-e); - } - DECIMAL_SIGN(d) = number->sign? DECIMAL_NEG: 0; - *value = d; - return 1; -} - -#if defined(_TARGET_X86_) - -#pragma warning(disable:4035) - -unsigned int DecDivMod1E9(DECIMAL* value) -{ - LIMITED_METHOD_CONTRACT - - _asm { - mov ebx,value - mov ecx,1000000000 - xor edx,edx - mov eax,[ebx+4] - div ecx - mov [ebx+4],eax - mov eax,[ebx+12] - div ecx - mov [ebx+12],eax - mov eax,[ebx+8] - div ecx - mov [ebx+8],eax - mov eax,edx - } -} - -void DecMul10(DECIMAL* value) -{ - LIMITED_METHOD_CONTRACT - - _asm { - mov ebx,value - mov eax,[ebx+8] - mov edx,[ebx+12] - mov ecx,[ebx+4] - shl eax,1 - rcl edx,1 - rcl ecx,1 - shl eax,1 - rcl edx,1 - rcl ecx,1 - add eax,[ebx+8] - adc edx,[ebx+12] - adc ecx,[ebx+4] - shl eax,1 - rcl edx,1 - rcl ecx,1 - mov [ebx+8],eax - mov [ebx+12],edx - mov [ebx+4],ecx - } -} - -void DecAddInt32(DECIMAL* value, unsigned int i) -{ - LIMITED_METHOD_CONTRACT - - _asm { - mov edx,value - mov eax,i - add dword ptr [edx+8],eax - adc dword ptr [edx+12],0 - adc dword ptr [edx+4],0 - } -} - -#pragma warning(default:4035) - -#else // !(defined(_TARGET_X86_) - -unsigned int D32DivMod1E9(unsigned int hi32, ULONG* lo32) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(lo32 != NULL); - - unsigned __int64 n = (unsigned __int64)hi32 << 32 | *lo32; - *lo32 = (unsigned int)(n / 1000000000); - return (unsigned int)(n % 1000000000); -} - -unsigned int DecDivMod1E9(DECIMAL* value) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(value != NULL); - - return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0, - &DECIMAL_HI32(*value)), &DECIMAL_MID32(*value)), &DECIMAL_LO32(*value)); -} - -void DecShiftLeft(DECIMAL* value) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(value != NULL); - - unsigned int c0 = DECIMAL_LO32(*value) & 0x80000000? 1: 0; - unsigned int c1 = DECIMAL_MID32(*value) & 0x80000000? 1: 0; - DECIMAL_LO32(*value) <<= 1; - DECIMAL_MID32(*value) = DECIMAL_MID32(*value) << 1 | c0; - DECIMAL_HI32(*value) = DECIMAL_HI32(*value) << 1 | c1; -} - -int D32AddCarry(ULONG* value, unsigned int i) -{ - LIMITED_METHOD_CONTRACT - _ASSERTE(value != NULL); - - unsigned int v = *value; - unsigned int sum = v + i; - *value = sum; - return sum < v || sum < i? 1: 0; -} - -void DecAdd(DECIMAL* value, DECIMAL* d) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(value != NULL && d != NULL); - - if (D32AddCarry(&DECIMAL_LO32(*value), DECIMAL_LO32(*d))) { - if (D32AddCarry(&DECIMAL_MID32(*value), 1)) { - D32AddCarry(&DECIMAL_HI32(*value), 1); - } - } - if (D32AddCarry(&DECIMAL_MID32(*value), DECIMAL_MID32(*d))) { - D32AddCarry(&DECIMAL_HI32(*value), 1); - } - D32AddCarry(&DECIMAL_HI32(*value), DECIMAL_HI32(*d)); -} - -void DecMul10(DECIMAL* value) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(value != NULL); - - DECIMAL d = *value; - DecShiftLeft(value); - DecShiftLeft(value); - DecAdd(value, &d); - DecShiftLeft(value); -} - -void DecAddInt32(DECIMAL* value, unsigned int i) -{ - WRAPPER_NO_CONTRACT - _ASSERTE(value != NULL); - - if (D32AddCarry(&DECIMAL_LO32(*value), i)) { - if (D32AddCarry(&DECIMAL_MID32(*value), 1)) { - D32AddCarry(&DECIMAL_HI32(*value), 1); - } - } -} - -#endif - -/*** -* -* Decimal Code ported from OleAut32 -* -***********************************************************************/ - -// This OleAut code is only used on 64-bit and rotor platforms. It is desiriable to continue -// to call the OleAut routines in X86 because of the performance of the hand-tuned assembly -// code and because there are currently no inconsistencies in behavior accross platforms. - -#ifndef UInt32x32To64 -#define UInt32x32To64(a, b) ((DWORDLONG)((DWORD)(a)) * (DWORDLONG)((DWORD)(b))) -#endif - -typedef union { - DWORDLONG int64; - struct { -#if BIGENDIAN - ULONG Hi; - ULONG Lo; -#else - ULONG Lo; - ULONG Hi; -#endif - } u; -} SPLIT64; - -#define OVFL_MAX_1_HI 429496729 -#define DEC_SCALE_MAX 28 -#define POWER10_MAX 9 - -#define OVFL_MAX_9_HI 4u -#define OVFL_MAX_9_MID 1266874889u -#define OVFL_MAX_9_LO 3047500985u - -#define OVFL_MAX_5_HI 42949 - - -const ULONG rgulPower10[POWER10_MAX+1] = {1, 10, 100, 1000, 10000, 100000, 1000000, - 10000000, 100000000, 1000000000}; - -struct DECOVFL -{ - ULONG Hi; - ULONG Mid; - ULONG Lo; -}; - -const DECOVFL PowerOvfl[] = { -// This is a table of the largest values that can be in the upper two -// ULONGs of a 96-bit number that will not overflow when multiplied -// by a given power. For the upper word, this is a table of -// 2^32 / 10^n for 1 <= n <= 9. For the lower word, this is the -// remaining fraction part * 2^32. 2^32 = 4294967296. -// - { 429496729u, 2576980377u, 2576980377u }, // 10^1 remainder 0.6 - { 42949672u, 4123168604u, 687194767u }, // 10^2 remainder 0.16 - { 4294967u, 1271310319u, 2645699854u }, // 10^3 remainder 0.616 - { 429496u, 3133608139u, 694066715u }, // 10^4 remainder 0.1616 - { 42949u, 2890341191u, 2216890319u }, // 10^5 remainder 0.51616 - { 4294u, 4154504685u, 2369172679u }, // 10^6 remainder 0.551616 - { 429u, 2133437386u, 4102387834u }, // 10^7 remainder 0.9551616 - { 42u, 4078814305u, 410238783u }, // 10^8 remainder 0.09991616 - { 4u, 1266874889u, 3047500985u }, // 10^9 remainder 0.709551616 -}; - - -/*** -* IncreaseScale -* -* Entry: -* rgulNum - Pointer to 96-bit number as array of ULONGs, least-sig first -* ulPwr - Scale factor to multiply by -* -* Purpose: -* Multiply the two numbers. The low 96 bits of the result overwrite -* the input. The last 32 bits of the product are the return value. -* -* Exit: -* Returns highest 32 bits of product. -* -* Exceptions: -* None. -* -***********************************************************************/ - -ULONG IncreaseScale(ULONG *rgulNum, ULONG ulPwr) -{ - LIMITED_METHOD_CONTRACT; - - SPLIT64 sdlTmp; - - sdlTmp.int64 = UInt32x32To64(rgulNum[0], ulPwr); - rgulNum[0] = sdlTmp.u.Lo; - sdlTmp.int64 = UInt32x32To64(rgulNum[1], ulPwr) + sdlTmp.u.Hi; - rgulNum[1] = sdlTmp.u.Lo; - sdlTmp.int64 = UInt32x32To64(rgulNum[2], ulPwr) + sdlTmp.u.Hi; - rgulNum[2] = sdlTmp.u.Lo; - return sdlTmp.u.Hi; -} - - -/*** -* SearchScale -* -* Entry: -* ulResHi - Top ULONG of quotient -* ulResMid - Middle ULONG of quotient -* ulResLo - Bottom ULONG of quotient -* iScale - Scale factor of quotient, range -DEC_SCALE_MAX to DEC_SCALE_MAX -* -* Purpose: -* Determine the max power of 10, <= 9, that the quotient can be scaled -* up by and still fit in 96 bits. -* -* Exit: -* Returns power of 10 to scale by, -1 if overflow error. -* -***********************************************************************/ - -int SearchScale(ULONG ulResHi, ULONG ulResMid, ULONG ulResLo, int iScale) -{ - WRAPPER_NO_CONTRACT; - - int iCurScale; - - // Quick check to stop us from trying to scale any more. - // - if (ulResHi > OVFL_MAX_1_HI || iScale >= DEC_SCALE_MAX) { - iCurScale = 0; - goto HaveScale; - } - - if (iScale > DEC_SCALE_MAX - 9) { - // We can't scale by 10^9 without exceeding the max scale factor. - // See if we can scale to the max. If not, we'll fall into - // standard search for scale factor. - // - iCurScale = DEC_SCALE_MAX - iScale; - if (ulResHi < PowerOvfl[iCurScale - 1].Hi) - goto HaveScale; - - if (ulResHi == PowerOvfl[iCurScale - 1].Hi) { - UpperEq: - if (ulResMid > PowerOvfl[iCurScale - 1].Mid || - (ulResMid == PowerOvfl[iCurScale - 1].Mid && ulResLo > PowerOvfl[iCurScale - 1].Lo)) { - iCurScale--; - } - goto HaveScale; - } - } - else if (ulResHi < OVFL_MAX_9_HI || (ulResHi == OVFL_MAX_9_HI && - ulResMid < OVFL_MAX_9_MID) || (ulResHi == OVFL_MAX_9_HI && ulResMid == OVFL_MAX_9_MID && ulResLo <= OVFL_MAX_9_LO)) - return 9; - - // Search for a power to scale by < 9. Do a binary search - // on PowerOvfl[]. - // - iCurScale = 5; - if (ulResHi < OVFL_MAX_5_HI) - iCurScale = 7; - else if (ulResHi > OVFL_MAX_5_HI) - iCurScale = 3; - else - goto UpperEq; - - // iCurScale is 3 or 7. - // - if (ulResHi < PowerOvfl[iCurScale - 1].Hi) - iCurScale++; - else if (ulResHi > PowerOvfl[iCurScale - 1].Hi) - iCurScale--; - else - goto UpperEq; - - // iCurScale is 2, 4, 6, or 8. - // - // In all cases, we already found we could not use the power one larger. - // So if we can use this power, it is the biggest, and we're done. If - // we can't use this power, the one below it is correct for all cases - // unless it's 10^1 -- we might have to go to 10^0 (no scaling). - // - if (ulResHi > PowerOvfl[iCurScale - 1].Hi) - iCurScale--; - - if (ulResHi == PowerOvfl[iCurScale - 1].Hi) - goto UpperEq; - -HaveScale: - // iCurScale = largest power of 10 we can scale by without overflow, - // iCurScale < 9. See if this is enough to make scale factor - // positive if it isn't already. - // - if (iCurScale + iScale < 0) - iCurScale = -1; - - return iCurScale; -} - -//*********************************************************************** -// -// Arithmetic Inlines -// - -#define Div64by32(num, den) ((ULONG)((DWORDLONG)(num) / (ULONG)(den))) -#define Mod64by32(num, den) ((ULONG)((DWORDLONG)(num) % (ULONG)(den))) - -inline DWORDLONG DivMod64by32(DWORDLONG num, ULONG den) -{ - WRAPPER_NO_CONTRACT; - - SPLIT64 sdl; - - sdl.u.Lo = Div64by32(num, den); - sdl.u.Hi = Mod64by32(num, den); - return sdl.int64; -} - -/*** -* Div128By96 -* -* Entry: -* rgulNum - Pointer to 128-bit dividend as array of ULONGs, least-sig first -* rgulDen - Pointer to 96-bit divisor. -* -* Purpose: -* Do partial divide, yielding 32-bit result and 96-bit remainder. -* Top divisor ULONG must be larger than top dividend ULONG. This is -* assured in the initial call because the divisor is normalized -* and the dividend can't be. In subsequent calls, the remainder -* is multiplied by 10^9 (max), so it can be no more than 1/4 of -* the divisor which is effectively multiplied by 2^32 (4 * 10^9). -* -* Exit: -* Remainder overwrites lower 96-bits of dividend. -* Returns quotient. -* -* Exceptions: -* None. -* -***********************************************************************/ - -ULONG Div128By96(ULONG *rgulNum, ULONG *rgulDen) -{ - LIMITED_METHOD_CONTRACT; - - SPLIT64 sdlQuo; - SPLIT64 sdlNum; - SPLIT64 sdlProd1; - SPLIT64 sdlProd2; - - sdlNum.u.Lo = rgulNum[0]; - sdlNum.u.Hi = rgulNum[1]; - - if (rgulNum[3] == 0 && rgulNum[2] < rgulDen[2]) - // Result is zero. Entire dividend is remainder. - // - return 0; - - // DivMod64by32 returns quotient in Lo, remainder in Hi. - // - sdlQuo.u.Lo = rgulNum[2]; - sdlQuo.u.Hi = rgulNum[3]; - sdlQuo.int64 = DivMod64by32(sdlQuo.int64, rgulDen[2]); - - // Compute full remainder, rem = dividend - (quo * divisor). - // - sdlProd1.int64 = UInt32x32To64(sdlQuo.u.Lo, rgulDen[0]); // quo * lo divisor - sdlProd2.int64 = UInt32x32To64(sdlQuo.u.Lo, rgulDen[1]); // quo * mid divisor - sdlProd2.int64 += sdlProd1.u.Hi; - sdlProd1.u.Hi = sdlProd2.u.Lo; - - sdlNum.int64 -= sdlProd1.int64; - rgulNum[2] = sdlQuo.u.Hi - sdlProd2.u.Hi; // sdlQuo.Hi is remainder - - // Propagate carries - // - if (sdlNum.int64 > ~sdlProd1.int64) { - rgulNum[2]--; - if (rgulNum[2] >= ~sdlProd2.u.Hi) - goto NegRem; - } - else if (rgulNum[2] > ~sdlProd2.u.Hi) { -NegRem: - // Remainder went negative. Add divisor back in until it's positive, - // a max of 2 times. - // - sdlProd1.u.Lo = rgulDen[0]; - sdlProd1.u.Hi = rgulDen[1]; - - for (;;) { - sdlQuo.u.Lo--; - sdlNum.int64 += sdlProd1.int64; - rgulNum[2] += rgulDen[2]; - - if (sdlNum.int64 < sdlProd1.int64) { - // Detected carry. Check for carry out of top - // before adding it in. - // - if (rgulNum[2]++ < rgulDen[2]) - break; - } - if (rgulNum[2] < rgulDen[2]) - break; // detected carry - } - } - - rgulNum[0] = sdlNum.u.Lo; - rgulNum[1] = sdlNum.u.Hi; - return sdlQuo.u.Lo; -} - - - -/*** -* Div96By32 -* -* Entry: -* rgulNum - Pointer to 96-bit dividend as array of ULONGs, least-sig first -* ulDen - 32-bit divisor. -* -* Purpose: -* Do full divide, yielding 96-bit result and 32-bit remainder. -* -* Exit: -* Quotient overwrites dividend. -* Returns remainder. -* -* Exceptions: -* None. -* -***********************************************************************/ - -ULONG Div96By32(ULONG *rgulNum, ULONG ulDen) -{ - LIMITED_METHOD_CONTRACT; - - SPLIT64 sdlTmp; - - sdlTmp.u.Hi = 0; - - if (rgulNum[2] != 0) - goto Div3Word; - - if (rgulNum[1] >= ulDen) - goto Div2Word; - - sdlTmp.u.Hi = rgulNum[1]; - rgulNum[1] = 0; - goto Div1Word; - -Div3Word: - sdlTmp.u.Lo = rgulNum[2]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen); - rgulNum[2] = sdlTmp.u.Lo; -Div2Word: - sdlTmp.u.Lo = rgulNum[1]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen); - rgulNum[1] = sdlTmp.u.Lo; -Div1Word: - sdlTmp.u.Lo = rgulNum[0]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen); - rgulNum[0] = sdlTmp.u.Lo; - return sdlTmp.u.Hi; -} - - -/*** -* Div96By64 -* -* Entry: -* rgulNum - Pointer to 96-bit dividend as array of ULONGs, least-sig first -* sdlDen - 64-bit divisor. -* -* Purpose: -* Do partial divide, yielding 32-bit result and 64-bit remainder. -* Divisor must be larger than upper 64 bits of dividend. -* -* Exit: -* Remainder overwrites lower 64-bits of dividend. -* Returns quotient. -* -* Exceptions: -* None. -* -***********************************************************************/ - -ULONG Div96By64(ULONG *rgulNum, SPLIT64 sdlDen) -{ - LIMITED_METHOD_CONTRACT; - - SPLIT64 sdlQuo; - SPLIT64 sdlNum; - SPLIT64 sdlProd; - - sdlNum.u.Lo = rgulNum[0]; - - if (rgulNum[2] >= sdlDen.u.Hi) { - // Divide would overflow. Assume a quotient of 2^32, and set - // up remainder accordingly. Then jump to loop which reduces - // the quotient. - // - sdlNum.u.Hi = rgulNum[1] - sdlDen.u.Lo; - sdlQuo.u.Lo = 0; - goto NegRem; - } - - // Hardware divide won't overflow - // - if (rgulNum[2] == 0 && rgulNum[1] < sdlDen.u.Hi) - // Result is zero. Entire dividend is remainder. - // - return 0; - - // DivMod64by32 returns quotient in Lo, remainder in Hi. - // - sdlQuo.u.Lo = rgulNum[1]; - sdlQuo.u.Hi = rgulNum[2]; - sdlQuo.int64 = DivMod64by32(sdlQuo.int64, sdlDen.u.Hi); - sdlNum.u.Hi = sdlQuo.u.Hi; // remainder - - // Compute full remainder, rem = dividend - (quo * divisor). - // - sdlProd.int64 = UInt32x32To64(sdlQuo.u.Lo, sdlDen.u.Lo); // quo * lo divisor - sdlNum.int64 -= sdlProd.int64; - - if (sdlNum.int64 > ~sdlProd.int64) { -NegRem: - // Remainder went negative. Add divisor back in until it's positive, - // a max of 2 times. - // - do { - sdlQuo.u.Lo--; - sdlNum.int64 += sdlDen.int64; - }while (sdlNum.int64 >= sdlDen.int64); - } - - rgulNum[0] = sdlNum.u.Lo; - rgulNum[1] = sdlNum.u.Hi; - return sdlQuo.u.Lo; -} - -// Add a 32 bit unsigned long to an array of 3 unsigned longs representing a 96 integer -// Returns FALSE if there is an overflow -BOOL Add32To96(ULONG *rgulNum, ULONG ulValue) { - rgulNum[0] += ulValue; - if (rgulNum[0] < ulValue) { - if (++rgulNum[1] == 0) { - if (++rgulNum[2] == 0) { - return FALSE; - } - } - } - return TRUE; -} - -// Adjust the quotient to deal with an overflow. We need to divide by 10, -// feed in the high bit to undo the overflow and then round as required, -void OverflowUnscale(ULONG *rgulQuo, BOOL fRemainder) { - LIMITED_METHOD_CONTRACT; - - SPLIT64 sdlTmp; - - // We have overflown, so load the high bit with a one. - sdlTmp.u.Hi = 1u; - sdlTmp.u.Lo = rgulQuo[2]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u); - rgulQuo[2] = sdlTmp.u.Lo; - sdlTmp.u.Lo = rgulQuo[1]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u); - rgulQuo[1] = sdlTmp.u.Lo; - sdlTmp.u.Lo = rgulQuo[0]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10u); - rgulQuo[0] = sdlTmp.u.Lo; - // The remainder is the last digit that does not fit, so we can use it to work out if we need to round up - if ((sdlTmp.u.Hi > 5) || ((sdlTmp.u.Hi == 5) && ( fRemainder || (rgulQuo[0] & 1)))) { - Add32To96(rgulQuo, 1u); - } -} - - - -//********************************************************************** -// -// VarDecDiv - Decimal Divide -// -//********************************************************************** - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif - -FCIMPL2(void, COMDecimal::DoDivideThrow, DECIMAL * pdecL, DECIMAL * pdecR) -{ - FCALL_CONTRACT; - - ULONG rgulQuo[3]; - ULONG rgulQuoSave[3]; - ULONG rgulRem[4]; - ULONG rgulDivisor[3]; - ULONG ulPwr; - ULONG ulTmp; - ULONG ulTmp1; - SPLIT64 sdlTmp; - SPLIT64 sdlDivisor; - int iScale; - int iCurScale; - BOOL fUnscale; - - iScale = DECIMAL_SCALE(*pdecL) - DECIMAL_SCALE(*pdecR); - fUnscale = FALSE; - rgulDivisor[0] = DECIMAL_LO32(*pdecR); - rgulDivisor[1] = DECIMAL_MID32(*pdecR); - rgulDivisor[2] = DECIMAL_HI32(*pdecR); - - if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) { - // Divisor is only 32 bits. Easy divide. - // - if (rgulDivisor[0] == 0) - FCThrowVoid(kDivideByZeroException); - - rgulQuo[0] = DECIMAL_LO32(*pdecL); - rgulQuo[1] = DECIMAL_MID32(*pdecL); - rgulQuo[2] = DECIMAL_HI32(*pdecL); - rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]); - - for (;;) { - if (rgulRem[0] == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale; - } - break; - } - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // We have computed a quotient based on the natural scale - // ( <dividend scale> - <divisor scale> ). We have a non-zero - // remainder, so now we should increase the scale if possible to - // include more quotient bits. - // - // If it doesn't cause overflow, we'll loop scaling by 10^9 and - // computing more quotient bits as long as the remainder stays - // non-zero. If scaling by that much would cause overflow, we'll - // drop out of the loop and scale by as much as we can. - // - // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9 - // = 4.294 967 296. So the upper limit is rgulQuo[2] == 4 and - // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+. Since - // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888 - // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is - // assured not to overflow. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - ulTmp = rgulRem[0] << 1; - if (ulTmp < rgulRem[0] || (ulTmp >= rgulDivisor[0] && - (ulTmp > rgulDivisor[0] || (rgulQuo[0] & 1)))) { -RoundUp: - if (!Add32To96(rgulQuo, 1)) { - if (iScale == 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - iScale--; - OverflowUnscale(rgulQuo, TRUE); - break; - } - } - break; - } - - if (iCurScale < 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - -HaveScale: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - - - sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]); - rgulRem[0] = sdlTmp.u.Hi; - - if (!Add32To96(rgulQuo, sdlTmp.u.Lo)) { - if (iScale == 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0)); - break; - } - } // for (;;) - } - else { - // Divisor has bits set in the upper 64 bits. - // - // Divisor must be fully normalized (shifted so bit 31 of the most - // significant ULONG is 1). Locate the MSB so we know how much to - // normalize by. The dividend will be shifted by the same amount so - // the quotient is not changed. - // - if (rgulDivisor[2] == 0) - ulTmp = rgulDivisor[1]; - else - ulTmp = rgulDivisor[2]; - - iCurScale = 0; - if (!(ulTmp & 0xFFFF0000)) { - iCurScale += 16; - ulTmp <<= 16; - } - if (!(ulTmp & 0xFF000000)) { - iCurScale += 8; - ulTmp <<= 8; - } - if (!(ulTmp & 0xF0000000)) { - iCurScale += 4; - ulTmp <<= 4; - } - if (!(ulTmp & 0xC0000000)) { - iCurScale += 2; - ulTmp <<= 2; - } - if (!(ulTmp & 0x80000000)) { - iCurScale++; - ulTmp <<= 1; - } - - // Shift both dividend and divisor left by iCurScale. - // - sdlTmp.int64 = DECIMAL_LO64_GET(*pdecL) << iCurScale; - rgulRem[0] = sdlTmp.u.Lo; - rgulRem[1] = sdlTmp.u.Hi; - sdlTmp.u.Lo = DECIMAL_MID32(*pdecL); - sdlTmp.u.Hi = DECIMAL_HI32(*pdecL); - sdlTmp.int64 <<= iCurScale; - rgulRem[2] = sdlTmp.u.Hi; - rgulRem[3] = (DECIMAL_HI32(*pdecL) >> (31 - iCurScale)) >> 1; - - sdlDivisor.u.Lo = rgulDivisor[0]; - sdlDivisor.u.Hi = rgulDivisor[1]; - sdlDivisor.int64 <<= iCurScale; - - if (rgulDivisor[2] == 0) { - // Have a 64-bit divisor in sdlDivisor. The remainder - // (currently 96 bits spread over 4 ULONGs) will be < divisor. - // - sdlTmp.u.Lo = rgulRem[2]; - sdlTmp.u.Hi = rgulRem[3]; - - rgulQuo[2] = 0; - rgulQuo[1] = Div96By64(&rgulRem[1], sdlDivisor); - rgulQuo[0] = Div96By64(rgulRem, sdlDivisor); - - for (;;) { - if ((rgulRem[0] | rgulRem[1]) == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale64; - } - break; - } - - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // Remainder is non-zero. Scale up quotient and remainder by - // powers of 10 so we can compute more significant bits. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - sdlTmp.u.Lo = rgulRem[0]; - sdlTmp.u.Hi = rgulRem[1]; - if (sdlTmp.u.Hi >= 0x80000000 || (sdlTmp.int64 <<= 1) > sdlDivisor.int64 || - (sdlTmp.int64 == sdlDivisor.int64 && (rgulQuo[0] & 1))) - goto RoundUp; - break; - } - - if (iCurScale < 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - -HaveScale64: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - - - rgulRem[2] = 0; // rem is 64 bits, IncreaseScale uses 96 - IncreaseScale(rgulRem, ulPwr); - ulTmp = Div96By64(rgulRem, sdlDivisor); - if (!Add32To96(rgulQuo, ulTmp)) { - if (iScale == 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0)); - break; - } - - } // for (;;) - } - else { - // Have a 96-bit divisor in rgulDivisor[]. - // - // Start by finishing the shift left by iCurScale. - // - sdlTmp.u.Lo = rgulDivisor[1]; - sdlTmp.u.Hi = rgulDivisor[2]; - sdlTmp.int64 <<= iCurScale; - rgulDivisor[0] = sdlDivisor.u.Lo; - rgulDivisor[1] = sdlDivisor.u.Hi; - rgulDivisor[2] = sdlTmp.u.Hi; - - // The remainder (currently 96 bits spread over 4 ULONGs) - // will be < divisor. - // - rgulQuo[2] = 0; - rgulQuo[1] = 0; - rgulQuo[0] = Div128By96(rgulRem, rgulDivisor); - - for (;;) { - if ((rgulRem[0] | rgulRem[1] | rgulRem[2]) == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale96; - } - break; - } - - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // Remainder is non-zero. Scale up quotient and remainder by - // powers of 10 so we can compute more significant bits. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - if (rgulRem[2] >= 0x80000000) - goto RoundUp; - - ulTmp = rgulRem[0] > 0x80000000; - ulTmp1 = rgulRem[1] > 0x80000000; - rgulRem[0] <<= 1; - rgulRem[1] = (rgulRem[1] << 1) + ulTmp; - rgulRem[2] = (rgulRem[2] << 1) + ulTmp1; - - if (rgulRem[2] > rgulDivisor[2] || (rgulRem[2] == rgulDivisor[2] && - (rgulRem[1] > rgulDivisor[1] || (rgulRem[1] == rgulDivisor[1] && - (rgulRem[0] > rgulDivisor[0] || (rgulRem[0] == rgulDivisor[0] && - (rgulQuo[0] & 1))))))) - goto RoundUp; - break; - } - - if (iCurScale < 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - -HaveScale96: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - - rgulRem[3] = IncreaseScale(rgulRem, ulPwr); - ulTmp = Div128By96(rgulRem, rgulDivisor); - if (!Add32To96(rgulQuo, ulTmp)) { - if (iScale == 0) { - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0 || rgulRem[2] != 0 || rgulRem[3] != 0)); - break; - } - - } // for (;;) - } - } - - // We need to unscale if and only if we have a non-zero remainder - if (fUnscale) { - // Try extracting any extra powers of 10 we may have - // added. We do this by trying to divide out 10^8, 10^4, 10^2, and 10^1. - // If a division by one of these powers returns a zero remainder, then - // we keep the quotient. If the remainder is not zero, then we restore - // the previous value. - // - // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 - // we can extract. We use this as a quick test on whether to try a - // given power. - // - while ((rgulQuo[0] & 0xFF) == 0 && iScale >= 8) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 100000000) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 8; - } - else - break; - } - - if ((rgulQuo[0] & 0xF) == 0 && iScale >= 4) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 10000) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 4; - } - } - - if ((rgulQuo[0] & 3) == 0 && iScale >= 2) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 100) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 2; - } - } - - if ((rgulQuo[0] & 1) == 0 && iScale >= 1) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 10) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 1; - } - } - } - - DECIMAL_SIGN(*pdecL) = DECIMAL_SIGN(*pdecL) ^ DECIMAL_SIGN(*pdecR); - DECIMAL_HI32(*pdecL) = rgulQuo[2]; - DECIMAL_MID32(*pdecL) = rgulQuo[1]; - DECIMAL_LO32(*pdecL) = rgulQuo[0]; - DECIMAL_SCALE(*pdecL) = (BYTE)iScale; - - pdecL->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - - -FCIMPL3(void, COMDecimal::DoDivide, DECIMAL * pdecL, DECIMAL * pdecR, CLR_BOOL * overflowed) -{ - FCALL_CONTRACT; - - ULONG rgulQuo[3]; - ULONG rgulQuoSave[3]; - ULONG rgulRem[4]; - ULONG rgulDivisor[3]; - ULONG ulPwr; - ULONG ulTmp; - ULONG ulTmp1; - SPLIT64 sdlTmp; - SPLIT64 sdlDivisor; - int iScale; - int iCurScale; - BOOL fUnscale; - - iScale = DECIMAL_SCALE(*pdecL) - DECIMAL_SCALE(*pdecR); - fUnscale = FALSE; - rgulDivisor[0] = DECIMAL_LO32(*pdecR); - rgulDivisor[1] = DECIMAL_MID32(*pdecR); - rgulDivisor[2] = DECIMAL_HI32(*pdecR); - - if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) { - // Divisor is only 32 bits. Easy divide. - // - if (rgulDivisor[0] == 0) - FCThrowVoid(kDivideByZeroException); - - rgulQuo[0] = DECIMAL_LO32(*pdecL); - rgulQuo[1] = DECIMAL_MID32(*pdecL); - rgulQuo[2] = DECIMAL_HI32(*pdecL); - rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]); - - for (;;) { - if (rgulRem[0] == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale; - } - break; - } - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // We have computed a quotient based on the natural scale - // ( <dividend scale> - <divisor scale> ). We have a non-zero - // remainder, so now we should increase the scale if possible to - // include more quotient bits. - // - // If it doesn't cause overflow, we'll loop scaling by 10^9 and - // computing more quotient bits as long as the remainder stays - // non-zero. If scaling by that much would cause overflow, we'll - // drop out of the loop and scale by as much as we can. - // - // Scaling by 10^9 will overflow if rgulQuo[2].rgulQuo[1] >= 2^32 / 10^9 - // = 4.294 967 296. So the upper limit is rgulQuo[2] == 4 and - // rgulQuo[1] == 0.294 967 296 * 2^32 = 1,266,874,889.7+. Since - // quotient bits in rgulQuo[0] could be all 1's, then 1,266,874,888 - // is the largest value in rgulQuo[1] (when rgulQuo[2] == 4) that is - // assured not to overflow. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - ulTmp = rgulRem[0] << 1; - if (ulTmp < rgulRem[0] || (ulTmp >= rgulDivisor[0] && - (ulTmp > rgulDivisor[0] || (rgulQuo[0] & 1)))) { -RoundUp: - if (!Add32To96(rgulQuo, 1)) { - if (iScale == 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - iScale--; - OverflowUnscale(rgulQuo, TRUE); - break; - } - } - break; - } - - if (iCurScale < 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - -HaveScale: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - - - sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]); - rgulRem[0] = sdlTmp.u.Hi; - - if (!Add32To96(rgulQuo, sdlTmp.u.Lo)) { - if (iScale == 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0)); - break; - } - } // for (;;) - } - else { - // Divisor has bits set in the upper 64 bits. - // - // Divisor must be fully normalized (shifted so bit 31 of the most - // significant ULONG is 1). Locate the MSB so we know how much to - // normalize by. The dividend will be shifted by the same amount so - // the quotient is not changed. - // - if (rgulDivisor[2] == 0) - ulTmp = rgulDivisor[1]; - else - ulTmp = rgulDivisor[2]; - - iCurScale = 0; - if (!(ulTmp & 0xFFFF0000)) { - iCurScale += 16; - ulTmp <<= 16; - } - if (!(ulTmp & 0xFF000000)) { - iCurScale += 8; - ulTmp <<= 8; - } - if (!(ulTmp & 0xF0000000)) { - iCurScale += 4; - ulTmp <<= 4; - } - if (!(ulTmp & 0xC0000000)) { - iCurScale += 2; - ulTmp <<= 2; - } - if (!(ulTmp & 0x80000000)) { - iCurScale++; - ulTmp <<= 1; - } - - // Shift both dividend and divisor left by iCurScale. - // - sdlTmp.int64 = DECIMAL_LO64_GET(*pdecL) << iCurScale; - rgulRem[0] = sdlTmp.u.Lo; - rgulRem[1] = sdlTmp.u.Hi; - sdlTmp.u.Lo = DECIMAL_MID32(*pdecL); - sdlTmp.u.Hi = DECIMAL_HI32(*pdecL); - sdlTmp.int64 <<= iCurScale; - rgulRem[2] = sdlTmp.u.Hi; - rgulRem[3] = (DECIMAL_HI32(*pdecL) >> (31 - iCurScale)) >> 1; - - sdlDivisor.u.Lo = rgulDivisor[0]; - sdlDivisor.u.Hi = rgulDivisor[1]; - sdlDivisor.int64 <<= iCurScale; - - if (rgulDivisor[2] == 0) { - // Have a 64-bit divisor in sdlDivisor. The remainder - // (currently 96 bits spread over 4 ULONGs) will be < divisor. - // - sdlTmp.u.Lo = rgulRem[2]; - sdlTmp.u.Hi = rgulRem[3]; - - rgulQuo[2] = 0; - rgulQuo[1] = Div96By64(&rgulRem[1], sdlDivisor); - rgulQuo[0] = Div96By64(rgulRem, sdlDivisor); - - for (;;) { - if ((rgulRem[0] | rgulRem[1]) == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale64; - } - break; - } - - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // Remainder is non-zero. Scale up quotient and remainder by - // powers of 10 so we can compute more significant bits. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - sdlTmp.u.Lo = rgulRem[0]; - sdlTmp.u.Hi = rgulRem[1]; - if (sdlTmp.u.Hi >= 0x80000000 || (sdlTmp.int64 <<= 1) > sdlDivisor.int64 || - (sdlTmp.int64 == sdlDivisor.int64 && (rgulQuo[0] & 1))) - goto RoundUp; - break; - } - - if (iCurScale < 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - -HaveScale64: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - - - rgulRem[2] = 0; // rem is 64 bits, IncreaseScale uses 96 - IncreaseScale(rgulRem, ulPwr); - ulTmp = Div96By64(rgulRem, sdlDivisor); - if (!Add32To96(rgulQuo, ulTmp)) { - if (iScale == 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0)); - break; - } - - } // for (;;) - } - else { - // Have a 96-bit divisor in rgulDivisor[]. - // - // Start by finishing the shift left by iCurScale. - // - sdlTmp.u.Lo = rgulDivisor[1]; - sdlTmp.u.Hi = rgulDivisor[2]; - sdlTmp.int64 <<= iCurScale; - rgulDivisor[0] = sdlDivisor.u.Lo; - rgulDivisor[1] = sdlDivisor.u.Hi; - rgulDivisor[2] = sdlTmp.u.Hi; - - // The remainder (currently 96 bits spread over 4 ULONGs) - // will be < divisor. - // - rgulQuo[2] = 0; - rgulQuo[1] = 0; - rgulQuo[0] = Div128By96(rgulRem, rgulDivisor); - - for (;;) { - if ((rgulRem[0] | rgulRem[1] | rgulRem[2]) == 0) { - if (iScale < 0) { - iCurScale = min(9, -iScale); - goto HaveScale96; - } - break; - } - - // We need to unscale if and only if we have a non-zero remainder - fUnscale = TRUE; - - // Remainder is non-zero. Scale up quotient and remainder by - // powers of 10 so we can compute more significant bits. - // - iCurScale = SearchScale(rgulQuo[2], rgulQuo[1], rgulQuo[0], iScale); - if (iCurScale == 0) { - // No more scaling to be done, but remainder is non-zero. - // Round quotient. - // - if (rgulRem[2] >= 0x80000000) - goto RoundUp; - - ulTmp = rgulRem[0] > 0x80000000; - ulTmp1 = rgulRem[1] > 0x80000000; - rgulRem[0] <<= 1; - rgulRem[1] = (rgulRem[1] << 1) + ulTmp; - rgulRem[2] = (rgulRem[2] << 1) + ulTmp1; - - if (rgulRem[2] > rgulDivisor[2] || (rgulRem[2] == rgulDivisor[2] && - (rgulRem[1] > rgulDivisor[1] || (rgulRem[1] == rgulDivisor[1] && - (rgulRem[0] > rgulDivisor[0] || (rgulRem[0] == rgulDivisor[0] && - (rgulQuo[0] & 1))))))) - goto RoundUp; - break; - } - - if (iCurScale < 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - -HaveScale96: - ulPwr = rgulPower10[iCurScale]; - iScale += iCurScale; - - if (IncreaseScale(rgulQuo, ulPwr) != 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - - rgulRem[3] = IncreaseScale(rgulRem, ulPwr); - ulTmp = Div128By96(rgulRem, rgulDivisor); - if (!Add32To96(rgulQuo, ulTmp)) { - if (iScale == 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - iScale--; - OverflowUnscale(rgulQuo, (rgulRem[0] != 0 || rgulRem[1] != 0 || rgulRem[2] != 0 || rgulRem[3] != 0)); - break; - } - - } // for (;;) - } - } - - // We need to unscale if and only if we have a non-zero remainder - if (fUnscale) { - // Try extracting any extra powers of 10 we may have - // added. We do this by trying to divide out 10^8, 10^4, 10^2, and 10^1. - // If a division by one of these powers returns a zero remainder, then - // we keep the quotient. If the remainder is not zero, then we restore - // the previous value. - // - // Since 10 = 2 * 5, there must be a factor of 2 for every power of 10 - // we can extract. We use this as a quick test on whether to try a - // given power. - // - while ((rgulQuo[0] & 0xFF) == 0 && iScale >= 8) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 100000000) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 8; - } - else - break; - } - - if ((rgulQuo[0] & 0xF) == 0 && iScale >= 4) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 10000) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 4; - } - } - - if ((rgulQuo[0] & 3) == 0 && iScale >= 2) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 100) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 2; - } - } - - if ((rgulQuo[0] & 1) == 0 && iScale >= 1) { - rgulQuoSave[0] = rgulQuo[0]; - rgulQuoSave[1] = rgulQuo[1]; - rgulQuoSave[2] = rgulQuo[2]; - - if (Div96By32(rgulQuoSave, 10) == 0) { - rgulQuo[0] = rgulQuoSave[0]; - rgulQuo[1] = rgulQuoSave[1]; - rgulQuo[2] = rgulQuoSave[2]; - iScale -= 1; - } - } - } - - DECIMAL_SIGN(*pdecL) = DECIMAL_SIGN(*pdecL) ^ DECIMAL_SIGN(*pdecR); - DECIMAL_HI32(*pdecL) = rgulQuo[2]; - DECIMAL_MID32(*pdecL) = rgulQuo[1]; - DECIMAL_LO32(*pdecL) = rgulQuo[0]; - DECIMAL_SCALE(*pdecL) = (BYTE)iScale; - - pdecL->wReserved = 0; - *overflowed = false; - FC_GC_POLL(); -} -FCIMPLEND - -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - - -//********************************************************************** -// -// VarDecAdd - Decimal Addition -// VarDecSub - Decimal Subtraction -// -//********************************************************************** - -static const ULONG ulTenToNine = 1000000000; - -/*** -* ScaleResult -* -* Entry: -* rgulRes - Array of ULONGs with value, least-significant first. -* iHiRes - Index of last non-zero value in rgulRes. -* iScale - Scale factor for this value, range 0 - 2 * DEC_SCALE_MAX -* -* Purpose: -* See if we need to scale the result to fit it in 96 bits. -* Perform needed scaling. Adjust scale factor accordingly. -* -* Exit: -* rgulRes updated in place, always 3 ULONGs. -* New scale factor returned, -1 if overflow error. -* -***********************************************************************/ - -int ScaleResult(ULONG *rgulRes, int iHiRes, int iScale) -{ - LIMITED_METHOD_CONTRACT; - - int iNewScale; - int iCur; - ULONG ulPwr; - ULONG ulTmp; - ULONG ulSticky; - SPLIT64 sdlTmp; - - // See if we need to scale the result. The combined scale must - // be <= DEC_SCALE_MAX and the upper 96 bits must be zero. - // - // Start by figuring a lower bound on the scaling needed to make - // the upper 96 bits zero. iHiRes is the index into rgulRes[] - // of the highest non-zero ULONG. - // - iNewScale = iHiRes * 32 - 64 - 1; - if (iNewScale > 0) { - - // Find the MSB. - // - ulTmp = rgulRes[iHiRes]; - if (!(ulTmp & 0xFFFF0000)) { - iNewScale -= 16; - ulTmp <<= 16; - } - if (!(ulTmp & 0xFF000000)) { - iNewScale -= 8; - ulTmp <<= 8; - } - if (!(ulTmp & 0xF0000000)) { - iNewScale -= 4; - ulTmp <<= 4; - } - if (!(ulTmp & 0xC0000000)) { - iNewScale -= 2; - ulTmp <<= 2; - } - if (!(ulTmp & 0x80000000)) { - iNewScale--; - ulTmp <<= 1; - } - - // Multiply bit position by log10(2) to figure it's power of 10. - // We scale the log by 256. log(2) = .30103, * 256 = 77. Doing this - // with a multiply saves a 96-byte lookup table. The power returned - // is <= the power of the number, so we must add one power of 10 - // to make it's integer part zero after dividing by 256. - // - // Note: the result of this multiplication by an approximation of - // log10(2) have been exhaustively checked to verify it gives the - // correct result. (There were only 95 to check...) - // - iNewScale = ((iNewScale * 77) >> 8) + 1; - - // iNewScale = min scale factor to make high 96 bits zero, 0 - 29. - // This reduces the scale factor of the result. If it exceeds the - // current scale of the result, we'll overflow. - // - if (iNewScale > iScale) - return -1; - } - else - iNewScale = 0; - - // Make sure we scale by enough to bring the current scale factor - // into valid range. - // - if (iNewScale < iScale - DEC_SCALE_MAX) - iNewScale = iScale - DEC_SCALE_MAX; - - if (iNewScale != 0) { - // Scale by the power of 10 given by iNewScale. Note that this is - // NOT guaranteed to bring the number within 96 bits -- it could - // be 1 power of 10 short. - // - iScale -= iNewScale; - ulSticky = 0; - sdlTmp.u.Hi = 0; // initialize remainder - - for (;;) { - - ulSticky |= sdlTmp.u.Hi; // record remainder as sticky bit - - if (iNewScale > POWER10_MAX) - ulPwr = ulTenToNine; - else - ulPwr = rgulPower10[iNewScale]; - - // Compute first quotient. - // DivMod64by32 returns quotient in Lo, remainder in Hi. - // - sdlTmp.int64 = DivMod64by32(rgulRes[iHiRes], ulPwr); - rgulRes[iHiRes] = sdlTmp.u.Lo; - iCur = iHiRes - 1; - - if (iCur >= 0) { - // If first quotient was 0, update iHiRes. - // - if (sdlTmp.u.Lo == 0) - iHiRes--; - - // Compute subsequent quotients. - // - do { - sdlTmp.u.Lo = rgulRes[iCur]; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr); - rgulRes[iCur] = sdlTmp.u.Lo; - iCur--; - } while (iCur >= 0); - - } - - iNewScale -= POWER10_MAX; - if (iNewScale > 0) - continue; // scale some more - - // If we scaled enough, iHiRes would be 2 or less. If not, - // divide by 10 more. - // - if (iHiRes > 2) { - iNewScale = 1; - iScale--; - continue; // scale by 10 - } - - // Round final result. See if remainder >= 1/2 of divisor. - // If remainder == 1/2 divisor, round up if odd or sticky bit set. - // - ulPwr >>= 1; // power of 10 always even - if ( ulPwr <= sdlTmp.u.Hi && (ulPwr < sdlTmp.u.Hi || - ((rgulRes[0] & 1) | ulSticky)) ) { - iCur = -1; - while (++rgulRes[++iCur] == 0); - - if (iCur > 2) { - // The rounding caused us to carry beyond 96 bits. - // Scale by 10 more. - // - iHiRes = iCur; - ulSticky = 0; // no sticky bit - sdlTmp.u.Hi = 0; // or remainder - iNewScale = 1; - iScale--; - continue; // scale by 10 - } - } - - // We may have scaled it more than we planned. Make sure the scale - // factor hasn't gone negative, indicating overflow. - // - if (iScale < 0) - return -1; - - return iScale; - } // for(;;) - } - return iScale; -} - -FCIMPL3(void, COMDecimal::DoAddSubThrow, DECIMAL * pdecL, DECIMAL * pdecR, UINT8 bSign) -{ - FCALL_CONTRACT; - - ULONG rgulNum[6]; - ULONG ulPwr; - int iScale; - int iHiProd; - int iCur; - SPLIT64 sdlTmp; - DECIMAL decRes; - DECIMAL decTmp; - LPDECIMAL pdecTmp; - LPDECIMAL pdecLOriginal; - - _ASSERTE(bSign == 0 || bSign == DECIMAL_NEG); - - pdecLOriginal = pdecL; - - bSign ^= (DECIMAL_SIGN(*pdecR) ^ DECIMAL_SIGN(*pdecL)) & DECIMAL_NEG; - - if (DECIMAL_SCALE(*pdecR) == DECIMAL_SCALE(*pdecL)) { - // Scale factors are equal, no alignment necessary. - // - DECIMAL_SIGNSCALE(decRes) = DECIMAL_SIGNSCALE(*pdecL); - -AlignedAdd: - if (bSign) { - // Signs differ - subtract - // - DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) - DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) - DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) > DECIMAL_LO64_GET(*pdecL)) { - DECIMAL_HI32(decRes)--; - if (DECIMAL_HI32(decRes) >= DECIMAL_HI32(*pdecL)) - goto SignFlip; - } - else if (DECIMAL_HI32(decRes) > DECIMAL_HI32(*pdecL)) { - // Got negative result. Flip its sign. - // -SignFlip: - DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes)); - DECIMAL_HI32(decRes) = ~DECIMAL_HI32(decRes); - if (DECIMAL_LO64_GET(decRes) == 0) - DECIMAL_HI32(decRes)++; - DECIMAL_SIGN(decRes) ^= DECIMAL_NEG; - } - - } - else { - // Signs are the same - add - // - DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) + DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) { - DECIMAL_HI32(decRes)++; - if (DECIMAL_HI32(decRes) <= DECIMAL_HI32(*pdecL)) - goto AlignedScale; - } - else if (DECIMAL_HI32(decRes) < DECIMAL_HI32(*pdecL)) { -AlignedScale: - // The addition carried above 96 bits. Divide the result by 10, - // dropping the scale factor. - // - if (DECIMAL_SCALE(decRes) == 0) - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); // DISP_E_OVERFLOW - DECIMAL_SCALE(decRes)--; - - sdlTmp.u.Lo = DECIMAL_HI32(decRes); - sdlTmp.u.Hi = 1; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_HI32(decRes) = sdlTmp.u.Lo; - - sdlTmp.u.Lo = DECIMAL_MID32(decRes); - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_MID32(decRes) = sdlTmp.u.Lo; - - sdlTmp.u.Lo = DECIMAL_LO32(decRes); - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_LO32(decRes) = sdlTmp.u.Lo; - - // See if we need to round up. - // - if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (DECIMAL_LO32(decRes) & 1))) { - DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1); - if (DECIMAL_LO64_GET(decRes) == 0) - DECIMAL_HI32(decRes)++; - } - } - } - } - else { - // Scale factors are not equal. Assume that a larger scale - // factor (more decimal places) is likely to mean that number - // is smaller. Start by guessing that the right operand has - // the larger scale factor. The result will have the larger - // scale factor. - // - DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecR); // scale factor of "smaller" - DECIMAL_SIGN(decRes) = DECIMAL_SIGN(*pdecL); // but sign of "larger" - iScale = DECIMAL_SCALE(decRes)- DECIMAL_SCALE(*pdecL); - - if (iScale < 0) { - // Guessed scale factor wrong. Swap operands. - // - iScale = -iScale; - DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecL); - DECIMAL_SIGN(decRes) ^= bSign; - pdecTmp = pdecR; - pdecR = pdecL; - pdecL = pdecTmp; - } - - // *pdecL will need to be multiplied by 10^iScale so - // it will have the same scale as *pdecR. We could be - // extending it to up to 192 bits of precision. - // - if (iScale <= POWER10_MAX) { - // Scaling won't make it larger than 4 ULONGs - // - ulPwr = rgulPower10[iScale]; - DECIMAL_LO64_SET(decTmp, UInt32x32To64(DECIMAL_LO32(*pdecL), ulPwr)); - sdlTmp.int64 = UInt32x32To64(DECIMAL_MID32(*pdecL), ulPwr); - sdlTmp.int64 += DECIMAL_MID32(decTmp); - DECIMAL_MID32(decTmp) = sdlTmp.u.Lo; - DECIMAL_HI32(decTmp) = sdlTmp.u.Hi; - sdlTmp.int64 = UInt32x32To64(DECIMAL_HI32(*pdecL), ulPwr); - sdlTmp.int64 += DECIMAL_HI32(decTmp); - if (sdlTmp.u.Hi == 0) { - // Result fits in 96 bits. Use standard aligned add. - // - DECIMAL_HI32(decTmp) = sdlTmp.u.Lo; - pdecL = &decTmp; - goto AlignedAdd; - } - rgulNum[0] = DECIMAL_LO32(decTmp); - rgulNum[1] = DECIMAL_MID32(decTmp); - rgulNum[2] = sdlTmp.u.Lo; - rgulNum[3] = sdlTmp.u.Hi; - iHiProd = 3; - } - else { - // Have to scale by a bunch. Move the number to a buffer - // where it has room to grow as it's scaled. - // - rgulNum[0] = DECIMAL_LO32(*pdecL); - rgulNum[1] = DECIMAL_MID32(*pdecL); - rgulNum[2] = DECIMAL_HI32(*pdecL); - iHiProd = 2; - - // Scan for zeros in the upper words. - // - if (rgulNum[2] == 0) { - iHiProd = 1; - if (rgulNum[1] == 0) { - iHiProd = 0; - if (rgulNum[0] == 0) { - // Left arg is zero, return right. - // - DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecR)); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecR); - DECIMAL_SIGN(decRes) ^= bSign; - goto RetDec; - } - } - } - - // Scaling loop, up to 10^9 at a time. iHiProd stays updated - // with index of highest non-zero ULONG. - // - for (; iScale > 0; iScale -= POWER10_MAX) { - if (iScale > POWER10_MAX) - ulPwr = ulTenToNine; - else - ulPwr = rgulPower10[iScale]; - - sdlTmp.u.Hi = 0; - for (iCur = 0; iCur <= iHiProd; iCur++) { - sdlTmp.int64 = UInt32x32To64(rgulNum[iCur], ulPwr) + sdlTmp.u.Hi; - rgulNum[iCur] = sdlTmp.u.Lo; - } - - if (sdlTmp.u.Hi != 0) - // We're extending the result by another ULONG. - rgulNum[++iHiProd] = sdlTmp.u.Hi; - } - } - - // Scaling complete, do the add. Could be subtract if signs differ. - // - sdlTmp.u.Lo = rgulNum[0]; - sdlTmp.u.Hi = rgulNum[1]; - - if (bSign) { - // Signs differ, subtract. - // - DECIMAL_LO64_SET(decRes, (sdlTmp.int64 - DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = rgulNum[2] - DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) { - DECIMAL_HI32(decRes)--; - if (DECIMAL_HI32(decRes) >= rgulNum[2]) - goto LongSub; - } - else if (DECIMAL_HI32(decRes) > rgulNum[2]) { -LongSub: - // If rgulNum has more than 96 bits of precision, then we need to - // carry the subtraction into the higher bits. If it doesn't, - // then we subtracted in the wrong order and have to flip the - // sign of the result. - // - if (iHiProd <= 2) - goto SignFlip; - - iCur = 3; - while(rgulNum[iCur++]-- == 0); - if (rgulNum[iHiProd] == 0) - iHiProd--; - } - } - else { - // Signs the same, add. - // - DECIMAL_LO64_SET(decRes, (sdlTmp.int64 + DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = rgulNum[2] + DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) { - DECIMAL_HI32(decRes)++; - if (DECIMAL_HI32(decRes) <= rgulNum[2]) - goto LongAdd; - } - else if (DECIMAL_HI32(decRes) < rgulNum[2]) { -LongAdd: - // Had a carry above 96 bits. - // - iCur = 3; - do { - if (iHiProd < iCur) { - rgulNum[iCur] = 1; - iHiProd = iCur; - break; - } - }while (++rgulNum[iCur++] == 0); - } - } - - if (iHiProd > 2) { - rgulNum[0] = DECIMAL_LO32(decRes); - rgulNum[1] = DECIMAL_MID32(decRes); - rgulNum[2] = DECIMAL_HI32(decRes); - DECIMAL_SCALE(decRes) = (BYTE)ScaleResult(rgulNum, iHiProd, DECIMAL_SCALE(decRes)); - if (DECIMAL_SCALE(decRes) == (BYTE)-1) - FCThrowResVoid(kOverflowException, W("Overflow_Decimal")); // DISP_E_OVERFLOW - - DECIMAL_LO32(decRes) = rgulNum[0]; - DECIMAL_MID32(decRes) = rgulNum[1]; - DECIMAL_HI32(decRes) = rgulNum[2]; - } - } - -RetDec: - pdecL = pdecLOriginal; - COPYDEC(*pdecL, decRes) - pdecL->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - -FCIMPL4(void, COMDecimal::DoAddSub, DECIMAL * pdecL, DECIMAL * pdecR, UINT8 bSign, CLR_BOOL * overflowed) -{ - FCALL_CONTRACT; - - ULONG rgulNum[6]; - ULONG ulPwr; - int iScale; - int iHiProd; - int iCur; - SPLIT64 sdlTmp; - DECIMAL decRes; - DECIMAL decTmp; - LPDECIMAL pdecTmp; - LPDECIMAL pdecLOriginal; - - _ASSERTE(bSign == 0 || bSign == DECIMAL_NEG); - - pdecLOriginal = pdecL; - - bSign ^= (DECIMAL_SIGN(*pdecR) ^ DECIMAL_SIGN(*pdecL)) & DECIMAL_NEG; - - if (DECIMAL_SCALE(*pdecR) == DECIMAL_SCALE(*pdecL)) { - // Scale factors are equal, no alignment necessary. - // - DECIMAL_SIGNSCALE(decRes) = DECIMAL_SIGNSCALE(*pdecL); - -AlignedAdd: - if (bSign) { - // Signs differ - subtract - // - DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) - DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) - DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) > DECIMAL_LO64_GET(*pdecL)) { - DECIMAL_HI32(decRes)--; - if (DECIMAL_HI32(decRes) >= DECIMAL_HI32(*pdecL)) - goto SignFlip; - } - else if (DECIMAL_HI32(decRes) > DECIMAL_HI32(*pdecL)) { - // Got negative result. Flip its sign. - // -SignFlip: - DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes)); - DECIMAL_HI32(decRes) = ~DECIMAL_HI32(decRes); - if (DECIMAL_LO64_GET(decRes) == 0) - DECIMAL_HI32(decRes)++; - DECIMAL_SIGN(decRes) ^= DECIMAL_NEG; - } - - } - else { - // Signs are the same - add - // - DECIMAL_LO64_SET(decRes, (DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecL) + DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) { - DECIMAL_HI32(decRes)++; - if (DECIMAL_HI32(decRes) <= DECIMAL_HI32(*pdecL)) - goto AlignedScale; - } - else if (DECIMAL_HI32(decRes) < DECIMAL_HI32(*pdecL)) { -AlignedScale: - // The addition carried above 96 bits. Divide the result by 10, - // dropping the scale factor. - // - if (DECIMAL_SCALE(decRes) == 0) { - *overflowed = true; - FC_GC_POLL(); - return; - } - DECIMAL_SCALE(decRes)--; - - sdlTmp.u.Lo = DECIMAL_HI32(decRes); - sdlTmp.u.Hi = 1; - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_HI32(decRes) = sdlTmp.u.Lo; - - sdlTmp.u.Lo = DECIMAL_MID32(decRes); - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_MID32(decRes) = sdlTmp.u.Lo; - - sdlTmp.u.Lo = DECIMAL_LO32(decRes); - sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10); - DECIMAL_LO32(decRes) = sdlTmp.u.Lo; - - // See if we need to round up. - // - if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (DECIMAL_LO32(decRes) & 1))) { - DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1); - if (DECIMAL_LO64_GET(decRes) == 0) - DECIMAL_HI32(decRes)++; - } - } - } - } - else { - // Scale factors are not equal. Assume that a larger scale - // factor (more decimal places) is likely to mean that number - // is smaller. Start by guessing that the right operand has - // the larger scale factor. The result will have the larger - // scale factor. - // - DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecR); // scale factor of "smaller" - DECIMAL_SIGN(decRes) = DECIMAL_SIGN(*pdecL); // but sign of "larger" - iScale = DECIMAL_SCALE(decRes)- DECIMAL_SCALE(*pdecL); - - if (iScale < 0) { - // Guessed scale factor wrong. Swap operands. - // - iScale = -iScale; - DECIMAL_SCALE(decRes) = DECIMAL_SCALE(*pdecL); - DECIMAL_SIGN(decRes) ^= bSign; - pdecTmp = pdecR; - pdecR = pdecL; - pdecL = pdecTmp; - } - - // *pdecL will need to be multiplied by 10^iScale so - // it will have the same scale as *pdecR. We could be - // extending it to up to 192 bits of precision. - // - if (iScale <= POWER10_MAX) { - // Scaling won't make it larger than 4 ULONGs - // - ulPwr = rgulPower10[iScale]; - DECIMAL_LO64_SET(decTmp, UInt32x32To64(DECIMAL_LO32(*pdecL), ulPwr)); - sdlTmp.int64 = UInt32x32To64(DECIMAL_MID32(*pdecL), ulPwr); - sdlTmp.int64 += DECIMAL_MID32(decTmp); - DECIMAL_MID32(decTmp) = sdlTmp.u.Lo; - DECIMAL_HI32(decTmp) = sdlTmp.u.Hi; - sdlTmp.int64 = UInt32x32To64(DECIMAL_HI32(*pdecL), ulPwr); - sdlTmp.int64 += DECIMAL_HI32(decTmp); - if (sdlTmp.u.Hi == 0) { - // Result fits in 96 bits. Use standard aligned add. - // - DECIMAL_HI32(decTmp) = sdlTmp.u.Lo; - pdecL = &decTmp; - goto AlignedAdd; - } - rgulNum[0] = DECIMAL_LO32(decTmp); - rgulNum[1] = DECIMAL_MID32(decTmp); - rgulNum[2] = sdlTmp.u.Lo; - rgulNum[3] = sdlTmp.u.Hi; - iHiProd = 3; - } - else { - // Have to scale by a bunch. Move the number to a buffer - // where it has room to grow as it's scaled. - // - rgulNum[0] = DECIMAL_LO32(*pdecL); - rgulNum[1] = DECIMAL_MID32(*pdecL); - rgulNum[2] = DECIMAL_HI32(*pdecL); - iHiProd = 2; - - // Scan for zeros in the upper words. - // - if (rgulNum[2] == 0) { - iHiProd = 1; - if (rgulNum[1] == 0) { - iHiProd = 0; - if (rgulNum[0] == 0) { - // Left arg is zero, return right. - // - DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecR)); - DECIMAL_HI32(decRes) = DECIMAL_HI32(*pdecR); - DECIMAL_SIGN(decRes) ^= bSign; - goto RetDec; - } - } - } - - // Scaling loop, up to 10^9 at a time. iHiProd stays updated - // with index of highest non-zero ULONG. - // - for (; iScale > 0; iScale -= POWER10_MAX) { - if (iScale > POWER10_MAX) - ulPwr = ulTenToNine; - else - ulPwr = rgulPower10[iScale]; - - sdlTmp.u.Hi = 0; - for (iCur = 0; iCur <= iHiProd; iCur++) { - sdlTmp.int64 = UInt32x32To64(rgulNum[iCur], ulPwr) + sdlTmp.u.Hi; - rgulNum[iCur] = sdlTmp.u.Lo; - } - - if (sdlTmp.u.Hi != 0) - // We're extending the result by another ULONG. - rgulNum[++iHiProd] = sdlTmp.u.Hi; - } - } - - // Scaling complete, do the add. Could be subtract if signs differ. - // - sdlTmp.u.Lo = rgulNum[0]; - sdlTmp.u.Hi = rgulNum[1]; - - if (bSign) { - // Signs differ, subtract. - // - DECIMAL_LO64_SET(decRes, (sdlTmp.int64 - DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = rgulNum[2] - DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) { - DECIMAL_HI32(decRes)--; - if (DECIMAL_HI32(decRes) >= rgulNum[2]) - goto LongSub; - } - else if (DECIMAL_HI32(decRes) > rgulNum[2]) { -LongSub: - // If rgulNum has more than 96 bits of precision, then we need to - // carry the subtraction into the higher bits. If it doesn't, - // then we subtracted in the wrong order and have to flip the - // sign of the result. - // - if (iHiProd <= 2) - goto SignFlip; - - iCur = 3; - while(rgulNum[iCur++]-- == 0); - if (rgulNum[iHiProd] == 0) - iHiProd--; - } - } - else { - // Signs the same, add. - // - DECIMAL_LO64_SET(decRes, (sdlTmp.int64 + DECIMAL_LO64_GET(*pdecR))); - DECIMAL_HI32(decRes) = rgulNum[2] + DECIMAL_HI32(*pdecR); - - // Propagate carry - // - if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) { - DECIMAL_HI32(decRes)++; - if (DECIMAL_HI32(decRes) <= rgulNum[2]) - goto LongAdd; - } - else if (DECIMAL_HI32(decRes) < rgulNum[2]) { -LongAdd: - // Had a carry above 96 bits. - // - iCur = 3; - do { - if (iHiProd < iCur) { - rgulNum[iCur] = 1; - iHiProd = iCur; - break; - } - }while (++rgulNum[iCur++] == 0); - } - } - - if (iHiProd > 2) { - rgulNum[0] = DECIMAL_LO32(decRes); - rgulNum[1] = DECIMAL_MID32(decRes); - rgulNum[2] = DECIMAL_HI32(decRes); - DECIMAL_SCALE(decRes) = (BYTE)ScaleResult(rgulNum, iHiProd, DECIMAL_SCALE(decRes)); - if (DECIMAL_SCALE(decRes) == (BYTE)-1) { - *overflowed = true; - FC_GC_POLL(); - return; - } - - DECIMAL_LO32(decRes) = rgulNum[0]; - DECIMAL_MID32(decRes) = rgulNum[1]; - DECIMAL_HI32(decRes) = rgulNum[2]; - } - } - -RetDec: - pdecL = pdecLOriginal; - COPYDEC(*pdecL, decRes) - pdecL->wReserved = 0; - FC_GC_POLL(); -} -FCIMPLEND - diff --git a/src/classlibnative/bcltype/decimal.h b/src/classlibnative/bcltype/decimal.h deleted file mode 100644 index f037fd3acb..0000000000 --- a/src/classlibnative/bcltype/decimal.h +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// -// File: Decimal.h -// - -// - -#ifndef _DECIMAL_H_ -#define _DECIMAL_H_ - -#include <oleauto.h> - -#include <pshpack1.h> - -#include "number.h" - -#define DECIMAL_PRECISION 29 - -class COMDecimal { -public: - static FCDECL2_IV(void, InitSingle, DECIMAL *_this, float value); - static FCDECL2_IV(void, InitDouble, DECIMAL *_this, double value); - static FCDECL2(INT32, DoCompare, DECIMAL * d1, DECIMAL * d2); - - static FCDECL3(void, DoAddSubThrow, DECIMAL * d1, DECIMAL * d2, UINT8 bSign); - static FCDECL2(void, DoDivideThrow, DECIMAL * d1, DECIMAL * d2); - static FCDECL2(void, DoMultiplyThrow, DECIMAL * d1, DECIMAL * d2); - - static FCDECL4(void, DoAddSub, DECIMAL * d1, DECIMAL * d2, UINT8 bSign, CLR_BOOL * overflowed); - static FCDECL3(void, DoDivide, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed); - static FCDECL3(void, DoMultiply, DECIMAL * d1, DECIMAL * d2, CLR_BOOL * overflowed); - - static FCDECL2(void, DoRound, DECIMAL * d1, INT32 decimals); - static FCDECL2_IV(void, DoToCurrency, CY * result, DECIMAL d); - static FCDECL1(void, DoTruncate, DECIMAL * d); - static FCDECL1(void, DoFloor, DECIMAL * d); - - static FCDECL1(double, ToDouble, FC_DECIMAL d); - static FCDECL1(float, ToSingle, FC_DECIMAL d); - static FCDECL1(INT32, ToInt32, FC_DECIMAL d); - static FCDECL1(Object*, ToString, FC_DECIMAL d); - - static int NumberToDecimal(NUMBER* number, DECIMAL* value); - - -}; - -#include <poppack.h> - -#endif // _DECIMAL_H_ diff --git a/src/classlibnative/bcltype/number.cpp b/src/classlibnative/bcltype/number.cpp index ac068d6a54..b4bf7a5bfc 100644 --- a/src/classlibnative/bcltype/number.cpp +++ b/src/classlibnative/bcltype/number.cpp @@ -11,7 +11,6 @@ #include "excep.h" #include "number.h" #include "string.h" -#include "decimal.h" #include "bignum.h" #include "grisu3.h" #include "fp.h" @@ -1278,6 +1277,7 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF */ _ASSERTE(numfmt != NULL); + _ASSERTE(!bDecimal); UINT64 newBufferLen = MIN_BUFFER_SIZE; CQuickBytesSpecifySize<LARGE_BUFFER_SIZE * sizeof(WCHAR)> buf; @@ -1441,15 +1441,8 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF { bool enableRounding = true; if (nMaxDigits < 1) { - if (bDecimal && (nMaxDigits == -1)) { // Default to 29 digits precision only for G formatting without a precision specifier - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = DECIMAL_PRECISION; - enableRounding = false; // Turn off rounding for ECMA compliance to output trailing 0's after decimal as significant - } - else { - // This ensures that the PAL code pads out to the correct place even when we use the default precision - nMaxDigits = nMinDigits = number->precision; - } + // This ensures that the PAL code pads out to the correct place even when we use the default precision + nMaxDigits = nMinDigits = number->precision; } else nMinDigits=nMaxDigits; @@ -1471,11 +1464,6 @@ STRINGREF NumberToString(NUMBER* number, wchar format, int nMaxDigits, NUMFMTREF if (enableRounding) // Don't round for G formatting without precision RoundNumber(number, nMaxDigits); // This also fixes up the minus zero case - else { - if (bDecimal && ((GetDigitsBuffer(number))[0] == 0)) { // Minus zero should be formatted as 0 - number->sign = 0; - } - } if (number->sign) { AddStringRef(&dst, sNegative); } @@ -2000,11 +1988,3 @@ FCIMPL1(double, COMNumber::NumberToDoubleFC, NUMBER* number) return d; } FCIMPLEND - -FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDecimal, NUMBER* number, DECIMAL* value) -{ - FCALL_CONTRACT; - - FC_RETURN_BOOL(COMDecimal::NumberToDecimal(number, value) != 0); -} -FCIMPLEND diff --git a/src/classlibnative/bcltype/number.h b/src/classlibnative/bcltype/number.h index bf1f328b02..0fd12b11bd 100644 --- a/src/classlibnative/bcltype/number.h +++ b/src/classlibnative/bcltype/number.h @@ -33,7 +33,6 @@ class COMNumber public: static FCDECL3_VII(void, DoubleToNumberFC, double value, int precision, NUMBER* number); static FCDECL1(double, NumberToDoubleFC, NUMBER* number); - static FCDECL2(FC_BOOL_RET, NumberBufferToDecimal, NUMBER* number, DECIMAL* value); static wchar_t* Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits); }; |