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)
96 int digits = 17 - precision;
98 n = AdjustScale (this, digits, false);
100 n = Round (this, 17);
101 this.notNull = n.notNull;
102 this.positive = n.positive;
103 this.precision = n.precision;
104 this.scale = n.scale;
105 this.value = n.value;
107 public SqlDecimal (int value) : this ((decimal)value) { }
108 public SqlDecimal (long value) : this ((decimal)value) { }
110 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
112 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
114 this.precision = bPrecision;
116 this.positive = fPositive;
117 this.value = new int[4];
118 this.value[0] = data1;
119 this.value[1] = data2;
120 this.value[2] = data3;
121 this.value[3] = data4;
124 if (precision < scale)
125 throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
128 throw new SqlTypeException (Locale.GetText ("Invalid precision/scale combination."));
130 if (this.ToDouble () > (Math.Pow (10, 38) - 1) ||
131 this.ToDouble () < -(Math.Pow (10, 38)))
132 throw new SqlTypeException ("Can't convert to SqlDecimal, Out of range ");
139 public byte[] BinData {
142 byte [] b = new byte [value.Length * 4];
145 for (int i = 0; i < value.Length; i++) {
147 b [j++] = (byte)(0xff & value [i]);
148 b [j++] = (byte)(0xff & value [i] >> 8);
149 b [j++] = (byte)(0xff & value [i] >> 16);
150 b [j++] = (byte)(0xff & value [i] >> 24);
160 throw new SqlNullValueException ();
161 // Data should always return clone, not to be modified
162 int [] ret = new int [4];
172 get { return !notNull; }
175 public bool IsPositive {
176 get { return positive; }
179 public byte Precision {
180 get { return precision; }
184 get { return scale; }
187 public decimal Value {
190 throw new SqlNullValueException ();
192 if (this.value[3] > 0)
193 throw new OverflowException ();
195 return new decimal (value[0], value[1], value[2], !positive, scale);
203 public static SqlDecimal Abs (SqlDecimal n)
207 return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
210 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
215 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
217 byte prec = n.Precision;
219 throw new SqlNullValueException ();
225 else if (digits > 0) {
226 prec = (byte)(prec + digits);
229 for (int i = 0; i < digits; i++)
231 data = Decimal.GetBits (d);
233 newScale = (byte) (n.scale + digits);
236 n = Round (n, digits + n.scale);
238 n = Round (Truncate (n, digits + n.scale), digits + n.scale);
243 return new SqlDecimal (prec, newScale, n.positive, data);
246 public static SqlDecimal Ceiling (SqlDecimal n)
250 return AdjustScale (n, -(n.Scale), true);
253 public int CompareTo (object value)
257 else if (!(value is SqlDecimal))
258 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
259 else if (((SqlDecimal)value).IsNull)
262 return this.Value.CompareTo (((SqlDecimal)value).Value);
265 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
267 // return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
269 return AdjustScale (n, scale - n.scale, true);
272 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
277 public override bool Equals (object value)
279 if (!(value is SqlDecimal))
281 else if (this.IsNull && ((SqlDecimal)value).IsNull)
283 else if (((SqlDecimal)value).IsNull)
286 return (bool) (this == (SqlDecimal)value);
289 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
294 public static SqlDecimal Floor (SqlDecimal n)
296 return AdjustScale (n, -(n.Scale), false);
299 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
304 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
307 public override int GetHashCode ()
310 result = 91 * result + this.Data[0];
311 result = 91 * result + this.Data[1];
312 result = 91 * result + this.Data[2];
313 result = 91 * result + this.Data[3];
314 result = 91 * result + (int)this.Scale;
315 result = 91 * result + (int)this.Precision;
320 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
325 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
330 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
335 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
340 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
345 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
350 public static SqlDecimal Parse (string s)
353 throw new ArgumentNullException (Locale.GetText ("string s"));
355 return new SqlDecimal (Decimal.Parse (s));
358 public static SqlDecimal Power (SqlDecimal n, double exp)
361 return SqlDecimal.Null;
363 return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
366 public static SqlDecimal Round (SqlDecimal n, int position)
369 throw new SqlNullValueException ();
372 d = Decimal.Round (d, position);
373 return new SqlDecimal (d);
376 public static SqlInt32 Sign (SqlDecimal n)
380 if (n >= new SqlDecimal (0))
388 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
393 private byte GetPrecision (decimal value)
395 string str = value.ToString ();
398 foreach (char c in str) {
400 if (c >= '0' && c <= '9')
407 public double ToDouble ()
409 // FIXME: This is wrong way to do this
410 double d = (uint)this.Data [0];
411 d += ((uint)this.Data [1]) * Math.Pow (2, 32);
412 d += ((uint)this.Data [2]) * Math.Pow (2, 64);
413 d += ((uint)this.Data [3]) * Math.Pow (2, 96);
414 d = d / Math.Pow (10, scale);
419 public SqlBoolean ToSqlBoolean ()
421 return ((SqlBoolean)this);
424 public SqlByte ToSqlByte ()
426 return ((SqlByte)this);
429 public SqlDouble ToSqlDouble ()
431 return ((SqlDouble)this);
434 public SqlInt16 ToSqlInt16 ()
436 return ((SqlInt16)this);
439 public SqlInt32 ToSqlInt32 ()
441 return ((SqlInt32)this);
444 public SqlInt64 ToSqlInt64 ()
446 return ((SqlInt64)this);
449 public SqlMoney ToSqlMoney ()
451 return ((SqlMoney)this);
454 public SqlSingle ToSqlSingle ()
456 return ((SqlSingle)this);
459 public SqlString ToSqlString ()
461 return ((SqlString)this);
464 public override string ToString ()
469 // convert int [4] --> ulong [2]
470 ulong lo = (uint)this.Data [0];
471 lo += (ulong)((ulong)this.Data [1] << 32);
472 ulong hi = (uint)this.Data [2];
473 hi += (ulong)((ulong)this.Data [3] << 32);
477 StringBuilder Result = new StringBuilder ();
478 for (int i = 0; lo != 0 || hi != 0; i++) {
480 Div128By32 (ref hi, ref lo, 10, ref rest);
481 Result.Insert (0, rest.ToString ());
484 while (Result.Length < this.Precision)
487 while (Result.Length > this.Precision)
488 Result.Remove (Result.Length - 1, 1);
491 Result.Insert (Result.Length - this.Scale, ".");
494 Result.Insert (0, '-');
496 return Result.ToString ();
500 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
503 return Div128By32 (ref hi, ref lo, divider, ref t);
507 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
513 a = (uint)(hi >> 32);
521 hi = b << 32 | (uint)c;
523 a |= (uint)(lo >> 32);
530 lo = b << 32 | (uint)c;
534 return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
538 [MonoTODO("Find out what is the right way to set scale and precision")]
539 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
546 byte prec = 0; // precision
547 bool positive = ! (x.positive ^ y.positive);
549 prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
550 DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
552 sc = x.Scale - y.Scale;
554 Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
558 Div128By32(ref hi, ref lo, 10, ref r);
565 while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
568 while ((prec + sc) > MaxScale) {
569 Div128By32(ref hi, ref lo, 10, ref r);
575 int resultLo = (int)lo;
576 int resultMi = (int)(lo >> 32);
577 int resultMi2 = (int)(hi);
578 int resultHi = (int)(hi >> 32);
580 return new SqlDecimal (prec, (byte)sc, positive, resultLo,
586 private static void Rescale128 (ref ulong clo, ref ulong chi,
587 ref int scale, int texp,
588 int minScale, int maxScale,
602 while (texp > 0 && sc <= maxScale) {
604 overhang = (uint)(chi >> 64);
605 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
608 roundBit = (int)(clo & 1);
609 RShift128 (ref clo, ref chi);
611 overhang = (uint)(chi >> 32);
614 if (texp > DECIMAL_MAX_INTFACTORS)
615 i = DECIMAL_MAX_INTFACTORS;
619 if (sc + i > maxScale)
629 factor = constantsDecadeInt32Factors [i] >> i;
630 // System.Console.WriteLine ("***");
631 Mult128By32 (ref clo, ref chi, factor, 0);
632 // System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
638 roundBit = (int)(clo & 1);
639 RShift128 (ref clo, ref chi);
643 while (sc > maxScale) {
644 i = scale - maxScale;
645 if (i > DECIMAL_MAX_INTFACTORS)
646 i = DECIMAL_MAX_INTFACTORS;
648 roundBit = Div128By32 (ref clo, ref chi,
649 constantsDecadeInt32Factors[i]);
652 while (sc < minScale) {
656 if (i > DECIMAL_MAX_INTFACTORS)
657 i = DECIMAL_MAX_INTFACTORS;
659 Mult128By32 (ref clo, ref chi,
660 constantsDecadeInt32Factors[i], roundBit);
664 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
668 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
674 if ((roundFlag != 0) && (roundBit != 0))
675 RoundUp128 (ref clo, ref chi);
679 private static void RoundUp128(ref ulong lo, ref ulong hi)
686 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
700 xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
701 xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
703 ylo = (uint)y.Data [0];
704 ymi = (uint)y.Data [1];
705 ymi2 = (uint)y.Data [2];
706 yhi = (uint)y.Data [3];
708 if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
709 throw new DivideByZeroException ();
711 if (xmi == 0 && xhi == 0) {
716 // enlarge dividend to get maximal precision
717 for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
718 LShift128 (ref xmi, ref xhi);
720 // ensure that divisor is at least 2^95
721 for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
722 LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
724 thi = ((ulong)yhi) << 32 | (ulong)ymi2;
725 tmi = ((ulong)ymi) << 32 | (ulong)ylo;
728 if (xhi > thi || (xhi == thi && xmi >=tmi)) {
729 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
735 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
737 exp = 128 + ashift - bshift;
740 RShift128 (ref clo, ref chi);
741 chi += LIT_GUINT64_HIGHBIT;
745 // try loss free right shift
746 while (exp > 0 && (clo & 1) == 0) {
747 RShift128 (ref clo, ref chi);
753 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
758 lo |= LIT_GUINT64_HIGHBIT;
762 mi |= LIT_GUINT64_HIGHBIT;
768 private static void RShift128(ref ulong lo, ref ulong hi)
772 lo |= LIT_GUINT64_HIGHBIT;
777 private static void LShift128(ref ulong lo, ref ulong hi)
781 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
788 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
791 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
795 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
799 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
806 private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi,
807 uint ylo, uint ymi, uint ymi2,
808 uint yhi, ref ulong clo, ref ulong chi)
810 ulong rlo, rmi, rhi; // remainders
817 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
820 rhi = (rhi << 32) | (rmi >> 32);
821 rmi = (rmi << 32) | (rlo >> 32);
824 chi = (((ulong)h) << 32) | Div192By128To32WithRest (
825 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
828 rhi = (rhi << 32) | (rmi >> 32);
829 rmi = (rmi << 32) | (rlo >> 32);
832 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
833 ylo, ymi, ymi2, yhi);
835 // estimate lowest 32 bit (two last bits may be wrong)
840 c = (uint)(rhi / yhi);
843 clo = (((ulong)h) << 32) | c;
847 private static uint Div192By128To32WithRest(ref ulong xlo, ref ulong xmi,
848 ref ulong xhi, uint ylo,
849 uint ymi, uint ymi2, uint yhi)
851 ulong rlo, rmi, rhi; // remainder
860 if (rhi >= (((ulong)yhi << 32)))
863 c = (uint) (rhi / yhi);
865 Mult128By32To128 (ylo, ymi, ymi2, yhi, c, ref tlo, ref thi);
866 Sub192 (rlo, rmi, rhi, 0, tlo, thi, ref rlo, ref rmi, ref rhi);
868 while (((long)rhi) < 0) {
870 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
880 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
887 a = ((ulong)(uint)clo) * factor;
894 a += (clo >> 32) * factor;
897 clo = ((ulong)h1) << 32 | h0;
900 a += ((ulong)(uint)cmi) * factor;
904 a += (cmi >> 32) * factor;
907 cmi = ((ulong)h1) << 32 | h0;
909 a += ((ulong)(uint)chi) * factor;
913 a += (chi >> 32) * factor;
915 chi = ((ulong)h1) << 32 | h0;
919 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
926 a = ((ulong)(uint)clo) * factor;
934 a += (clo >> 32) * factor;
937 clo = ((ulong)h1) << 32 | h0;
940 a += ((ulong)(uint)chi) * factor;
944 a += (chi >> 32) * factor;
947 chi = ((ulong)h1) << 32 | h0;
952 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
953 uint factor, ref ulong clo, ref ulong chi)
958 a = ((ulong)xlo) * factor;
962 a += ((ulong)xmi) * factor;
966 a += ((ulong)xmi2) * factor;
970 a += ((ulong)xhi) * factor;
972 clo = ((ulong)h1) << 32 | h0;
977 private static void Add192 (ulong xlo, ulong xmi, ulong xhi,
978 ulong ylo, ulong ymi, ulong yhi,
979 ref ulong clo, ref ulong cmi, ref ulong chi)
1000 private static void Sub192 (ulong xlo, ulong xmi, ulong xhi,
1001 ulong ylo, ulong ymi, ulong yhi,
1002 ref ulong lo, ref ulong mi, ref ulong hi)
1027 public static SqlDecimal Truncate (SqlDecimal n, int position)
1029 int diff = n.scale - position;
1032 int [] data = n.Data;
1033 decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
1035 for (int i = 0; i < diff; i++, x *= 10)
1037 data = Decimal.GetBits (d);
1039 return new SqlDecimal (n.precision, n.scale, n.positive, data);
1042 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
1044 // if one of them is negative, perform subtraction
1045 if (x.IsPositive && !y.IsPositive) return x - y;
1046 if (y.IsPositive && !x.IsPositive) return y - x;
1048 // adjust the scale to the larger of the two beforehand
1049 if (x.scale > y.scale)
1050 y = SqlDecimal.AdjustScale (y, x.scale - y.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1051 else if (y.scale > x.scale)
1052 x = SqlDecimal.AdjustScale (x, y.scale - x.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1054 // set the precision to the greater of the two
1055 byte resultPrecision;
1056 if (x.Precision > y.Precision)
1057 resultPrecision = x.Precision;
1059 resultPrecision = y.Precision;
1061 int[] xData = x.Data;
1062 int[] yData = y.Data;
1063 int[] resultBits = new int[4];
1068 // add one at a time, and carry the results over to the next
1069 for (int i = 0; i < 4; i +=1)
1072 res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
1073 if (res > Int32.MaxValue)
1075 carry = res - Int32.MaxValue;
1076 res = Int32.MaxValue;
1078 resultBits [i] = (int)res;
1081 // if we have carry left, then throw an exception
1083 throw new OverflowException ();
1085 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1088 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1090 // return new SqlDecimal (x.Value / y.Value);
1091 return DecimalDiv (x, y);
1094 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1096 if (x.IsNull || y.IsNull)
1097 return SqlBoolean.Null;
1099 if (x.Scale > y.Scale)
1100 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1101 else if (y.Scale > x.Scale)
1102 x = SqlDecimal.AdjustScale(y, y.Scale - x.Scale, false);
1104 for (int i = 0; i < 4; i += 1)
1106 if (x.Data[i] != y.Data[i])
1107 return new SqlBoolean (false);
1109 return new SqlBoolean (true);
1112 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1114 if (x.IsNull || y.IsNull)
1115 return SqlBoolean.Null;
1117 if (x.Scale > y.Scale)
1118 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1119 else if (y.Scale > x.Scale)
1120 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, false);
1122 for (int i = 3; i >= 0; i--)
1124 if (x.Data[i] == 0 && y.Data[i] == 0)
1127 return new SqlBoolean (x.Data[i] > y.Data[i]);
1129 return new SqlBoolean (false);
1132 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1134 if (x.IsNull || y.IsNull)
1135 return SqlBoolean.Null;
1137 if (x.Scale > y.Scale)
1138 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1139 else if (y.Scale > x.Scale)
1140 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1142 for (int i = 3; i >= 0; i -= 1)
1144 if (x.Data[i] == 0 && y.Data[i] == 0)
1147 return new SqlBoolean (x.Data[i] >= y.Data[i]);
1149 return new SqlBoolean (true);
1152 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1154 if (x.IsNull || y.IsNull)
1155 return SqlBoolean.Null;
1157 if (x.Scale > y.Scale)
1158 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1159 else if (y.Scale > x.Scale)
1160 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1162 for (int i = 0; i < 4; i += 1)
1164 if (x.Data[i] != y.Data[i])
1165 return new SqlBoolean (true);
1167 return new SqlBoolean (false);
1170 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1173 if (x.IsNull || y.IsNull)
1174 return SqlBoolean.Null;
1176 if (x.Scale > y.Scale)
1177 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1178 else if (y.Scale > x.Scale)
1179 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1181 for (int i = 3; i >= 0; i -= 1)
1183 if (x.Data[i] == 0 && y.Data[i] == 0)
1186 return new SqlBoolean (x.Data[i] < y.Data[i]);
1188 return new SqlBoolean (false);
1192 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1194 if (x.IsNull || y.IsNull)
1195 return SqlBoolean.Null;
1197 if (x.Scale > y.Scale)
1198 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1199 else if (y.Scale > x.Scale)
1200 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1202 for (int i = 3; i >= 0; i -= 1)
1204 if (x.Data[i] == 0 && y.Data[i] == 0)
1207 return new SqlBoolean (x.Data[i] <= y.Data[i]);
1209 return new SqlBoolean (true);
1212 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1214 // adjust the scale to the smaller of the two beforehand
1215 if (x.Scale > y.Scale)
1216 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1217 else if (y.Scale > x.Scale)
1218 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1220 // set the precision to the greater of the two
1221 byte resultPrecision;
1222 if (x.Precision > y.Precision)
1223 resultPrecision = x.Precision;
1225 resultPrecision = y.Precision;
1227 int[] xData = x.Data;
1228 int[] yData = y.Data;
1229 int[] resultBits = new int[4];
1234 // multiply one at a time, and carry the results over to the next
1235 for (int i = 0; i < 4; i +=1)
1238 res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
1239 if (res > Int32.MaxValue)
1241 carry = res - Int32.MaxValue;
1242 res = Int32.MaxValue;
1244 resultBits [i] = (int)res;
1247 // if we have carry left, then throw an exception
1249 throw new OverflowException ();
1251 return new SqlDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
1255 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1257 if (x.IsPositive && !y.IsPositive) return x + y;
1258 if (!x.IsPositive && y.IsPositive) return -(x + y);
1259 if (!x.IsPositive && !y.IsPositive) return y - x;
1261 // otherwise, x is positive and y is positive
1262 bool resultPositive = (bool)(x > y);
1263 int[] yData = y.Data;
1265 for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
1267 SqlDecimal yInverse = new SqlDecimal (y.Precision, y.Scale, y.IsPositive, yData);
1270 return x + yInverse;
1272 return -(x + yInverse);
1275 public static SqlDecimal operator - (SqlDecimal n)
1277 return new SqlDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
1280 public static explicit operator SqlDecimal (SqlBoolean x)
1285 return new SqlDecimal ((decimal)x.ByteValue);
1288 public static explicit operator Decimal (SqlDecimal n)
1293 public static explicit operator SqlDecimal (SqlDouble x)
1299 return new SqlDecimal ((double)x.Value);
1303 public static explicit operator SqlDecimal (SqlSingle x)
1309 return new SqlDecimal ((double)x.Value);
1313 public static explicit operator SqlDecimal (SqlString x)
1316 return Parse (x.Value);
1320 public static implicit operator SqlDecimal (decimal x)
1322 return new SqlDecimal (x);
1325 public static implicit operator SqlDecimal (SqlByte x)
1330 return new SqlDecimal ((decimal)x.Value);
1333 public static implicit operator SqlDecimal (SqlInt16 x)
1338 return new SqlDecimal ((decimal)x.Value);
1341 public static implicit operator SqlDecimal (SqlInt32 x)
1346 return new SqlDecimal ((decimal)x.Value);
1349 public static implicit operator SqlDecimal (SqlInt64 x)
1354 return new SqlDecimal ((decimal)x.Value);
1357 public static implicit operator SqlDecimal (SqlMoney x)
1362 return new SqlDecimal ((decimal)x.Value);