summaryrefslogtreecommitdiff
path: root/src/palrt
diff options
context:
space:
mode:
authorPent Ploompuu <kaalikas@gmail.com>2018-07-17 18:41:39 +0300
committerJan Kotas <jkotas@microsoft.com>2018-07-17 08:41:39 -0700
commit2b50bba8131acca2ab535e144796941ad93487b7 (patch)
tree5c3f9901749fceb1aa1e14c67665a76b5a9ee408 /src/palrt
parent624f72d55a92e49aef3c3cd6e69150fa3b085fac (diff)
downloadcoreclr-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/palrt')
-rw-r--r--src/palrt/CMakeLists.txt2
-rw-r--r--src/palrt/decarith.cpp1267
-rw-r--r--src/palrt/decconv.cpp602
3 files changed, 0 insertions, 1871 deletions
diff --git a/src/palrt/CMakeLists.txt b/src/palrt/CMakeLists.txt
index e19b55d9dc..e5ca200a5e 100644
--- a/src/palrt/CMakeLists.txt
+++ b/src/palrt/CMakeLists.txt
@@ -5,8 +5,6 @@ set(PALRT_SOURCES
bstr.cpp
coguid.cpp
comem.cpp
- decarith.cpp
- decconv.cpp
guid.cpp
memorystream.cpp
path.cpp
diff --git a/src/palrt/decarith.cpp b/src/palrt/decarith.cpp
deleted file mode 100644
index f190707ab6..0000000000
--- a/src/palrt/decarith.cpp
+++ /dev/null
@@ -1,1267 +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: decarith.cpp
-//
-// ===========================================================================
-/***
-*
-*Purpose:
-* Implement arithmetic for Decimal data type.
-*
-*Implementation Notes:
-*
-*****************************************************************************/
-
-#include "common.h"
-
-#include <oleauto.h>
-#include "convert.h"
-
-//***********************************************************************
-//
-// Additional Decimal and Int64 definitions
-//
-#define COPYDEC(dest, src) {DECIMAL_SIGNSCALE(dest) = DECIMAL_SIGNSCALE(src); DECIMAL_HI32(dest) = DECIMAL_HI32(src); \
- DECIMAL_MID32(dest) = DECIMAL_MID32(src); DECIMAL_LO32(dest) = DECIMAL_LO32(src); }
-
-#define DEC_SCALE_MAX 28
-#define POWER10_MAX 9
-
-// The following functions are defined in the classlibnative\bcltype\decimal.cpp
-ULONG Div96By32(ULONG *rgulNum, ULONG ulDen);
-ULONG Div96By64(ULONG *rgulNum, SPLIT64 sdlDen);
-ULONG Div128By96(ULONG *rgulNum, ULONG *rgulDen);
-int ScaleResult(ULONG *rgulRes, int iHiRes, int iScale);
-ULONG IncreaseScale(ULONG *rgulNum, ULONG ulPwr);
-
-//***********************************************************************
-//
-// Data tables
-//
-
-static ULONG rgulPower10[POWER10_MAX+1] = {1, 10, 100, 1000, 10000, 100000, 1000000,
- 10000000, 100000000, 1000000000};
-
-struct DECOVFL
-{
- ULONG Hi;
- ULONG Mid;
-};
-
-static 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.
-//
- { 429496729UL, 2576980377UL }, // 10^1 remainder 0.6
- { 42949672UL, 4123168604UL }, // 10^2 remainder 0.16
- { 4294967UL, 1271310319UL }, // 10^3 remainder 0.616
- { 429496UL, 3133608139UL }, // 10^4 remainder 0.1616
- { 42949UL, 2890341191UL }, // 10^5 remainder 0.51616
- { 4294UL, 4154504685UL }, // 10^6 remainder 0.551616
- { 429UL, 2133437386UL }, // 10^7 remainder 0.9551616
- { 42UL, 4078814305UL }, // 10^8 remainder 0.09991616
-// { 4UL, 1266874889UL }, // 10^9 remainder 0.709551616
-};
-
-#define OVFL_MAX_9_HI 4
-#define OVFL_MAX_9_MID 1266874889
-
-#define OVFL_MAX_5_HI 42949
-#define OVFL_MAX_5_MID 2890341191
-
-#define OVFL_MAX_1_HI 429496729
-
-
-
-//***********************************************************************
-//
-// static helper functions
-//
-
-/***
-* FullDiv64By32
-*
-* Entry:
-* pdlNum - Pointer to 64-bit dividend
-* ulDen - 32-bit divisor
-*
-* Purpose:
-* Do full divide, yielding 64-bit result and 32-bit remainder.
-*
-* Exit:
-* Quotient overwrites dividend.
-* Returns remainder.
-*
-* Exceptions:
-* None.
-*
-***********************************************************************/
-
-ULONG FullDiv64By32(DWORDLONG *pdlNum, ULONG ulDen)
-{
- SPLIT64 sdlTmp;
- SPLIT64 sdlRes;
-
- sdlTmp.int64 = *pdlNum;
- sdlRes.u.Hi = 0;
-
- if (sdlTmp.u.Hi >= ulDen) {
- // DivMod64by32 returns quotient in Lo, remainder in Hi.
- //
- sdlRes.u.Lo = sdlTmp.u.Hi;
- sdlRes.int64 = DivMod64by32(sdlRes.int64, ulDen);
- sdlTmp.u.Hi = sdlRes.u.Hi;
- sdlRes.u.Hi = sdlRes.u.Lo;
- }
-
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulDen);
- sdlRes.u.Lo = sdlTmp.u.Lo;
- *pdlNum = sdlRes.int64;
- return sdlTmp.u.Hi;
-}
-
-
-
-
-/***
-* SearchScale
-*
-* Entry:
-* ulResHi - Top ULONG of quotient
-* ulResLo - Middle 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 ulResLo, int iScale)
-{
- 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 (ulResLo >= PowerOvfl[iCurScale - 1].Mid)
- iCurScale--;
- goto HaveScale;
- }
- }
- else if (ulResHi < OVFL_MAX_9_HI || (ulResHi == OVFL_MAX_9_HI &&
- ulResLo < OVFL_MAX_9_MID))
- 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;
-}
-
-/***
-* DecFixInt
-*
-* Entry:
-* pdecRes - Pointer to Decimal result location
-* pdecIn - Pointer to Decimal operand
-*
-* Purpose:
-* Chop the value to integer. Return remainder so Int() function
-* can round down if non-zero.
-*
-* Exit:
-* Returns remainder.
-*
-* Exceptions:
-* None.
-*
-***********************************************************************/
-
-ULONG DecFixInt(LPDECIMAL pdecRes, LPDECIMAL pdecIn)
-{
- ULONG rgulNum[3];
- ULONG ulRem;
- ULONG ulPwr;
- int iScale;
-
- if (pdecIn->u.u.scale > 0) {
- rgulNum[0] = pdecIn->v.v.Lo32;
- rgulNum[1] = pdecIn->v.v.Mid32;
- rgulNum[2] = pdecIn->Hi32;
- iScale = pdecIn->u.u.scale;
- pdecRes->u.u.sign = pdecIn->u.u.sign;
- ulRem = 0;
-
- do {
- if (iScale > POWER10_MAX)
- ulPwr = ulTenToNine;
- else
- ulPwr = rgulPower10[iScale];
-
- ulRem |= Div96By32(rgulNum, ulPwr);
- iScale -= 9;
- }while (iScale > 0);
-
- pdecRes->v.v.Lo32 = rgulNum[0];
- pdecRes->v.v.Mid32 = rgulNum[1];
- pdecRes->Hi32 = rgulNum[2];
- pdecRes->u.u.scale = 0;
-
- return ulRem;
- }
-
- COPYDEC(*pdecRes, *pdecIn)
- return 0;
-}
-
-
-//***********************************************************************
-//
-//
-//
-
-//**********************************************************************
-//
-// VarDecMul - Decimal Multiply
-//
-//**********************************************************************
-
-STDAPI VarDecMul(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
- SPLIT64 sdlTmp;
- SPLIT64 sdlTmp2;
- SPLIT64 sdlTmp3;
- int iScale;
- int iHiProd;
- ULONG ulPwr;
- ULONG ulRemLo;
- ULONG ulRemHi;
- ULONG rgulProd[6];
-
- iScale = pdecL->u.u.scale + pdecR->u.u.scale;
-
- if ((pdecL->Hi32 | pdecL->v.v.Mid32 | pdecR->Hi32 | pdecR->v.v.Mid32) == 0)
- {
- // Upper 64 bits are zero.
- //
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Lo32);
- if (iScale > DEC_SCALE_MAX)
- {
- // Result iScale is too big. Divide result by power of 10 to reduce it.
- // If the amount to divide by is > 19 the result is guaranteed
- // less than 1/2. [max value in 64 bits = 1.84E19]
- //
- iScale -= DEC_SCALE_MAX;
- if (iScale > 19)
- {
-ReturnZero:
- DECIMAL_SETZERO(*pdecRes);
- return NOERROR;
- }
- if (iScale > POWER10_MAX)
- {
- // Divide by 1E10 first, to get the power down to a 32-bit quantity.
- // 1E10 itself doesn't fit in 32 bits, so we'll divide by 2.5E9 now
- // then multiply the next divisor by 4 (which will be a max of 4E9).
- //
- ulRemLo = FullDiv64By32(&sdlTmp.int64, ulTenToTenDiv4);
- ulPwr = rgulPower10[iScale - 10] << 2;
- }
- else
- {
- ulPwr = rgulPower10[iScale];
- ulRemLo = 0;
- }
-
- // Power to divide by fits in 32 bits.
- //
- ulRemHi = FullDiv64By32(&sdlTmp.int64, ulPwr);
-
- // Round result. See if remainder >= 1/2 of divisor.
- // Divisor is a power of 10, so it is always even.
- //
- ulPwr >>= 1;
- if (ulRemHi >= ulPwr && (ulRemHi > ulPwr || (ulRemLo | (sdlTmp.u.Lo & 1))))
- sdlTmp.int64++;
-
- iScale = DEC_SCALE_MAX;
- }
- DECIMAL_LO32(*pdecRes) = sdlTmp.u.Lo;
- DECIMAL_MID32(*pdecRes) = sdlTmp.u.Hi;
- DECIMAL_HI32(*pdecRes) = 0;
- }
- else
- {
-
- // At least one operand has bits set in the upper 64 bits.
- //
- // Compute and accumulate the 9 partial products into a
- // 192-bit (24-byte) result.
- //
- // [l-h][l-m][l-l] left high, middle, low
- // x [r-h][r-m][r-l] right high, middle, low
- // ------------------------------
- //
- // [0-h][0-l] l-l * r-l
- // [1ah][1al] l-l * r-m
- // [1bh][1bl] l-m * r-l
- // [2ah][2al] l-m * r-m
- // [2bh][2bl] l-l * r-h
- // [2ch][2cl] l-h * r-l
- // [3ah][3al] l-m * r-h
- // [3bh][3bl] l-h * r-m
- // [4-h][4-l] l-h * r-h
- // ------------------------------
- // [p-5][p-4][p-3][p-2][p-1][p-0] prod[] array
- //
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Lo32);
- rgulProd[0] = sdlTmp.u.Lo;
-
- sdlTmp2.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->v.v.Mid32) + sdlTmp.u.Hi;
-
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->v.v.Lo32);
- sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
- rgulProd[1] = sdlTmp.u.Lo;
- if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
- sdlTmp2.u.Hi = 1;
- else
- sdlTmp2.u.Hi = 0;
- sdlTmp2.u.Lo = sdlTmp.u.Hi;
-
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->v.v.Mid32) + sdlTmp2.int64;
-
- if (pdecL->Hi32 | pdecR->Hi32) {
- // Highest 32 bits is non-zero. Calculate 5 more partial products.
- //
- sdlTmp2.int64 = UInt32x32To64(pdecL->v.v.Lo32, pdecR->Hi32);
- sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
- if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
- sdlTmp3.u.Hi = 1;
- else
- sdlTmp3.u.Hi = 0;
-
- sdlTmp2.int64 = UInt32x32To64(pdecL->Hi32, pdecR->v.v.Lo32);
- sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
- rgulProd[2] = sdlTmp.u.Lo;
- if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
- sdlTmp3.u.Hi++;
- sdlTmp3.u.Lo = sdlTmp.u.Hi;
-
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, pdecR->Hi32);
- sdlTmp.int64 += sdlTmp3.int64; // this could generate carry
- if (sdlTmp.int64 < sdlTmp3.int64) // detect carry
- sdlTmp3.u.Hi = 1;
- else
- sdlTmp3.u.Hi = 0;
-
- sdlTmp2.int64 = UInt32x32To64(pdecL->Hi32, pdecR->v.v.Mid32);
- sdlTmp.int64 += sdlTmp2.int64; // this could generate carry
- rgulProd[3] = sdlTmp.u.Lo;
- if (sdlTmp.int64 < sdlTmp2.int64) // detect carry
- sdlTmp3.u.Hi++;
- sdlTmp3.u.Lo = sdlTmp.u.Hi;
-
- sdlTmp.int64 = UInt32x32To64(pdecL->Hi32, pdecR->Hi32) + sdlTmp3.int64;
- rgulProd[4] = sdlTmp.u.Lo;
- rgulProd[5] = sdlTmp.u.Hi;
-
- iHiProd = 5;
- }
- else {
- rgulProd[2] = sdlTmp.u.Lo;
- rgulProd[3] = sdlTmp.u.Hi;
- iHiProd = 3;
- }
-
- // Check for leading zero ULONGs on the product
- //
- while (rgulProd[iHiProd] == 0) {
- iHiProd--;
- if (iHiProd < 0)
- goto ReturnZero;
- }
-
- iScale = ScaleResult(rgulProd, iHiProd, iScale);
- if (iScale == -1)
- return DISP_E_OVERFLOW;
-
- pdecRes->v.v.Lo32 = rgulProd[0];
- pdecRes->v.v.Mid32 = rgulProd[1];
- pdecRes->Hi32 = rgulProd[2];
- }
-
- pdecRes->u.u.sign = pdecR->u.u.sign ^ pdecL->u.u.sign;
- pdecRes->u.u.scale = (char)iScale;
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecAdd - Decimal Addition
-// VarDecSub - Decimal Subtraction
-//
-//**********************************************************************
-
-static HRESULT DecAddSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes, char bSign);
-
-STDAPI VarDecAdd(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
- return DecAddSub(pdecL, pdecR, pdecRes, 0);
-}
-
-
-STDAPI VarDecSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
- return DecAddSub(pdecL, pdecR, pdecRes, DECIMAL_NEG);
-}
-
-
-static HRESULT DecAddSub(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes, char bSign)
-{
- ULONG rgulNum[6];
- ULONG ulPwr;
- int iScale;
- int iHiProd;
- int iCur;
- SPLIT64 sdlTmp;
- DECIMAL decRes;
- DECIMAL decTmp;
- LPDECIMAL pdecTmp;
-
- bSign ^= (pdecR->u.u.sign ^ pdecL->u.u.sign) & DECIMAL_NEG;
-
- if (pdecR->u.u.scale == pdecL->u.u.scale) {
- // Scale factors are equal, no alignment necessary.
- //
- decRes.u.signscale = pdecL->u.signscale;
-
-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)) {
- decRes.Hi32--;
- if (decRes.Hi32 >= pdecL->Hi32)
- goto SignFlip;
- }
- else if (decRes.Hi32 > pdecL->Hi32) {
- // Got negative result. Flip its sign.
- //
-SignFlip:
- DECIMAL_LO64_SET(decRes, -(LONGLONG)DECIMAL_LO64_GET(decRes));
- decRes.Hi32 = ~decRes.Hi32;
- if (DECIMAL_LO64_GET(decRes) == 0)
- decRes.Hi32++;
- decRes.u.u.sign ^= DECIMAL_NEG;
- }
-
- }
- else {
- // Signs are the same - add
- //
- DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(*pdecL) + DECIMAL_LO64_GET(*pdecR));
- decRes.Hi32 = pdecL->Hi32 + pdecR->Hi32;
-
- // Propagate carry
- //
- if (DECIMAL_LO64_GET(decRes) < DECIMAL_LO64_GET(*pdecL)) {
- decRes.Hi32++;
- if (decRes.Hi32 <= pdecL->Hi32)
- goto AlignedScale;
- }
- else if (decRes.Hi32 < pdecL->Hi32) {
-AlignedScale:
- // The addition carried above 96 bits. Divide the result by 10,
- // dropping the scale factor.
- //
- if (decRes.u.u.scale == 0)
- return DISP_E_OVERFLOW;
- decRes.u.u.scale--;
-
- sdlTmp.u.Lo = decRes.Hi32;
- sdlTmp.u.Hi = 1;
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
- decRes.Hi32 = sdlTmp.u.Lo;
-
- sdlTmp.u.Lo = decRes.v.v.Mid32;
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
- decRes.v.v.Mid32 = sdlTmp.u.Lo;
-
- sdlTmp.u.Lo = decRes.v.v.Lo32;
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, 10);
- decRes.v.v.Lo32 = sdlTmp.u.Lo;
-
- // See if we need to round up.
- //
- if (sdlTmp.u.Hi >= 5 && (sdlTmp.u.Hi > 5 || (decRes.v.v.Lo32 & 1))) {
- DECIMAL_LO64_SET(decRes, DECIMAL_LO64_GET(decRes)+1)
- if (DECIMAL_LO64_GET(decRes) == 0)
- decRes.Hi32++;
- }
- }
- }
- }
- 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.
- //
- decRes.u.u.scale = pdecR->u.u.scale; // scale factor of "smaller"
- decRes.u.u.sign = pdecL->u.u.sign; // but sign of "larger"
- iScale = decRes.u.u.scale - pdecL->u.u.scale;
-
- if (iScale < 0) {
- // Guessed scale factor wrong. Swap operands.
- //
- iScale = -iScale;
- decRes.u.u.scale = pdecL->u.u.scale;
- decRes.u.u.sign ^= 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(pdecL->v.v.Lo32, ulPwr));
- sdlTmp.int64 = UInt32x32To64(pdecL->v.v.Mid32, ulPwr);
- sdlTmp.int64 += decTmp.v.v.Mid32;
- decTmp.v.v.Mid32 = sdlTmp.u.Lo;
- decTmp.Hi32 = sdlTmp.u.Hi;
- sdlTmp.int64 = UInt32x32To64(pdecL->Hi32, ulPwr);
- sdlTmp.int64 += decTmp.Hi32;
- if (sdlTmp.u.Hi == 0) {
- // Result fits in 96 bits. Use standard aligned add.
- //
- decTmp.Hi32 = sdlTmp.u.Lo;
- pdecL = &decTmp;
- goto AlignedAdd;
- }
- rgulNum[0] = decTmp.v.v.Lo32;
- rgulNum[1] = decTmp.v.v.Mid32;
- 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] = pdecL->v.v.Lo32;
- rgulNum[1] = pdecL->v.v.Mid32;
- rgulNum[2] = pdecL->Hi32;
- 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));
- decRes.Hi32 = pdecR->Hi32;
- decRes.u.u.sign ^= 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));
- decRes.Hi32 = rgulNum[2] - pdecR->Hi32;
-
- // Propagate carry
- //
- if (DECIMAL_LO64_GET(decRes) > sdlTmp.int64) {
- decRes.Hi32--;
- if (decRes.Hi32 >= rgulNum[2])
- goto LongSub;
- }
- else if (decRes.Hi32 > 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));
- decRes.Hi32 = rgulNum[2] + pdecR->Hi32;
-
- // Propagate carry
- //
- if (DECIMAL_LO64_GET(decRes) < sdlTmp.int64) {
- decRes.Hi32++;
- if (decRes.Hi32 <= rgulNum[2])
- goto LongAdd;
- }
- else if (decRes.Hi32 < 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] = decRes.v.v.Lo32;
- rgulNum[1] = decRes.v.v.Mid32;
- rgulNum[2] = decRes.Hi32;
- decRes.u.u.scale = ScaleResult(rgulNum, iHiProd, decRes.u.u.scale);
- if (decRes.u.u.scale == (BYTE) -1)
- return DISP_E_OVERFLOW;
-
- decRes.v.v.Lo32 = rgulNum[0];
- decRes.v.v.Mid32 = rgulNum[1];
- decRes.Hi32 = rgulNum[2];
- }
- }
-
-RetDec:
- COPYDEC(*pdecRes, decRes)
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecDiv - Decimal Divide
-//
-//**********************************************************************
-
-STDAPI VarDecDiv(LPDECIMAL pdecL, LPDECIMAL pdecR, LPDECIMAL pdecRes)
-{
- 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;
-
- iScale = pdecL->u.u.scale - pdecR->u.u.scale;
- rgulDivisor[0] = pdecR->v.v.Lo32;
- rgulDivisor[1] = pdecR->v.v.Mid32;
- rgulDivisor[2] = pdecR->Hi32;
-
- if (rgulDivisor[1] == 0 && rgulDivisor[2] == 0) {
- // Divisor is only 32 bits. Easy divide.
- //
- if (rgulDivisor[0] == 0)
- return DISP_E_DIVBYZERO;
-
- rgulQuo[0] = pdecL->v.v.Lo32;
- rgulQuo[1] = pdecL->v.v.Mid32;
- rgulQuo[2] = pdecL->Hi32;
- rgulRem[0] = Div96By32(rgulQuo, rgulDivisor[0]);
-
- for (;;) {
- if (rgulRem[0] == 0) {
- if (iScale < 0) {
- iCurScale = min(9, -iScale);
- goto HaveScale;
- }
- break;
- }
-
- // 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], 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 (++rgulQuo[0] == 0)
- if (++rgulQuo[1] == 0)
- rgulQuo[2]++;
- }
- break;
- }
-
- if (iCurScale == -1)
- return DISP_E_OVERFLOW;
-
-HaveScale:
- ulPwr = rgulPower10[iCurScale];
- iScale += iCurScale;
-
- if (IncreaseScale(rgulQuo, ulPwr) != 0)
- return DISP_E_OVERFLOW;
-
- sdlTmp.int64 = DivMod64by32(UInt32x32To64(rgulRem[0], ulPwr), rgulDivisor[0]);
- rgulRem[0] = sdlTmp.u.Hi;
-
- rgulQuo[0] += sdlTmp.u.Lo;
- if (rgulQuo[0] < sdlTmp.u.Lo) {
- if (++rgulQuo[1] == 0)
- rgulQuo[2]++;
- }
- } // 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 = pdecL->v.v.Mid32;
- sdlTmp.u.Hi = pdecL->Hi32;
- sdlTmp.int64 <<= iCurScale;
- rgulRem[2] = sdlTmp.u.Hi;
- rgulRem[3] = (pdecL->Hi32 >> (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;
- }
-
- // 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], 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 == -1)
- return DISP_E_OVERFLOW;
-
-HaveScale64:
- ulPwr = rgulPower10[iCurScale];
- iScale += iCurScale;
-
- if (IncreaseScale(rgulQuo, ulPwr) != 0)
- return DISP_E_OVERFLOW;
-
- rgulRem[2] = 0; // rem is 64 bits, IncreaseScale uses 96
- IncreaseScale(rgulRem, ulPwr);
- ulTmp = Div96By64(rgulRem, sdlDivisor);
- rgulQuo[0] += ulTmp;
- if (rgulQuo[0] < ulTmp)
- if (++rgulQuo[1] == 0)
- rgulQuo[2]++;
-
- } // 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;
- }
-
- // 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], 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 == -1)
- return DISP_E_OVERFLOW;
-
-HaveScale96:
- ulPwr = rgulPower10[iCurScale];
- iScale += iCurScale;
-
- if (IncreaseScale(rgulQuo, ulPwr) != 0)
- return DISP_E_OVERFLOW;
-
- rgulRem[3] = IncreaseScale(rgulRem, ulPwr);
- ulTmp = Div128By96(rgulRem, rgulDivisor);
- rgulQuo[0] += ulTmp;
- if (rgulQuo[0] < ulTmp)
- if (++rgulQuo[1] == 0)
- rgulQuo[2]++;
-
- } // for (;;)
- }
- }
-
- // No more remainder. 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;
- }
- }
-
- pdecRes->Hi32 = rgulQuo[2];
- pdecRes->v.v.Mid32 = rgulQuo[1];
- pdecRes->v.v.Lo32 = rgulQuo[0];
- pdecRes->u.u.scale = iScale;
- pdecRes->u.u.sign = pdecL->u.u.sign ^ pdecR->u.u.sign;
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecAbs - Decimal Absolute Value
-//
-//**********************************************************************
-
-STDAPI VarDecAbs(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
- COPYDEC(*pdecRes, *pdecOprd)
- pdecRes->u.u.sign &= ~DECIMAL_NEG;
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecFix - Decimal Fix (chop to integer)
-//
-//**********************************************************************
-
-STDAPI VarDecFix(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
- DecFixInt(pdecRes, pdecOprd);
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecInt - Decimal Int (round down to integer)
-//
-//**********************************************************************
-
-STDAPI VarDecInt(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
- if (DecFixInt(pdecRes, pdecOprd) != 0 && (pdecRes->u.u.sign & DECIMAL_NEG)) {
- // We have chopped off a non-zero amount from a negative value. Since
- // we round toward -infinity, we must increase the integer result by
- // 1 to make it more negative. This will never overflow because
- // in order to have a remainder, we must have had a non-zero scale factor.
- // Our scale factor is back to zero now.
- //
- DECIMAL_LO64_SET(*pdecRes, DECIMAL_LO64_GET(*pdecRes) + 1);
- if (DECIMAL_LO64_GET(*pdecRes) == 0)
- pdecRes->Hi32++;
- }
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecNeg - Decimal Negate
-//
-//**********************************************************************
-
-STDAPI VarDecNeg(LPDECIMAL pdecOprd, LPDECIMAL pdecRes)
-{
- COPYDEC(*pdecRes, *pdecOprd)
- pdecRes->u.u.sign ^= DECIMAL_NEG;
- return NOERROR;
-}
-
-
-//**********************************************************************
-//
-// VarDecCmp - Decimal Compare
-//
-//**********************************************************************
-
-STDAPI VarDecCmp(LPDECIMAL pdecL, LPDECIMAL pdecR)
-{
- ULONG ulSgnL;
- ULONG ulSgnR;
-
- // First check signs and whether either are zero. If both are
- // non-zero and of the same sign, just use subtraction to compare.
- //
- ulSgnL = pdecL->v.v.Lo32 | pdecL->v.v.Mid32 | pdecL->Hi32;
- ulSgnR = pdecR->v.v.Lo32 | pdecR->v.v.Mid32 | pdecR->Hi32;
- if (ulSgnL != 0)
- ulSgnL = (pdecL->u.u.sign & DECIMAL_NEG) | 1;
-
- if (ulSgnR != 0)
- ulSgnR = (pdecR->u.u.sign & DECIMAL_NEG) | 1;
-
- // ulSgnL & ulSgnR have values 1, 0, or 0x81 depending on if the left/right
- // operand is +, 0, or -.
- //
- if (ulSgnL == ulSgnR) {
- if (ulSgnL == 0) // both are zero
- return VARCMP_EQ; // return equal
-
- DECIMAL decRes;
-
- DecAddSub(pdecL, pdecR, &decRes, DECIMAL_NEG);
- if (DECIMAL_LO64_GET(decRes) == 0 && decRes.Hi32 == 0)
- return VARCMP_EQ;
- if (decRes.u.u.sign & DECIMAL_NEG)
- return VARCMP_LT;
- return VARCMP_GT;
- }
-
- // Signs are different. Used signed byte compares
- //
- if ((char)ulSgnL > (char)ulSgnR)
- return VARCMP_GT;
- return VARCMP_LT;
-}
-
-STDAPI VarDecRound(LPDECIMAL pdecIn, int cDecimals, LPDECIMAL pdecRes)
-{
- ULONG rgulNum[3];
- ULONG ulRem;
- ULONG ulSticky;
- ULONG ulPwr;
- int iScale;
-
- if (cDecimals < 0)
- return E_INVALIDARG;
-
- iScale = pdecIn->u.u.scale - cDecimals;
- if (iScale > 0)
- {
- rgulNum[0] = pdecIn->v.v.Lo32;
- rgulNum[1] = pdecIn->v.v.Mid32;
- rgulNum[2] = pdecIn->Hi32;
- pdecRes->u.u.sign = pdecIn->u.u.sign;
- ulRem = ulSticky = 0;
-
- do {
- ulSticky |= ulRem;
- if (iScale > POWER10_MAX)
- ulPwr = ulTenToNine;
- else
- ulPwr = rgulPower10[iScale];
-
- ulRem = Div96By32(rgulNum, ulPwr);
- iScale -= 9;
- }while (iScale > 0);
-
- // Now round. ulRem has last remainder, ulSticky has sticky bits.
- // To do IEEE rounding, we add LSB of result to sticky bits so
- // either causes round up if remainder * 2 == last divisor.
- //
- ulSticky |= rgulNum[0] & 1;
- ulRem = (ulRem << 1) + (ulSticky != 0);
- if (ulPwr < ulRem &&
- ++rgulNum[0] == 0 &&
- ++rgulNum[1] == 0
- )
- ++rgulNum[2];
-
- pdecRes->v.v.Lo32 = rgulNum[0];
- pdecRes->v.v.Mid32 = rgulNum[1];
- pdecRes->Hi32 = rgulNum[2];
- pdecRes->u.u.scale = cDecimals;
- return NOERROR;
- }
-
- COPYDEC(*pdecRes, *pdecIn)
- return NOERROR;
-}
diff --git a/src/palrt/decconv.cpp b/src/palrt/decconv.cpp
deleted file mode 100644
index 9cb7575b04..0000000000
--- a/src/palrt/decconv.cpp
+++ /dev/null
@@ -1,602 +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: decconv.cpp
-//
-// ===========================================================================
-/***
-*
-*Purpose:
-* This module contains the low level conversion for Decimal data type.
-*
-*Implementation Notes:
-*
-*****************************************************************************/
-
-#include "common.h"
-#include "convert.h"
-
-#include <oleauto.h>
-#include <math.h>
-#include <limits.h>
-
-#define VALIDATEDECIMAL(dec) \
- if (DECIMAL_SCALE(dec) > DECMAX || (DECIMAL_SIGN(dec) & ~DECIMAL_NEG) != 0) \
- return E_INVALIDARG;
-
-#define RESULT(X) ((HRESULT)(X))
-
-//***********************************************************************
-//
-// Data tables
-//
-
-const double dblPower10[] = {
- 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
- 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
- 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
- 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
- 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
- 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
- 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
- 1e80 };
-
-double fnDblPower10(int ix)
-{
- const int maxIx = (sizeof(dblPower10)/sizeof(dblPower10[0]));
- _ASSERTE(ix >= 0);
- if (ix < maxIx)
- return dblPower10[ix];
- return pow(10.0, ix);
-} // double fnDblPower10()
-
-#define DBLBIAS 1022
-#define SNGBIAS 126
-#define DECMAX 28
-
-const SPLIT64 sdlTenToEighteen = { UI64(1000000000000000000) };
-const DBLSTRUCT ds2to64 = DEFDS(0, 0, DBLBIAS + 65, 0);
-
-//***********************************************************************
-//
-// Data tables
-//
-
-const SPLIT64 sdlPower10[] = { {UI64(10000000000)}, // 1E10
- {UI64(100000000000)}, // 1E11
- {UI64(1000000000000)}, // 1E12
- {UI64(10000000000000)}, // 1E13
- {UI64(100000000000000)} }; // 1E14
-
-const unsigned __int64 ulPower10[] = {1,
- UI64(10),
- UI64(100),
- UI64(1000),
- UI64(10000),
- UI64(100000),
- UI64(1000000),
- UI64(10000000),
- UI64(100000000),
- UI64(1000000000),
- UI64(10000000000),
- UI64(100000000000),
- UI64(1000000000000),
- UI64(10000000000000),
- UI64(100000000000000),
- UI64(1000000000000000),
- UI64(10000000000000000),
- UI64(100000000000000000),
- UI64(1000000000000000000),
- UI64(10000000000000000000)};
-
-DWORDLONG UInt64x64To128(SPLIT64 sdlOp1, SPLIT64 sdlOp2, DWORDLONG *pdlHi)
-{
- SPLIT64 sdlTmp1;
- SPLIT64 sdlTmp2;
- SPLIT64 sdlTmp3;
-
- sdlTmp1.int64 = UInt32x32To64(sdlOp1.u.Lo, sdlOp2.u.Lo); // lo partial prod
- sdlTmp2.int64 = UInt32x32To64(sdlOp1.u.Lo, sdlOp2.u.Hi); // mid 1 partial prod
- sdlTmp1.u.Hi += sdlTmp2.u.Lo;
- if (sdlTmp1.u.Hi < sdlTmp2.u.Lo) // test for carry
- sdlTmp2.u.Hi++;
- sdlTmp3.int64 = UInt32x32To64(sdlOp1.u.Hi, sdlOp2.u.Hi) + (DWORDLONG)sdlTmp2.u.Hi;
- sdlTmp2.int64 = UInt32x32To64(sdlOp1.u.Hi, sdlOp2.u.Lo);
- sdlTmp1.u.Hi += sdlTmp2.u.Lo;
- if (sdlTmp1.u.Hi < sdlTmp2.u.Lo) // test for carry
- sdlTmp2.u.Hi++;
- sdlTmp3.int64 += (DWORDLONG)sdlTmp2.u.Hi;
-
- *pdlHi = sdlTmp3.int64;
- return sdlTmp1.int64;
-}
-
-
-//***********************************************************************
-//
-// Conversion to/from Decimal data type
-//
-
-
-STDAPI
-VarDecFromR4(float fltIn, DECIMAL FAR* pdecOut)
-{
- int iExp; // number of bits to left of binary point
- int iPower;
- ULONG ulMant;
- double dbl;
- SPLIT64 sdlLo;
- SPLIT64 sdlHi;
- int lmax, cur; // temps used during scale reduction
-
- // 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 ( (iExp = ((SNGSTRUCT *)&fltIn)->exp - SNGBIAS) < -94 )
- {
- DECIMAL_SETZERO(*pdecOut);
- return NOERROR;
- }
-
- if (iExp > 96)
- return RESULT(DISP_E_OVERFLOW);
-
- // Round the input to a 7-digit integer. The R4 format has
- // only 7 digits of precision, and we want to keep garbage digits
- // out of the Decimal were making.
- //
- // Calculate max power of 10 input value could have by multiplying
- // the exponent by log10(2). Using scaled integer multiplcation,
- // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
- //
- dbl = fabs(fltIn);
- iPower = 6 - ((iExp * 19728) >> 16);
-
- if (iPower >= 0) {
- // We have less than 7 digits, scale input up.
- //
- if (iPower > DECMAX)
- iPower = DECMAX;
-
- dbl = dbl * dblPower10[iPower];
- }
- else {
- if (iPower != -1 || dbl >= 1E7)
- dbl = dbl / fnDblPower10(-iPower);
- else
- iPower = 0; // didn't scale it
- }
-
- _ASSERTE(dbl < 1E7);
- if (dbl < 1E6 && iPower < DECMAX)
- {
- dbl *= 10;
- iPower++;
- _ASSERTE(dbl >= 1E6);
- }
-
- // Round to integer
- //
- ulMant = (LONG)dbl;
- dbl -= (double)ulMant; // difference between input & integer
- if ( dbl > 0.5 || (dbl == 0.5 && (ulMant & 1)) )
- ulMant++;
-
- if (ulMant == 0)
- {
- DECIMAL_SETZERO(*pdecOut);
- return NOERROR;
- }
-
- if (iPower < 0) {
- // Add -iPower factors of 10, -iPower <= (29 - 7) = 22.
- //
- iPower = -iPower;
- if (iPower < 10) {
- sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower]);
-
- DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
- DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
- DECIMAL_HI32(*pdecOut) = 0;
- }
- else {
- // Have a big power of 10.
- //
- if (iPower > 18) {
- sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower - 18]);
- sdlLo.int64 = UInt64x64To128(sdlLo, sdlTenToEighteen, &sdlHi.int64);
-
- if (sdlHi.u.Hi != 0)
- return RESULT(DISP_E_OVERFLOW);
- }
- else {
- sdlLo.int64 = UInt32x32To64(ulMant, (ULONG)ulPower10[iPower - 9]);
- sdlHi.int64 = UInt32x32To64(ulTenToNine, sdlLo.u.Hi);
- sdlLo.int64 = UInt32x32To64(ulTenToNine, sdlLo.u.Lo);
- sdlHi.int64 += sdlLo.u.Hi;
- sdlLo.u.Hi = sdlHi.u.Lo;
- sdlHi.u.Lo = sdlHi.u.Hi;
- }
- DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
- DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
- DECIMAL_HI32(*pdecOut) = sdlHi.u.Lo;
- }
- DECIMAL_SCALE(*pdecOut) = 0;
- }
- else {
- // Factor out powers of 10 to reduce the scale, if possible.
- // The maximum number we could factor out would be 6. This
- // comes from the fact we have a 7-digit number, and the
- // MSD must be non-zero -- but the lower 6 digits could be
- // zero. Note also the scale factor is never negative, so
- // we can't scale by any more than the power we used to
- // get the integer.
- //
- // DivMod32by32 returns the quotient in Lo, the remainder in Hi.
- //
- lmax = min(iPower, 6);
-
- // lmax is the largest power of 10 to try, lmax <= 6.
- // We'll try powers 4, 2, and 1 unless they're too big.
- //
- for (cur = 4; cur > 0; cur >>= 1)
- {
- if (cur > lmax)
- continue;
-
- sdlLo.int64 = DivMod32by32(ulMant, (ULONG)ulPower10[cur]);
-
- if (sdlLo.u.Hi == 0) {
- ulMant = sdlLo.u.Lo;
- iPower -= cur;
- lmax -= cur;
- }
- }
- DECIMAL_LO32(*pdecOut) = ulMant;
- DECIMAL_MID32(*pdecOut) = 0;
- DECIMAL_HI32(*pdecOut) = 0;
- DECIMAL_SCALE(*pdecOut) = iPower;
- }
-
- DECIMAL_SIGN(*pdecOut) = (char)((SNGSTRUCT *)&fltIn)->sign << 7;
- return NOERROR;
-}
-
-STDAPI
-VarDecFromR8(double dblIn, DECIMAL FAR* pdecOut)
-{
- int iExp; // number of bits to left of binary point
- int iPower; // power-of-10 scale factor
- SPLIT64 sdlMant;
- SPLIT64 sdlLo;
- double dbl;
- int lmax, cur; // temps used during scale reduction
- ULONG ulPwrCur;
- ULONG ulQuo;
-
-
- // 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 ( (iExp = ((DBLSTRUCT *)&dblIn)->u.exp - DBLBIAS) < -94 )
- {
- DECIMAL_SETZERO(*pdecOut);
- return NOERROR;
- }
-
- if (iExp > 96)
- return RESULT(DISP_E_OVERFLOW);
-
- // Round the input to a 15-digit integer. The R8 format has
- // only 15 digits of precision, and we want to keep garbage digits
- // out of the Decimal were making.
- //
- // Calculate max power of 10 input value could have by multiplying
- // the exponent by log10(2). Using scaled integer multiplcation,
- // log10(2) * 2 ^ 16 = .30103 * 65536 = 19728.3.
- //
- dbl = fabs(dblIn);
- iPower = 14 - ((iExp * 19728) >> 16);
-
- if (iPower >= 0) {
- // We have less than 15 digits, scale input up.
- //
- if (iPower > DECMAX)
- iPower = DECMAX;
-
- dbl = dbl * dblPower10[iPower];
- }
- else {
- if (iPower != -1 || dbl >= 1E15)
- dbl = dbl / fnDblPower10(-iPower);
- else
- iPower = 0; // didn't scale it
- }
-
- _ASSERTE(dbl < 1E15);
- if (dbl < 1E14 && iPower < DECMAX)
- {
- dbl *= 10;
- iPower++;
- _ASSERTE(dbl >= 1E14);
- }
-
- // Round to int64
- //
- sdlMant.int64 = (LONGLONG)dbl;
- dbl -= (double)(LONGLONG)sdlMant.int64; // dif between input & integer
- if ( dbl > 0.5 || (dbl == 0.5 && (sdlMant.u.Lo & 1)) )
- sdlMant.int64++;
-
- if (sdlMant.int64 == 0)
- {
- DECIMAL_SETZERO(*pdecOut);
- return NOERROR;
- }
-
- if (iPower < 0) {
- // Add -iPower factors of 10, -iPower <= (29 - 15) = 14.
- //
- iPower = -iPower;
- if (iPower < 10) {
- sdlLo.int64 = UInt32x32To64(sdlMant.u.Lo, (ULONG)ulPower10[iPower]);
- sdlMant.int64 = UInt32x32To64(sdlMant.u.Hi, (ULONG)ulPower10[iPower]);
- sdlMant.int64 += sdlLo.u.Hi;
- sdlLo.u.Hi = sdlMant.u.Lo;
- sdlMant.u.Lo = sdlMant.u.Hi;
- }
- else {
- // Have a big power of 10.
- //
- _ASSERTE(iPower <= 14);
- sdlLo.int64 = UInt64x64To128(sdlMant, sdlPower10[iPower-10], &sdlMant.int64);
-
- if (sdlMant.u.Hi != 0)
- return RESULT(DISP_E_OVERFLOW);
- }
- DECIMAL_LO32(*pdecOut) = sdlLo.u.Lo;
- DECIMAL_MID32(*pdecOut) = sdlLo.u.Hi;
- DECIMAL_HI32(*pdecOut) = sdlMant.u.Lo;
- DECIMAL_SCALE(*pdecOut) = 0;
- }
- else {
- // Factor out powers of 10 to reduce the scale, if possible.
- // The maximum number we could factor out would be 14. This
- // comes from the fact we have a 15-digit number, and the
- // MSD must be non-zero -- but the lower 14 digits could be
- // zero. Note also the scale factor is never negative, so
- // we can't scale by any more than the power we used to
- // get the integer.
- //
- // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
- //
- lmax = min(iPower, 14);
-
- // lmax is the largest power of 10 to try, lmax <= 14.
- // We'll try powers 8, 4, 2, and 1 unless they're too big.
- //
- for (cur = 8; cur > 0; cur >>= 1)
- {
- if (cur > lmax)
- continue;
-
- ulPwrCur = (ULONG)ulPower10[cur];
-
- if (sdlMant.u.Hi >= ulPwrCur) {
- // Overflow if we try to divide in one step.
- //
- sdlLo.int64 = DivMod64by32(sdlMant.u.Hi, ulPwrCur);
- ulQuo = sdlLo.u.Lo;
- sdlLo.u.Lo = sdlMant.u.Lo;
- sdlLo.int64 = DivMod64by32(sdlLo.int64, ulPwrCur);
- }
- else {
- ulQuo = 0;
- sdlLo.int64 = DivMod64by32(sdlMant.int64, ulPwrCur);
- }
-
- if (sdlLo.u.Hi == 0) {
- sdlMant.u.Hi = ulQuo;
- sdlMant.u.Lo = sdlLo.u.Lo;
- iPower -= cur;
- lmax -= cur;
- }
- }
-
- DECIMAL_HI32(*pdecOut) = 0;
- DECIMAL_SCALE(*pdecOut) = iPower;
- DECIMAL_LO32(*pdecOut) = sdlMant.u.Lo;
- DECIMAL_MID32(*pdecOut) = sdlMant.u.Hi;
- }
-
- DECIMAL_SIGN(*pdecOut) = (char)((DBLSTRUCT *)&dblIn)->u.sign << 7;
- return NOERROR;
-}
-
-STDAPI
-VarDecFromCy(CY cyIn, DECIMAL FAR* pdecOut)
-{
- DECIMAL_SIGN(*pdecOut) = (UCHAR)((cyIn.u.Hi >> 24) & DECIMAL_NEG);
- if (DECIMAL_SIGN(*pdecOut))
- cyIn.int64 = -cyIn.int64;
-
- DECIMAL_LO32(*pdecOut) = cyIn.u.Lo;
- DECIMAL_MID32(*pdecOut) = cyIn.u.Hi;
- DECIMAL_SCALE(*pdecOut) = 4;
- DECIMAL_HI32(*pdecOut) = 0;
- return NOERROR;
-}
-
-STDAPI VarR4FromDec(DECIMAL FAR* pdecIn, float FAR* pfltOut)
-{
- double dbl;
-
- VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
- // Can't overflow; no errors possible.
- //
- VarR8FromDec(pdecIn, &dbl);
- *pfltOut = (float)dbl;
- return NOERROR;
-}
-
-STDAPI VarR8FromDec(DECIMAL FAR* pdecIn, double FAR* pdblOut)
-{
- SPLIT64 sdlTmp;
- double dbl;
-
- VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
- sdlTmp.u.Lo = DECIMAL_LO32(*pdecIn);
- sdlTmp.u.Hi = DECIMAL_MID32(*pdecIn);
-
- if ( (LONG)DECIMAL_MID32(*pdecIn) < 0 )
- dbl = (ds2to64.dbl + (double)(LONGLONG)sdlTmp.int64 +
- (double)DECIMAL_HI32(*pdecIn) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*pdecIn)) ;
- else
- dbl = ((double)(LONGLONG)sdlTmp.int64 +
- (double)DECIMAL_HI32(*pdecIn) * ds2to64.dbl) / fnDblPower10(DECIMAL_SCALE(*pdecIn));
-
- if (DECIMAL_SIGN(*pdecIn))
- dbl = -dbl;
-
- *pdblOut = dbl;
- return NOERROR;
-}
-
-STDAPI VarCyFromDec(DECIMAL FAR* pdecIn, CY FAR* pcyOut)
-{
- SPLIT64 sdlTmp;
- SPLIT64 sdlTmp1;
- int scale;
- ULONG ulPwr;
- ULONG ul;
-
- VALIDATEDECIMAL(*pdecIn); // E_INVALIDARG check
-
- scale = DECIMAL_SCALE(*pdecIn) - 4; // the power of 10 to divide by
-
- if (scale == 0) {
- // No scaling needed -- the Decimal has 4 decimal places,
- // just what Currency needs.
- //
- if ( DECIMAL_HI32(*pdecIn) != 0 ||
- (DECIMAL_MID32(*pdecIn) >= 0x80000000 &&
- (DECIMAL_MID32(*pdecIn) != 0x80000000 || DECIMAL_LO32(*pdecIn) != 0 || !DECIMAL_SIGN(*pdecIn))) )
- return RESULT(DISP_E_OVERFLOW);
-
- sdlTmp.u.Lo = DECIMAL_LO32(*pdecIn);
- sdlTmp.u.Hi = DECIMAL_MID32(*pdecIn);
-
- if (DECIMAL_SIGN(*pdecIn))
- pcyOut->int64 = -(LONGLONG)sdlTmp.int64;
- else
- pcyOut->int64 = sdlTmp.int64;
- return NOERROR;
- }
-
- // Need to scale to get 4 decimal places. -4 <= scale <= 24.
- //
- if (scale < 0) {
- sdlTmp1.int64 = UInt32x32To64((ULONG)ulPower10[-scale], DECIMAL_MID32(*pdecIn));
- sdlTmp.int64 = UInt32x32To64((ULONG)ulPower10[-scale], DECIMAL_LO32(*pdecIn));
- sdlTmp.u.Hi += sdlTmp1.u.Lo;
- if (DECIMAL_HI32(*pdecIn) != 0 || sdlTmp1.u.Hi != 0 || sdlTmp1.u.Lo > sdlTmp.u.Hi)
- return RESULT(DISP_E_OVERFLOW);
- }
- else if (scale < 10) {
- // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
- //
- ulPwr = (ULONG)ulPower10[scale];
- if (DECIMAL_HI32(*pdecIn) >= ulPwr)
- return RESULT(DISP_E_OVERFLOW);
- sdlTmp1.u.Lo = DECIMAL_MID32(*pdecIn);
- sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn);
- sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulPwr);
- sdlTmp.u.Hi = sdlTmp1.u.Lo; // quotient to high half of result
- sdlTmp1.u.Lo = DECIMAL_LO32(*pdecIn); // extended remainder
- sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulPwr);
- sdlTmp.u.Lo = sdlTmp1.u.Lo; // quotient to low half of result
-
- // Round result based on remainder in sdlTmp1.Hi.
- //
- ulPwr >>= 1; // compare to power/2 (power always even)
- if (sdlTmp1.u.Hi > ulPwr || (sdlTmp1.u.Hi == ulPwr && (sdlTmp.u.Lo & 1)))
- sdlTmp.int64++;
- }
- else {
- // We have a power of 10 in the range 10 - 24. These powers do
- // not fit in 32 bits. We'll handle this by scaling 2 or 3 times,
- // first by 10^10, then by the remaining amount (or 10^9, then
- // the last bit).
- //
- // To scale by 10^10, we'll actually divide by 10^10/4, which fits
- // in 32 bits. The second scaling is multiplied by four
- // to account for it, just barely assured of fitting in 32 bits
- // (4E9 < 2^32). Note that the upper third of the quotient is
- // either zero or one, so we skip the divide step to calculate it.
- // (Max 4E9 divided by 2.5E9.)
- //
- // DivMod64by32 returns the quotient in Lo, the remainder in Hi.
- //
- if (DECIMAL_HI32(*pdecIn) >= ulTenToTenDiv4) {
- sdlTmp.u.Hi = 1; // upper 1st quotient
- sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn) - ulTenToTenDiv4; // remainder
- }
- else {
- sdlTmp.u.Hi = 0; // upper 1st quotient
- sdlTmp1.u.Hi = DECIMAL_HI32(*pdecIn); // remainder
- }
- sdlTmp1.u.Lo = DECIMAL_MID32(*pdecIn); // extended remainder
- sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulTenToTenDiv4);
- sdlTmp.u.Lo = sdlTmp1.u.Lo; // middle 1st quotient
-
- sdlTmp1.u.Lo = DECIMAL_LO32(*pdecIn); // extended remainder
- sdlTmp1.int64 = DivMod64by32(sdlTmp1.int64, ulTenToTenDiv4);
-
- ulPwr = (ULONG)(ulPower10[min(scale-10, 9)] << 2);
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
- ul = sdlTmp.u.Lo; // upper 2nd quotient
-
- sdlTmp.u.Lo = sdlTmp1.u.Lo; // extended remainder
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
- sdlTmp1.u.Lo = sdlTmp.u.Hi; // save final remainder
- sdlTmp.u.Hi = ul; // position high result
-
- if (scale >= 20) {
- ulPwr = (ULONG)(ulPower10[scale-19]);
- sdlTmp.int64 = DivMod64by32(sdlTmp.int64, ulPwr);
- sdlTmp1.u.Hi |= sdlTmp1.u.Lo; // combine sticky bits
- sdlTmp1.u.Lo = sdlTmp.u.Hi; // final remainder
- sdlTmp.u.Hi = 0; // guaranteed result fits in 32 bits
- }
-
- // Round result based on remainder in sdlTmp1.Lo. sdlTmp1.Hi is
- // the remainder from the first division(s), representing sticky bits.
- // Current result is in sdlTmp.
- //
- ulPwr >>= 1; // compare to power/2 (power always even)
- if (sdlTmp1.u.Lo > ulPwr || (sdlTmp1.u.Lo == ulPwr &&
- ((sdlTmp.u.Lo & 1) || sdlTmp1.u.Hi != 0)))
- sdlTmp.int64++;
- }
-
- if (sdlTmp.u.Hi >= 0x80000000 &&
- (sdlTmp.int64 != UI64(0x8000000000000000) || !DECIMAL_SIGN(*pdecIn)))
- return RESULT(DISP_E_OVERFLOW);
-
- if (DECIMAL_SIGN(*pdecIn))
- sdlTmp.int64 = -(LONGLONG)sdlTmp.int64;
-
- pcyOut->int64 = sdlTmp.int64;
- return NOERROR;
-}
-
-