public static SqlBoolean operator <=(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) { return(SqlBoolean.Null); } if (x.IsPositive != y.IsPositive) { return(new SqlBoolean(y.IsPositive)); } if (x.Scale > y.Scale) { y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true); } else if (y.Scale > x.Scale) { x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true); } for (int i = 3; i >= 0; i -= 1) { if (x.Data[i] == 0 && y.Data[i] == 0) { continue; } else { return(new SqlBoolean(x.Data[i] <= y.Data[i])); } } return(new SqlBoolean(true)); }
/// <summary> /// Initializes a new instance of the <see cref='SqlMoney'/> class with the value given. /// </summary> public SqlMoney(decimal value) { // Since Decimal is a value type, operate directly on value, don't worry about changing it. SqlDecimal snum = new SqlDecimal(value); snum.AdjustScale(s_iMoneyScale - snum.Scale, true); Debug.Assert(snum.Scale == s_iMoneyScale); if (snum._data3 != 0 || snum._data4 != 0) { throw new OverflowException(SQLResource.s_arithOverflowMessage); } bool fPositive = snum.IsPositive; ulong ulValue = snum._data1 + (((ulong)snum._data2) << 32); if (fPositive && ulValue > long.MaxValue || !fPositive && ulValue > unchecked ((ulong)(long.MinValue))) { throw new OverflowException(SQLResource.s_arithOverflowMessage); } _value = fPositive ? (long)ulValue : unchecked (-(long)ulValue); _fNotNull = true; }
public static SqlBoolean operator !=(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) { return(SqlBoolean.Null); } if (x.IsPositive != y.IsPositive) { return(SqlBoolean.True); } if (x.Scale > y.Scale) { x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true); } else if (y.Scale > x.Scale) { y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true); } for (int i = 0; i < 4; i += 1) { if (x.Data[i] != y.Data[i]) { return(SqlBoolean.True); } } return(SqlBoolean.False); }
public static SqlDecimal operator *(SqlDecimal x, SqlDecimal y) { // adjust the scale to the smaller of the two beforehand if (x.Scale > y.Scale) { x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true); } else if (y.Scale > x.Scale) { y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true); } return(new SqlDecimal(x.Value * y.Value)); }
public SqlMoney(decimal value) { SqlDecimal num2 = new SqlDecimal(value); num2.AdjustScale(x_iMoneyScale - num2.Scale, true); if ((num2.m_data3 != 0) || (num2.m_data4 != 0)) { throw new OverflowException(SQLResource.ArithOverflowMessage); } bool isPositive = num2.IsPositive; ulong num = num2.m_data1 + (num2.m_data2 << 0x20); if ((isPositive && (num > 0x7fffffffffffffffL)) || (!isPositive && (num > 9223372036854775808L))) { throw new OverflowException(SQLResource.ArithOverflowMessage); } this.m_value = isPositive ? ((long) num) : ((long) -num); this.m_fNotNull = true; }
/// <summary> /// Initializes a new instance of the <see cref='SqlMoney'/> class with the value given. /// </summary> public SqlMoney(decimal value) { // Since Decimal is a value type, operate directly on value, don't worry about changing it. SqlDecimal snum = new SqlDecimal(value); snum.AdjustScale(s_iMoneyScale - snum.Scale, true); Debug.Assert(snum.Scale == s_iMoneyScale); if (snum._data3 != 0 || snum._data4 != 0) throw new OverflowException(SQLResource.s_arithOverflowMessage); bool fPositive = snum.IsPositive; ulong ulValue = snum._data1 + (((ulong)snum._data2) << 32); if (fPositive && ulValue > long.MaxValue || !fPositive && ulValue > unchecked((ulong)(long.MinValue))) throw new OverflowException(SQLResource.s_arithOverflowMessage); _value = fPositive ? (long)ulValue : unchecked(-(long)ulValue); _fNotNull = true; }
public SqlMoney(decimal value) { SqlDecimal num2 = new SqlDecimal(value); num2.AdjustScale(x_iMoneyScale - num2.Scale, true); if ((num2.m_data3 != 0) || (num2.m_data4 != 0)) { throw new OverflowException(SQLResource.ArithOverflowMessage); } bool isPositive = num2.IsPositive; ulong num = num2.m_data1 + (num2.m_data2 << 0x20); if ((isPositive && (num > 0x7fffffffffffffffL)) || (!isPositive && (num > 9223372036854775808L))) { throw new OverflowException(SQLResource.ArithOverflowMessage); } this.m_value = isPositive ? ((long)num) : ((long)-num); this.m_fNotNull = true; }
// Power - Compute the power of a numeric /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public static SqlDecimal Power(SqlDecimal n, double exp) { n.AssertValid(); if (n.IsNull) return SqlDecimal.Null; byte prec = n.Precision; int scale = n.Scale; double dBaseNum = n.ToDouble(); n = new SqlDecimal(Math.Pow(dBaseNum, exp)); n.AdjustScale(scale - (int)n.Scale, true); n.m_bPrec = MaxPrecision; return n; }
// 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 Power(SqlDecimal n, double exp) { if (n.IsNull) { return Null; } byte precision = n.Precision; int scale = n.Scale; double x = n.ToDouble(); n = new SqlDecimal(Math.Pow(x, exp)); n.AdjustScale(scale - n.Scale, true); n.m_bPrec = MaxPrecision; return n; }
public static SqlDecimal operator -(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) { return(SqlDecimal.Null); } if (x.IsPositive && !y.IsPositive) { y = new SqlDecimal(y.Precision, y.Scale, !y.IsPositive, y.Data); return(x + y); } if (!x.IsPositive && y.IsPositive) { x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data); x = (x + y); return(new SqlDecimal(x.Precision, x.Scale, false, x.Data)); } if (!x.IsPositive && !y.IsPositive) { y = new SqlDecimal(y.Precision, y.Scale, !y.IsPositive, y.Data); x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data); return(y - x); } // adjust the scale to the larger of the two beforehand if (x.scale > y.scale) { y = SqlDecimal.AdjustScale(y, x.scale - y.scale, false); } else if (y.scale > x.scale) { x = SqlDecimal.AdjustScale(x, y.scale - x.scale, false); } //calculation of the new Precision for the result byte resultPrecision = (byte)(Math.Max(x.Scale, y.Scale) + Math.Max(x.Precision - x.Scale, y.Precision - y.Scale)); int[] op1_Data; int[] op2_Data; if (x >= y) { op1_Data = x.Data; op2_Data = y.Data; } else { op1_Data = y.Data; op2_Data = x.Data; } ulong res = 0; int carry = 0; int[] resultBits = new int[4]; /* * if ((uint)op2_Data [i] > (uint)op1_Data [i]) { * carry = UInt32.MaxValue; * op2_Data [i] = op2_Data [i] >> 1; * } else * carr = 0; * res = (uint)carry; +(ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) */ for (int i = 0; i < 4; i += 1) { res = (ulong)((uint)op1_Data [i]) - (ulong)((uint)op2_Data [i]) + (ulong)carry; carry = 0; if ((uint)op2_Data [i] > (uint)op1_Data [i]) { carry = -1; } resultBits [i] = (int)res; } if (carry > 0) { throw new OverflowException(); } else { return(new SqlDecimal(resultPrecision, x.Scale, (x >= y).Value, resultBits)); } }
public static SqlDecimal operator +(SqlDecimal x, SqlDecimal y) { if (x.IsNull || y.IsNull) { return(SqlDecimal.Null); } //if one of them is negative, perform subtraction if (x.IsPositive && !y.IsPositive) { y = new SqlDecimal(y.Precision, y.Scale, !y.IsPositive, y.Data); return(x - y); } if (!x.IsPositive && y.IsPositive) { x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data); return(y - x); } if (!x.IsPositive && !y.IsPositive) { x = new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data); y = new SqlDecimal(y.Precision, y.Scale, !y.IsPositive, y.Data); x = (x + y); return(new SqlDecimal(x.Precision, x.Scale, !x.IsPositive, x.Data)); } // adjust the scale to the larger of the two beforehand if (x.scale > y.scale) { y = SqlDecimal.AdjustScale(y, x.scale - y.scale, false); } else if (y.scale > x.scale) { x = SqlDecimal.AdjustScale(x, y.scale - x.scale, false); } byte resultPrecision = (byte)(Math.Max(x.Scale, y.Scale) + Math.Max(x.Precision - x.Scale, y.Precision - y.Scale) + 1); if (resultPrecision > MaxPrecision) { resultPrecision = MaxPrecision; } int [] xData = x.Data; int [] yData = y.Data; int [] resultBits = new int[4]; ulong carry = 0; ulong res = 0; for (int i = 0; i < 4; i++) { res = (ulong)((uint)xData [i]) + (ulong)((uint)yData [i]) + carry; resultBits [i] = (int)(res & (UInt32.MaxValue)); carry = res >> 32; } if (carry > 0) { throw new OverflowException(); } else { return(new SqlDecimal(resultPrecision, x.Scale, x.IsPositive, resultBits)); } }