private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate) { if (n.IsNull) return SqlDecimal.Null; if (lPosition >= 0) { //If round to the right of decimal number lPosition = Math.Min(s_NUMERIC_MAX_PRECISION, lPosition); if (lPosition >= n.m_bScale) return n; //No need to round } else { //If round to the left of the decimal point lPosition = Math.Max(-s_NUMERIC_MAX_PRECISION, lPosition); //Return +0.00 if truncation of integer part if (lPosition < n.m_bScale - n.m_bPrec) { n.SetToZero(); return n; } } uint ulRem = 0; // Remainder: the highest significant digit to be truncated int lAdjust = Math.Abs(lPosition - (int)n.m_bScale); // Precision adjustment uint ulLastDivBase = 1; // //Compute the integral part of the numeric while (lAdjust > 0) { if (lAdjust >= 9) { ulRem = n.DivByULong(s_rgulShiftBase[8]); ulLastDivBase = s_rgulShiftBase[8]; lAdjust -= 9; } else { ulRem = n.DivByULong(s_rgulShiftBase[lAdjust - 1]); ulLastDivBase = s_rgulShiftBase[lAdjust - 1]; lAdjust = 0; } } // The rounding only depends on the first digit after the rounding position if (ulLastDivBase > 1) { ulRem /= (ulLastDivBase / 10); } //If result is zero, return if (n.FZero() && (fTruncate || ulRem < 5)) { n.SetPositive(); n.AssertValid(); return n; } // Adjust by adding 1 if remainder is larger than 5 if (ulRem >= 5 && !fTruncate) n.AddULong(1); // Convert back to original scale lAdjust = Math.Abs(lPosition - n.m_bScale); while (lAdjust-- > 0) { n.MultByULong(s_ulBase10); } n.AssertValid(); return n; }
//----------------------------------------------------------- //DivNm(): // Divide numeric by numeric. // The Quotient will be returned in *this // //Result scale & precision: // NOTE: same as in Hydra but different from SQL Server Manual, // where scale = max(s1+p2-s2+1,x_cNumeDivScaleMin)): // scale = max(s1 + p2 + 1, x_cNumeDivScaleMin); // precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1; // //Overflow Rules: // If scale is greater than NUMERIC_MAX_PRECISION it is set to // NUMERIC_MAX_PRECISION. If precision is greater than NUMERIC_MAX_PRECISION // it's set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the // integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin. // For example, if using the above formula, the resulting precision is 46 and // scale is 10, the precision will be reduced to 38, to keep the integral part // untruncated the scale needs be reduced to 2, but since x_cNumeDivScaleMin // is set to 6 currently, resulting scale will be 6. // OverflowException is thrown only if the actual precision is greater than // NUMERIC_MAX_PRECISION or actual length is greater than x_cbNumeBuf // //Algorithm // Call general purpose arbitrary precision division routine with scale = 0. // Scale,prec adjusted later. // /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) return Null; x.AssertValid(); y.AssertValid(); // Variables for figuring prec,scale int bScaleD; // Input Scale of dividend (output scale of remainder) int bPrecD; // Input Prec of dividend (output prec of remainder) int ResScale; // Final scale we will force quotient to int ResPrec; // Final precision we will force quotient to int ResInteger; // # of digits in integer part of result (prec-scale) int MinScale; // Temp to help compute ResScale int lScaleAdjust; // How much result scale will be adjusted bool fResSignPos; // sign of result // Steps: // 1) Figure result prec,scale; adjust scale of dividend // 2) Compute result remainder/quotient in 0 scale numbers // 3) Set result prec,scale and adjust as necessary // 0) Check for Div by 0 if (y.FZero()) throw new DivideByZeroException(SQLResource.DivideByZeroMessage); // 1) Figure out result prec,scale,sign.. fResSignPos = (x.IsPositive == y.IsPositive);//sign of result //scale = max(s1 + p2 + 1, x_cNumeDivScaleMin); //precision = max(s1 + p2 + 1, x_cNumeDivScaleMin) + p1 + p2 + 1; //For backward compatibility, use exactly the same scheme as in Hydra bScaleD = x.m_bScale; bPrecD = x.m_bPrec; ResScale = Math.Max(x.m_bScale + y.m_bPrec + 1, s_cNumeDivScaleMin); ResInteger = x.m_bPrec - x.m_bScale + y.m_bScale; MinScale = Math.Min(ResScale, s_cNumeDivScaleMin); ResInteger = Math.Min(ResInteger, s_NUMERIC_MAX_PRECISION); ResPrec = ResInteger + ResScale; if (ResPrec > s_NUMERIC_MAX_PRECISION) ResPrec = s_NUMERIC_MAX_PRECISION; // If overflow, reduce the scale to avoid truncation of data ResScale = Math.Min((ResPrec - ResInteger), ResScale); ResScale = Math.Max(ResScale, MinScale); //Adjust the scale of the dividend lScaleAdjust = ResScale - (int)x.m_bScale + (int)y.m_bScale; x.AdjustScale(lScaleAdjust, true); // Step2: Actual Computation uint[] rgulData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] rgulData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; // Buffers for arbitrary precision divide uint[] rgulR = new uint[s_cNumeMax + 1]; uint[] rgulQ = new uint[s_cNumeMax]; // # of ULONGs in result int culQ, culR; // Divide mantissas. V is not zero - already checked. // Cannot overflow, as Q <= U, R <= V. (and both are positive) MpDiv(rgulData1, x.m_bLen, rgulData2, y.m_bLen, rgulQ, out culQ, rgulR, out culR); // Construct the result from Q ZeroToMaxLen(rgulQ, culQ); SqlDecimal ret = new SqlDecimal(rgulQ, (byte)culQ, (byte)ResPrec, (byte)ResScale, fResSignPos); if (ret.FZero()) ret.SetPositive(); ret.AssertValid(); return ret; }
// Floor - next largest integer smaller or equal to the numeric /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public static SqlDecimal Floor(SqlDecimal n) { n.AssertValid(); if (n.IsNull) return SqlDecimal.Null; if (n.m_bScale == 0) return n; bool fFraction; //Fractional flag n.MakeInteger(out fFraction); //When the numeric has fraction and is negative, subtract 1 by calling AddULong(1) //Otherwise return the integral part. if (fFraction && !n.IsPositive) { n.AddULong(1); } if (n.FZero())//if result is zero, sign should be positive n.SetPositive(); n.AssertValid(); return n; }
// Binary operators // Arithmetic operators /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) return Null; ulong dwlAccum; //accumulated sum bool fMySignPos; //sign of x was positive at start bool fOpSignPos; // sign of y positive at start bool fResSignPos = true; //sign of result should be positive int MyScale; //scale of x int OpScale; //scale of y int ResScale; //scale of result int ResPrec; //precision of result int ResInteger; //number of digits for the integer part of result int culOp1; //# of UI4s in x int culOp2; //# of UI4s in y int iulData; //which UI4 we are operating on in x, y byte bLen; // length for the result x.AssertValid(); y.AssertValid(); fMySignPos = x.IsPositive; fOpSignPos = y.IsPositive; //result scale = max(s1,s2) //result precision = max(s1,s2) + max(p1-s1,p2-s2) MyScale = x.m_bScale; OpScale = y.m_bScale; // Calculate the integer part of the result. ResInteger = Math.Max((int)x.m_bPrec - MyScale, (int)y.m_bPrec - OpScale); Debug.Assert(ResInteger <= MaxPrecision); // Calculate the scale of the result. ResScale = Math.Max(MyScale, OpScale); Debug.Assert(ResScale <= MaxScale); // Calculate the precision of the result. // Add 1 for final carry. ResPrec = ResInteger + ResScale + 1; ResPrec = Math.Min(MaxPrecision, ResPrec); // If precision adjusted, scale is reduced to keep the integer part untruncated. // But discard the extra carry, only keep the integer part as ResInteger, not ResInteger + 1. Debug.Assert(ResPrec - ResInteger >= 0); if (ResPrec - ResInteger < ResScale) ResScale = ResPrec - ResInteger; // Adjust both operands to be the same scale as ResScale. if (MyScale != ResScale) x.AdjustScale(ResScale - MyScale, true); if (OpScale != ResScale) y.AdjustScale(ResScale - OpScale, true); // When sign of first operand is negative // negate all operands including result. if (!fMySignPos) { fMySignPos = !fMySignPos; fOpSignPos = !fOpSignPos; fResSignPos = !fResSignPos; } // Initialize operand lengths and pointer. culOp1 = x.m_bLen; culOp2 = y.m_bLen; uint[] rglData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] rglData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; if (fOpSignPos) { dwlAccum = 0; // CONSIDER: Call AddUlong when possible // Loop through UI4s adding operands and putting result in *this // of the operands and put result in *this for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++) { // None of these DWORDLONG additions can overflow, as dwlAccum comes in < x_lInt32Base if (iulData < culOp1) dwlAccum += rglData1[iulData]; if (iulData < culOp2) dwlAccum += rglData2[iulData]; rglData1[iulData] = (uint)dwlAccum; // equiv to mod x_lInt32Base dwlAccum >>= 32; // equiv to div x_lInt32Base } //If carry if (dwlAccum != 0) { Debug.Assert(dwlAccum < s_ulInt32Base); //Either overflowed if (iulData == s_cNumeMax) throw new OverflowException(SQLResource.ArithOverflowMessage); // Or extended length rglData1[iulData] = (uint)dwlAccum; iulData++; } // Set result length bLen = (byte)iulData; } else { int iulLastNonZero = 0; // The last nonzero UI // When second operand is negative, switch operands // if operand2 is greater than operand1 if (x.LAbsCmp(y) < 0) { fResSignPos = !fResSignPos; uint[] rguiTemp = rglData2; rglData2 = rglData1; rglData1 = rguiTemp; culOp1 = culOp2; culOp2 = x.m_bLen; } dwlAccum = s_ulInt32Base; for (iulData = 0; iulData < culOp1 || iulData < culOp2; iulData++) { if (iulData < culOp1) dwlAccum += rglData1[iulData]; if (iulData < culOp2) dwlAccum -= rglData2[iulData]; rglData1[iulData] = (uint)dwlAccum; // equiv to mod BaseUI4 if (rglData1[iulData] != 0) iulLastNonZero = iulData; dwlAccum >>= 32; // equiv to /= BaseUI4 dwlAccum += s_ulInt32BaseForMod; // equiv to BaseUI4 - 1 } // Set length based on highest non-zero ULONG bLen = (byte)(iulLastNonZero + 1); } SqlDecimal ret = new SqlDecimal(rglData1, bLen, (byte)ResPrec, (byte)ResScale, fResSignPos); if (ret.FGt10_38() || ret.CalculatePrecision() > s_NUMERIC_MAX_PRECISION) throw new OverflowException(SQLResource.ArithOverflowMessage); if (ret.FZero()) ret.SetPositive(); ret.AssertValid(); return ret; }
// MultNm() // // Multiply two numerics. // // Parameters: // x - IN Multiplier // y - IN Multiplicand // // Result scale and precision(same as in SQL Server Manual and Hydra): // scale = s1 + s2 // precision = s1 + s2 + (p1 - s1) + (p2 - s2) + 1 // // Overflow Rules: // If scale is greater than NUMERIC_MAX_PRECISION it is set to // NUMERIC_MAX_PRECISION. If precision is greater than NUMERIC_MAX_PRECISION // it is set to NUMERIC_MAX_PRECISION, then scale is reduced to keep the // integer part untruncated but keeping a minimum value of x_cNumeDivScaleMin. // For example, if using the above formula, the resulting precision is 46 and // scale is 10, the precision will be reduced to 38. To keep the integral part // untruncated the scale needs be reduced to 2, but since x_cNumeDivScaleMin // is set to 6 currently, resulting scale will be 6. // O_OVERFLOW is returned only if the actual precision is greater than // NUMERIC_MAX_PRECISION or the actual length is greater than x_cbNumeBuf. // // Algorithm: // Starting from the lowest significant UI4, for each UI4 of the multiplier // iterate through the UI4s of the multiplicand starting from // the least significant UI4s, multiply the multiplier UI4 with // multiplicand UI4, update the result buffer with the product modulo // x_dwlBaseUI4 at the same index as the multiplicand, and carry the quotient to // add to the next multiplicand UI4. Until the end of the multiplier data // array is reached. // /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y) { x.AssertValid(); y.AssertValid(); if (x.IsNull || y.IsNull) return Null; //Implementation: // I) Figure result scale,prec // II) Perform mult. // III) Adjust product to result scale,prec // Local variables for actual multiplication int iulPlier; //index of UI4 in the Multiplier uint ulPlier; //current multiplier UI4 ulong dwlAccum; //accumulated sum ulong dwlNextAccum; //overflow of accumulated sum int culCand = y.m_bLen; //length of multiplicand in UI4s //Local variables to track scale,precision int ActualScale; // Scale after mult done int ResScale; // Final scale we will force result to int ResPrec; // Final precision we will force result to int ResInteger; // # of digits in integer part of result (prec-scale) int lScaleAdjust; //How much result scale will be adjusted bool fResPositive; // Result sign SqlDecimal ret; //I) Figure result prec,scale ActualScale = x.m_bScale + y.m_bScale; ResScale = ActualScale; ResInteger = (x.m_bPrec - x.m_bScale) + (y.m_bPrec - y.m_bScale) + 1; //result precision = s1 + s2 + (p1 - s1) + (p2 - s2) + 1 ResPrec = ResScale + ResInteger; // Downward adjust res prec,scale if either larger than NUMERIC_MAX_PRECISION if (ResPrec > s_NUMERIC_MAX_PRECISION) ResPrec = s_NUMERIC_MAX_PRECISION; if (ResScale > s_NUMERIC_MAX_PRECISION) ResScale = s_NUMERIC_MAX_PRECISION; // // It is possible when two large numbers are being multiplied the scale // can be reduced to 0 to keep data untruncated; the fix here is to // preserve a minimum scale of 6. // // If overflow, reduce the scale to avoid truncation of data ResScale = Math.Min((ResPrec - ResInteger), ResScale); // But keep a minimum scale of NUMERIC_MIN_DVSCALE ResScale = Math.Max(ResScale, Math.Min(ActualScale, s_cNumeDivScaleMin)); lScaleAdjust = ResScale - ActualScale; fResPositive = (x.IsPositive == y.IsPositive);//positive if both signs same. // II) Perform multiplication uint[] rglData1 = new uint[4] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] rglData2 = new uint[4] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; //Local buffer to hold the result of multiplication. //Longer than CReNumeBuf because full precision of multiplication is carried out const int x_culNumeMultRes = 9; // Maximum # UI4s in result buffer in multiplication uint[] rgulRes = new uint[x_culNumeMultRes]; //new [] are already initialized to zero int culRes; // # of UI4s in result int idRes = 0; //Iterate over the bytes of multiplier for (iulPlier = 0; iulPlier < x.m_bLen; iulPlier++) { ulPlier = rglData1[iulPlier]; dwlAccum = 0; //Multiply each UI4 of multiCand by ulPliear and accumulate into result buffer // Start on correct place in result idRes = iulPlier; for (int iulCand = 0; iulCand < culCand; iulCand++) { // dwlAccum = dwlAccum + rgulRes[idRes] + ulPlier*rglData2[iulCand] // use dwlNextAccum to detect overflow of DWORDLONG dwlNextAccum = dwlAccum + rgulRes[idRes]; ulong ulTemp = (ulong)rglData2[iulCand]; dwlAccum = (ulong)ulPlier * ulTemp; dwlAccum += dwlNextAccum; if (dwlAccum < dwlNextAccum) // indicates dwl addition overflowed dwlNextAccum = s_ulInt32Base; // = maxUI64/x_dwlBaseUI4 else dwlNextAccum = 0; // Update result and accum rgulRes[idRes++] = (uint)(dwlAccum);// & x_ulInt32BaseForMod); // equiv to mod x_lInt32Base dwlAccum = (dwlAccum >> 32) + dwlNextAccum; // equiv to div BaseUI4 + dwlNAccum // dwlNextAccum can't overflow next iteration Debug.Assert(dwlAccum < s_ulInt32Base * 2); } Debug.Assert(dwlAccum < s_ulInt32Base); // can never final accum > 1 more UI4 if (dwlAccum != 0) rgulRes[idRes++] = (uint)dwlAccum; } // Skip leading 0s (may exist if we are multiplying by 0) for (; (rgulRes[idRes] == 0) && (idRes > 0); idRes--) ; // Calculate actual result length culRes = idRes + 1; // III) Adjust precision,scale to result prec,scale if (lScaleAdjust != 0) { // If need to decrease scale if (lScaleAdjust < 0) { Debug.Assert(s_NUMERIC_MAX_PRECISION == ResPrec); // have to adjust - might yet end up fitting. // Cannot call AdjustScale - number cannot fit in a numeric, so // have to duplicate code here uint ulRem; //Remainder when downshifting uint ulShiftBase; //What to multiply by to effect scale adjust do { if (lScaleAdjust <= -9) { ulShiftBase = s_rgulShiftBase[8]; lScaleAdjust += 9; } else { ulShiftBase = s_rgulShiftBase[-lScaleAdjust - 1]; lScaleAdjust = 0; } MpDiv1(rgulRes, ref culRes, ulShiftBase, out ulRem); } while (lScaleAdjust != 0); // Still do not fit? if (culRes > s_cNumeMax) throw new OverflowException(SQLResource.ArithOverflowMessage); for (idRes = culRes; idRes < s_cNumeMax; idRes++) rgulRes[idRes] = 0; ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive); // Is it greater than 10**38? if (ret.FGt10_38()) throw new OverflowException(SQLResource.ArithOverflowMessage); ret.AssertValid(); // If remainder is 5 or above, increment/decrement by 1. if (ulRem >= ulShiftBase / 2) ret.AddULong(1); // After adjusting, if the result is 0 and remainder is less than 5, // set the sign to be positive if (ret.FZero()) ret.SetPositive(); return ret; } // Otherwise call AdjustScale if (culRes > s_cNumeMax) // Do not fit now, so will not fit after adjustment throw new OverflowException(SQLResource.ArithOverflowMessage); // NOTE: Have not check for value in the range (10**38..2**128), // as we'll call AdjustScale with positive argument, and it'll // return "normal" overflow for (idRes = culRes; idRes < s_cNumeMax; idRes++) rgulRes[idRes] = 0; ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ActualScale, fResPositive); if (ret.FZero()) ret.SetPositive(); ret.AssertValid(); ret.AdjustScale(lScaleAdjust, true); return ret; } else { if (culRes > s_cNumeMax) throw new OverflowException(SQLResource.ArithOverflowMessage); for (idRes = culRes; idRes < s_cNumeMax; idRes++) rgulRes[idRes] = 0; ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, (byte)ResScale, fResPositive); // Is it greater than 10**38? if (ret.FGt10_38()) throw new OverflowException(SQLResource.ArithOverflowMessage); if (ret.FZero()) ret.SetPositive(); ret.AssertValid(); return ret; } }
public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y) { SqlDecimal num11; if (x.IsNull || y.IsNull) { return Null; } int bLen = y.m_bLen; int num10 = x.m_bScale + y.m_bScale; int num3 = num10; int num13 = ((x.m_bPrec - x.m_bScale) + (y.m_bPrec - y.m_bScale)) + 1; int num6 = num3 + num13; if (num6 > NUMERIC_MAX_PRECISION) { num6 = NUMERIC_MAX_PRECISION; } if (num3 > NUMERIC_MAX_PRECISION) { num3 = NUMERIC_MAX_PRECISION; } num3 = Math.Max(Math.Min(num6 - num13, num3), Math.Min(num10, x_cNumeDivScaleMin)); int digits = num3 - num10; bool fPositive = x.IsPositive == y.IsPositive; uint[] numArray5 = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] numArray4 = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; uint[] rgulU = new uint[9]; int index = 0; for (int i = 0; i < x.m_bLen; i++) { uint num16 = numArray5[i]; ulong num2 = 0L; index = i; for (int j = 0; j < bLen; j++) { ulong num7 = num2 + rgulU[index]; ulong num15 = numArray4[j]; num2 = num16 * num15; num2 += num7; if (num2 < num7) { num7 = x_ulInt32Base; } else { num7 = 0L; } rgulU[index++] = (uint) num2; num2 = (num2 >> 0x20) + num7; } if (num2 != 0L) { rgulU[index++] = (uint) num2; } } while ((rgulU[index] == 0) && (index > 0)) { index--; } int ciulU = index + 1; if (digits != 0) { if (digits < 0) { uint num12; uint num14; do { if (digits <= -9) { num12 = x_rgulShiftBase[8]; digits += 9; } else { num12 = x_rgulShiftBase[-digits - 1]; digits = 0; } MpDiv1(rgulU, ref ciulU, num12, out num14); } while (digits != 0); if (ciulU > x_cNumeMax) { throw new OverflowException(SQLResource.ArithOverflowMessage); } for (index = ciulU; index < x_cNumeMax; index++) { rgulU[index] = 0; } num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num3, fPositive); if (num11.FGt10_38()) { throw new OverflowException(SQLResource.ArithOverflowMessage); } if (num14 >= (num12 / 2)) { num11.AddULong(1); } if (num11.FZero()) { num11.SetPositive(); } return num11; } if (ciulU > x_cNumeMax) { throw new OverflowException(SQLResource.ArithOverflowMessage); } for (index = ciulU; index < x_cNumeMax; index++) { rgulU[index] = 0; } num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num10, fPositive); if (num11.FZero()) { num11.SetPositive(); } num11.AdjustScale(digits, true); return num11; } if (ciulU > x_cNumeMax) { throw new OverflowException(SQLResource.ArithOverflowMessage); } for (index = ciulU; index < x_cNumeMax; index++) { rgulU[index] = 0; } num11 = new SqlDecimal(rgulU, (byte) ciulU, (byte) num6, (byte) num3, fPositive); if (num11.FGt10_38()) { throw new OverflowException(SQLResource.ArithOverflowMessage); } if (num11.FZero()) { num11.SetPositive(); } return num11; }
public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y) { int num; ulong num2; byte num11; if (x.IsNull || y.IsNull) { return Null; } bool fPositive = true; bool isPositive = x.IsPositive; bool flag2 = y.IsPositive; int bScale = x.m_bScale; int num7 = y.m_bScale; int num9 = Math.Max((int) (x.m_bPrec - bScale), (int) (y.m_bPrec - num7)); int num3 = Math.Max(bScale, num7); int num6 = (num9 + num3) + 1; num6 = Math.Min(MaxPrecision, num6); if ((num6 - num9) < num3) { num3 = num6 - num9; } if (bScale != num3) { x.AdjustScale(num3 - bScale, true); } if (num7 != num3) { y.AdjustScale(num3 - num7, true); } if (!isPositive) { isPositive = !isPositive; flag2 = !flag2; fPositive = !fPositive; } int bLen = x.m_bLen; int num4 = y.m_bLen; uint[] rglData = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] numArray4 = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; if (flag2) { num2 = 0L; num = 0; while ((num < bLen) || (num < num4)) { if (num < bLen) { num2 += rglData[num]; } if (num < num4) { num2 += numArray4[num]; } rglData[num] = (uint) num2; num2 = num2 >> 0x20; num++; } if (num2 != 0L) { if (num == x_cNumeMax) { throw new OverflowException(SQLResource.ArithOverflowMessage); } rglData[num] = (uint) num2; num++; } num11 = (byte) num; } else { int num10 = 0; if (x.LAbsCmp(y) < 0) { fPositive = !fPositive; uint[] numArray5 = numArray4; numArray4 = rglData; rglData = numArray5; bLen = num4; num4 = x.m_bLen; } num2 = x_ulInt32Base; for (num = 0; (num < bLen) || (num < num4); num++) { if (num < bLen) { num2 += rglData[num]; } if (num < num4) { num2 -= numArray4[num]; } rglData[num] = (uint) num2; if (rglData[num] != 0) { num10 = num; } num2 = num2 >> 0x20; num2 += x_ulInt32BaseForMod; } num11 = (byte) (num10 + 1); } SqlDecimal num12 = new SqlDecimal(rglData, num11, (byte) num6, (byte) num3, fPositive); if (num12.FGt10_38() || (num12.CalculatePrecision() > NUMERIC_MAX_PRECISION)) { throw new OverflowException(SQLResource.ArithOverflowMessage); } if (num12.FZero()) { num12.SetPositive(); } return num12; }
private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate) { if (n.IsNull) { return Null; } if (lPosition >= 0) { lPosition = Math.Min(NUMERIC_MAX_PRECISION, lPosition); if (lPosition >= n.m_bScale) { return n; } } else { lPosition = Math.Max(-NUMERIC_MAX_PRECISION, lPosition); if (lPosition < (n.m_bScale - n.m_bPrec)) { n.SetToZero(); return n; } } uint num2 = 0; int num = Math.Abs((int) (lPosition - n.m_bScale)); uint num3 = 1; while (num > 0) { if (num >= 9) { num2 = n.DivByULong(x_rgulShiftBase[8]); num3 = x_rgulShiftBase[8]; num -= 9; } else { num2 = n.DivByULong(x_rgulShiftBase[num - 1]); num3 = x_rgulShiftBase[num - 1]; num = 0; } } if (num3 > 1) { num2 /= num3 / 10; } if (n.FZero() && (fTruncate || (num2 < 5))) { n.SetPositive(); return n; } if ((num2 >= 5) && !fTruncate) { n.AddULong(1); } num = Math.Abs((int) (lPosition - n.m_bScale)); while (num-- > 0) { n.MultByULong(x_ulBase10); } return n; }
public static SqlDecimal Floor(SqlDecimal n) { if (n.IsNull) { return Null; } if (n.m_bScale != 0) { bool flag; n.MakeInteger(out flag); if (flag && !n.IsPositive) { n.AddULong(1); } if (n.FZero()) { n.SetPositive(); } } return n; }
public static SqlDecimal operator /(SqlDecimal x, SqlDecimal y) { int num4; int num8; if (x.IsNull || y.IsNull) { return Null; } if (y.FZero()) { throw new DivideByZeroException(SQLResource.DivideByZeroMessage); } bool fPositive = x.IsPositive == y.IsPositive; int num = Math.Max((x.m_bScale + y.m_bPrec) + 1, (int) x_cNumeDivScaleMin); int num3 = (x.m_bPrec - x.m_bScale) + y.m_bScale; int num2 = ((num + x.m_bPrec) + y.m_bPrec) + 1; int num7 = Math.Min(num, x_cNumeDivScaleMin); num3 = Math.Min(num3, NUMERIC_MAX_PRECISION); num2 = num3 + num; if (num2 > NUMERIC_MAX_PRECISION) { num2 = NUMERIC_MAX_PRECISION; } num = Math.Max(Math.Min(num2 - num3, num), num7); int digits = (num - x.m_bScale) + y.m_bScale; x.AdjustScale(digits, true); uint[] rgulU = new uint[] { x.m_data1, x.m_data2, x.m_data3, x.m_data4 }; uint[] rgulD = new uint[] { y.m_data1, y.m_data2, y.m_data3, y.m_data4 }; uint[] rgulR = new uint[x_cNumeMax + 1]; uint[] rgulQ = new uint[x_cNumeMax]; MpDiv(rgulU, x.m_bLen, rgulD, y.m_bLen, rgulQ, out num4, rgulR, out num8); ZeroToMaxLen(rgulQ, num4); SqlDecimal num5 = new SqlDecimal(rgulQ, (byte) num4, (byte) num2, (byte) num, fPositive); if (num5.FZero()) { num5.SetPositive(); } return num5; }