2 // System.Data.SqlTypes.SqlDecimal
5 // Tim Coleman <tim@timcoleman.com>
6 // Ville Palo <vi64pa@koti.soon.fi>
8 // (C) Copyright 2002 Tim Coleman
11 using Mono.Data.Tds.Protocol;
14 using System.Globalization;
16 namespace System.Data.SqlTypes
18 public struct SqlDecimal : INullable, IComparable
29 // borrowed from System.Decimal
30 const int SCALE_SHIFT = 16;
31 const int SIGN_SHIFT = 31;
32 const int RESERVED_SS32_BITS = 0x7F00FFFF;
33 const ulong LIT_GUINT64_HIGHBIT = 0x8000000000000000;
34 const ulong LIT_GUINT32_HIGHBIT = 0x80000000;
35 const byte DECIMAL_MAX_INTFACTORS = 9;
36 static uint [] constantsDecadeInt32Factors = new uint [10]
38 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
39 10000000u, 100000000u, 1000000000u
42 public static readonly byte MaxPrecision = 38;
43 public static readonly byte MaxScale = 38;
45 // This should be 99999999999999999999999999999999999999
46 public static readonly SqlDecimal MaxValue = new SqlDecimal (MaxPrecision,
53 // This should be -99999999999999999999999999999999999999
54 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision,
61 public static readonly SqlDecimal Null;
67 public SqlDecimal (decimal value)
69 int[] binData = Decimal.GetBits (value);
71 this.precision = MaxPrecision; // this value seems unclear
73 this.scale = (byte)(((uint)binData [3]) >> SCALE_SHIFT);
75 if (this.scale > MaxScale || ((uint)binData [3] & RESERVED_SS32_BITS) != 0)
76 throw new ArgumentException(Locale.GetText ("Invalid scale"));
78 this.value = new int[4];
79 this.value[0] = binData[0];
80 this.value[1] = binData[1];
81 this.value[2] = binData[2];
90 precision = GetPrecision (value);
93 public SqlDecimal (double value) : this ((decimal)value) { }
94 public SqlDecimal (int value) : this ((decimal)value) { }
95 public SqlDecimal (long value) : this ((decimal)value) { }
97 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
100 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
102 this.precision = bPrecision;
104 this.positive = fPositive;
105 this.value = new int[4];
106 this.value[0] = data1;
107 this.value[1] = data2;
108 this.value[2] = data3;
109 this.value[3] = data4;
112 if (precision < scale)
113 throw new ArgumentException(Locale.GetText ("Invalid scale"));
115 // FIXME: What is the right message of Exception
116 if (this.ToDouble () > (Math.Pow (10, 38) - 1) ||
117 this.ToDouble () < -(Math.Pow (10, 38)))
118 throw new SqlTypeException ("Can't convert to SqlDecimal");
125 public byte[] BinData {
128 byte [] b = new byte [value.Length * 4];
131 for (int i = 0; i < value.Length; i++) {
133 b [j++] = (byte)(0xff & value [i]);
134 b [j++] = (byte)(0xff & value [i] >> 8);
135 b [j++] = (byte)(0xff & value [i] >> 16);
136 b [j++] = (byte)(0xff & value [i] >> 24);
146 throw new SqlNullValueException ();
153 get { return !notNull; }
156 public bool IsPositive {
157 get { return positive; }
160 public byte Precision {
161 get { return precision; }
165 get { return scale; }
168 public decimal Value {
171 throw new SqlNullValueException ();
173 if (this.value[3] > 0)
174 throw new OverflowException ();
176 return new decimal (value[0], value[1], value[2], !positive, scale);
184 public static SqlDecimal Abs (SqlDecimal n)
186 return new SqlDecimal (n.Precision, n.Scale, true,
187 n.BinData [0], n.BinData [1],
188 n.BinData [2], n.BinData [3]);
191 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
196 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
198 byte prec = n.Precision;
200 throw new SqlNullValueException ();
203 prec = (byte)(prec + digits);
206 n = Round (n, digits + n.Scale);
208 return new SqlDecimal (prec,
209 (byte)(n.Scale + digits),
210 n.IsPositive, n.Data);
213 public static SqlDecimal Ceiling (SqlDecimal n)
215 return AdjustScale (n, -(n.Scale), true);
218 public int CompareTo (object value)
222 else if (!(value is SqlDecimal))
223 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
224 else if (((SqlDecimal)value).IsNull)
227 return this.Value.CompareTo (((SqlDecimal)value).Value);
230 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
232 return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
235 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
240 public override bool Equals (object value)
242 if (!(value is SqlDecimal))
244 else if (this.IsNull && ((SqlDecimal)value).IsNull)
246 else if (((SqlDecimal)value).IsNull)
249 return (bool) (this == (SqlDecimal)value);
252 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
257 public static SqlDecimal Floor (SqlDecimal n)
259 return AdjustScale (n, -(n.Scale), false);
262 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
267 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
270 public override int GetHashCode ()
273 result = 91 * result + this.Data[0];
274 result = 91 * result + this.Data[1];
275 result = 91 * result + this.Data[2];
276 result = 91 * result + this.Data[3];
277 result = 91 * result + (int)this.Scale;
278 result = 91 * result + (int)this.Precision;
283 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
288 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
293 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
298 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
303 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
308 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
314 public static SqlDecimal Parse (string s)
316 // FIXME: Huh, There must be better way to do this
318 throw new ArgumentNullException ();
320 return SqlDouble.Parse (s).ToSqlDecimal ();
323 public static SqlDecimal Power (SqlDecimal n, double exp)
326 return SqlDecimal.Null;
328 return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
332 public static SqlDecimal Round (SqlDecimal n, int position)
334 // FIXME: There must be better way to do this
336 throw new SqlNullValueException ();
338 SqlDecimal result = new SqlDecimal (Math.Round (
339 (double)(n.ToDouble () * Math.Pow (10, position))));
341 result = result / new SqlDecimal(Math.Pow (10, position));
346 public static SqlInt32 Sign (SqlDecimal n)
350 if (n >= new SqlDecimal (0))
358 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
363 private byte GetPrecision (decimal value)
365 string str = value.ToString ();
368 foreach (char c in str) {
370 if (c >= '0' && c <= '9')
377 public double ToDouble ()
379 // FIXME: This is wrong way to do this
380 double d = (uint)this.Data [0];
381 d += ((uint)this.Data [1]) * Math.Pow (2, 32);
382 d += ((uint)this.Data [2]) * Math.Pow (2, 64);
383 d += ((uint)this.Data [3]) * Math.Pow (2, 96);
384 d = d / Math.Pow (10, scale);
389 public SqlBoolean ToSqlBoolean ()
391 return ((SqlBoolean)this);
394 public SqlByte ToSqlByte ()
396 return ((SqlByte)this);
399 public SqlDouble ToSqlDouble ()
401 return ((SqlDouble)this);
404 public SqlInt16 ToSqlInt16 ()
406 return ((SqlInt16)this);
409 public SqlInt32 ToSqlInt32 ()
411 return ((SqlInt32)this);
414 public SqlInt64 ToSqlInt64 ()
416 return ((SqlInt64)this);
419 public SqlMoney ToSqlMoney ()
421 return ((SqlMoney)this);
424 public SqlSingle ToSqlSingle ()
426 return ((SqlSingle)this);
429 public SqlString ToSqlString ()
431 return ((SqlString)this);
434 public override string ToString ()
439 // convert int [4] --> ulong [2]
440 ulong lo = (uint)this.Data [0];
441 lo += (ulong)((ulong)this.Data [1] << 32);
442 ulong hi = (uint)this.Data [2];
443 hi += (ulong)((ulong)this.Data [3] << 32);
447 StringBuilder Result = new StringBuilder ();
448 for (int i = 0; lo != 0 || hi != 0; i++) {
450 Div128By32 (ref hi, ref lo, 10, ref rest);
451 Result.Insert (0, rest.ToString ());
454 while (Result.Length < this.Precision)
457 while (Result.Length > this.Precision)
458 Result.Remove (Result.Length - 1, 1);
461 Result.Insert (Result.Length - this.Scale, ".");
463 return Result.ToString ();
467 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
470 return Div128By32 (ref hi, ref lo, divider, ref t);
474 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
480 a = (uint)(hi >> 32);
488 hi = b << 32 | (uint)c;
490 a |= (uint)(lo >> 32);
497 lo = b << 32 | (uint)c;
501 return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
505 [MonoTODO("Find out what is the right way to set scale and precision")]
506 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
513 byte prec = 0; // precision
515 prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
516 DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
518 sc = x.Scale - y.Scale;
520 Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
524 Div128By32(ref hi, ref lo, 10, ref r);
531 while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
534 while ((prec + sc) > MaxScale) {
535 Div128By32(ref hi, ref lo, 10, ref r);
541 int resultLo = (int)lo;
542 int resultMi = (int)(lo >> 32);
543 int resultMi2 = (int)(hi);
544 int resultHi = (int)(hi >> 32);
546 return new SqlDecimal (prec, (byte)sc, true, resultLo,
552 private static void Rescale128 (ref ulong clo, ref ulong chi,
553 ref int scale, int texp,
554 int minScale, int maxScale,
568 while (texp > 0 && sc <= maxScale) {
570 overhang = (uint)(chi >> 64);
571 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
574 roundBit = (int)(clo & 1);
575 RShift128 (ref clo, ref chi);
577 overhang = (uint)(chi >> 32);
580 if (texp > DECIMAL_MAX_INTFACTORS)
581 i = DECIMAL_MAX_INTFACTORS;
585 if (sc + i > maxScale)
595 factor = constantsDecadeInt32Factors [i] >> i;
596 System.Console.WriteLine ("***");
597 Mult128By32 (ref clo, ref chi, factor, 0);
598 System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
604 roundBit = (int)(clo & 1);
605 RShift128 (ref clo, ref chi);
609 while (sc > maxScale) {
610 i = scale - maxScale;
611 if (i > DECIMAL_MAX_INTFACTORS)
612 i = DECIMAL_MAX_INTFACTORS;
614 roundBit = Div128By32 (ref clo, ref chi,
615 constantsDecadeInt32Factors[i]);
618 while (sc < minScale) {
622 if (i > DECIMAL_MAX_INTFACTORS)
623 i = DECIMAL_MAX_INTFACTORS;
625 Mult128By32 (ref clo, ref chi,
626 constantsDecadeInt32Factors[i], roundBit);
630 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
634 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
640 if ((roundFlag != 0) && (roundBit != 0))
641 RoundUp128 (ref clo, ref chi);
645 private static void RoundUp128(ref ulong lo, ref ulong hi)
652 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
666 xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
667 xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
669 ylo = (uint)y.Data [0];
670 ymi = (uint)y.Data [1];
671 ymi2 = (uint)y.Data [2];
672 yhi = (uint)y.Data [3];
674 if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
675 throw new DivideByZeroException ();
677 if (xmi == 0 && xhi == 0) {
682 // enlarge dividend to get maximal precision
683 for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
684 LShift128 (ref xmi, ref xhi);
686 // ensure that divisor is at least 2^95
687 for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
688 LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
690 thi = ((ulong)yhi) << 32 | (ulong)ymi2;
691 tmi = ((ulong)ymi) << 32 | (ulong)ylo;
694 if (xhi > thi || (xhi == thi && xmi >=tmi)) {
695 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
701 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
703 exp = 128 + ashift - bshift;
706 RShift128 (ref clo, ref chi);
707 chi += LIT_GUINT64_HIGHBIT;
711 // try loss free right shift
712 while (exp > 0 && (clo & 1) == 0) {
713 RShift128 (ref clo, ref chi);
719 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
724 lo |= LIT_GUINT64_HIGHBIT;
728 mi |= LIT_GUINT64_HIGHBIT;
734 private static void RShift128(ref ulong lo, ref ulong hi)
738 lo |= LIT_GUINT64_HIGHBIT;
743 private static void LShift128(ref ulong lo, ref ulong hi)
747 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
754 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
757 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
761 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
765 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
772 private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi,
773 uint ylo, uint ymi, uint ymi2,
774 uint yhi, ref ulong clo, ref ulong chi)
776 ulong rlo, rmi, rhi; // remainders
783 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
786 rhi = (rhi << 32) | (rmi >> 32);
787 rmi = (rmi << 32) | (rlo >> 32);
790 chi = (((ulong)h) << 32) | Div192By128To32WithRest (
791 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
794 rhi = (rhi << 32) | (rmi >> 32);
795 rmi = (rmi << 32) | (rlo >> 32);
798 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
799 ylo, ymi, ymi2, yhi);
801 // estimate lowest 32 bit (two last bits may be wrong)
806 c = (uint)(rhi / yhi);
809 clo = (((ulong)h) << 32) | c;
813 private static uint Div192By128To32WithRest(ref ulong xlo, ref ulong xmi,
814 ref ulong xhi, uint ylo,
815 uint ymi, uint ymi2, uint yhi)
817 ulong rlo, rmi, rhi; // remainder
826 if (rhi >= (((ulong)yhi << 32)))
829 c = (uint) (rhi / yhi);
831 Mult128By32To128 (ylo, ymi, ymi2, yhi, c, ref tlo, ref thi);
832 Sub192 (rlo, rmi, rhi, 0, tlo, thi, ref rlo, ref rmi, ref rhi);
834 while (((long)rhi) < 0) {
836 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
846 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
853 a = ((ulong)(uint)clo) * factor;
860 a += (clo >> 32) * factor;
863 clo = ((ulong)h1) << 32 | h0;
866 a += ((ulong)(uint)cmi) * factor;
870 a += (cmi >> 32) * factor;
873 cmi = ((ulong)h1) << 32 | h0;
875 a += ((ulong)(uint)chi) * factor;
879 a += (chi >> 32) * factor;
881 chi = ((ulong)h1) << 32 | h0;
885 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
892 a = ((ulong)(uint)clo) * factor;
900 a += (clo >> 32) * factor;
903 clo = ((ulong)h1) << 32 | h0;
906 a += ((ulong)(uint)chi) * factor;
910 a += (chi >> 32) * factor;
913 chi = ((ulong)h1) << 32 | h0;
918 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
919 uint factor, ref ulong clo, ref ulong chi)
924 a = ((ulong)xlo) * factor;
928 a += ((ulong)xmi) * factor;
932 a += ((ulong)xmi2) * factor;
936 a += ((ulong)xhi) * factor;
938 clo = ((ulong)h1) << 32 | h0;
943 private static void Add192 (ulong xlo, ulong xmi, ulong xhi,
944 ulong ylo, ulong ymi, ulong yhi,
945 ref ulong clo, ref ulong cmi, ref ulong chi)
966 private static void Sub192 (ulong xlo, ulong xmi, ulong xhi,
967 ulong ylo, ulong ymi, ulong yhi,
968 ref ulong lo, ref ulong mi, ref ulong hi)
993 public static SqlDecimal Truncate (SqlDecimal n, int position)
995 int prec = n.Precision;// + (position - n.Scale);
997 return new SqlDecimal ((byte)prec, (byte)sc,
998 n.IsPositive, n.Data);
1001 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
1003 // if one of them is negative, perform subtraction
1004 if (x.IsPositive && !y.IsPositive) return x - y;
1005 if (y.IsPositive && !x.IsPositive) return y - x;
1007 // adjust the scale to the smaller of the two beforehand
1008 if (x.Scale > y.Scale)
1009 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1010 else if (y.Scale > x.Scale)
1011 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1013 // set the precision to the greater of the two
1014 byte resultPrecision;
1015 if (x.Precision > y.Precision)
1016 resultPrecision = x.Precision;
1018 resultPrecision = y.Precision;
1020 int[] xData = x.Data;
1021 int[] yData = y.Data;
1022 int[] resultBits = new int[4];
1027 // add one at a time, and carry the results over to the next
1028 for (int i = 0; i < 4; i +=1)
1031 res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
1032 if (res > Int32.MaxValue)
1034 carry = res - Int32.MaxValue;
1035 res = Int32.MaxValue;
1037 resultBits [i] = (int)res;
1040 // if we have carry left, then throw an exception
1042 throw new OverflowException ();
1044 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1047 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1049 // return new SqlDecimal (x.Value / y.Value);
1050 return DecimalDiv (x, y);
1053 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1055 if (x.IsNull || y.IsNull)
1056 return SqlBoolean.Null;
1058 if (x.Scale > y.Scale)
1059 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1060 else if (y.Scale > x.Scale)
1061 x = SqlDecimal.AdjustScale(y, y.Scale - x.Scale, false);
1063 for (int i = 0; i < 4; i += 1)
1065 if (x.Data[i] != y.Data[i])
1066 return new SqlBoolean (false);
1068 return new SqlBoolean (true);
1071 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1073 if (x.IsNull || y.IsNull)
1074 return SqlBoolean.Null;
1076 if (x.Scale > y.Scale)
1077 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1078 else if (y.Scale > x.Scale)
1079 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, false);
1081 for (int i = 3; i >= 0; i--)
1083 if (x.Data[i] == 0 && y.Data[i] == 0)
1086 return new SqlBoolean (x.Data[i] > y.Data[i]);
1088 return new SqlBoolean (false);
1091 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1093 if (x.IsNull || y.IsNull)
1094 return SqlBoolean.Null;
1096 if (x.Scale > y.Scale)
1097 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1098 else if (y.Scale > x.Scale)
1099 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1101 for (int i = 3; i >= 0; i -= 1)
1103 if (x.Data[i] == 0 && y.Data[i] == 0)
1106 return new SqlBoolean (x.Data[i] >= y.Data[i]);
1108 return new SqlBoolean (true);
1111 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1113 if (x.IsNull || y.IsNull)
1114 return SqlBoolean.Null;
1116 if (x.Scale > y.Scale)
1117 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1118 else if (y.Scale > x.Scale)
1119 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1121 for (int i = 0; i < 4; i += 1)
1123 if (x.Data[i] != y.Data[i])
1124 return new SqlBoolean (true);
1126 return new SqlBoolean (false);
1129 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1132 if (x.IsNull || y.IsNull)
1133 return SqlBoolean.Null;
1135 if (x.Scale > y.Scale)
1136 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1137 else if (y.Scale > x.Scale)
1138 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1140 for (int i = 3; i >= 0; i -= 1)
1142 if (x.Data[i] == 0 && y.Data[i] == 0)
1145 return new SqlBoolean (x.Data[i] < y.Data[i]);
1147 return new SqlBoolean (false);
1151 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1153 if (x.IsNull || y.IsNull)
1154 return SqlBoolean.Null;
1156 if (x.Scale > y.Scale)
1157 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1158 else if (y.Scale > x.Scale)
1159 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1161 for (int i = 3; i >= 0; i -= 1)
1163 if (x.Data[i] == 0 && y.Data[i] == 0)
1166 return new SqlBoolean (x.Data[i] <= y.Data[i]);
1168 return new SqlBoolean (true);
1171 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1173 // adjust the scale to the smaller of the two beforehand
1174 if (x.Scale > y.Scale)
1175 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1176 else if (y.Scale > x.Scale)
1177 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1179 // set the precision to the greater of the two
1180 byte resultPrecision;
1181 if (x.Precision > y.Precision)
1182 resultPrecision = x.Precision;
1184 resultPrecision = y.Precision;
1186 int[] xData = x.Data;
1187 int[] yData = y.Data;
1188 int[] resultBits = new int[4];
1193 // multiply one at a time, and carry the results over to the next
1194 for (int i = 0; i < 4; i +=1)
1197 res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
1198 if (res > Int32.MaxValue)
1200 carry = res - Int32.MaxValue;
1201 res = Int32.MaxValue;
1203 resultBits [i] = (int)res;
1206 // if we have carry left, then throw an exception
1208 throw new OverflowException ();
1210 return new SqlDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
1214 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1216 if (x.IsPositive && !y.IsPositive) return x + y;
1217 if (!x.IsPositive && y.IsPositive) return -(x + y);
1218 if (!x.IsPositive && !y.IsPositive) return y - x;
1220 // otherwise, x is positive and y is positive
1221 bool resultPositive = (bool)(x > y);
1222 int[] yData = y.Data;
1224 for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
1226 SqlDecimal yInverse = new SqlDecimal (y.Precision, y.Scale, y.IsPositive, yData);
1229 return x + yInverse;
1231 return -(x + yInverse);
1234 public static SqlDecimal operator - (SqlDecimal n)
1236 return new SqlDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
1239 public static explicit operator SqlDecimal (SqlBoolean x)
1244 return new SqlDecimal ((decimal)x.ByteValue);
1247 public static explicit operator Decimal (SqlDecimal n)
1252 public static explicit operator SqlDecimal (SqlDouble x)
1258 return new SqlDecimal ((decimal)x.Value);
1262 public static explicit operator SqlDecimal (SqlSingle x)
1268 return new SqlDecimal ((decimal)x.Value);
1272 public static explicit operator SqlDecimal (SqlString x)
1275 return Parse (x.Value);
1279 public static implicit operator SqlDecimal (decimal x)
1281 return new SqlDecimal (x);
1284 public static implicit operator SqlDecimal (SqlByte x)
1289 return new SqlDecimal ((decimal)x.Value);
1292 public static implicit operator SqlDecimal (SqlInt16 x)
1297 return new SqlDecimal ((decimal)x.Value);
1300 public static implicit operator SqlDecimal (SqlInt32 x)
1305 return new SqlDecimal ((decimal)x.Value);
1308 public static implicit operator SqlDecimal (SqlInt64 x)
1313 return new SqlDecimal ((decimal)x.Value);
1316 public static implicit operator SqlDecimal (SqlMoney x)
1321 return new SqlDecimal ((decimal)x.Value);