2 // System.Data.SqlTypes.SqlDecimal
5 // Tim Coleman <tim@timcoleman.com>
6 // Ville Palo <vi64pa@koti.soon.fi>
8 // (C) Copyright 2002 Tim Coleman
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using Mono.Data.Tds.Protocol;
37 using System.Globalization;
39 namespace System.Data.SqlTypes
41 public struct SqlDecimal : INullable, IComparable
52 // borrowed from System.Decimal
53 const int SCALE_SHIFT = 16;
54 const int SIGN_SHIFT = 31;
55 const int RESERVED_SS32_BITS = 0x7F00FFFF;
56 const ulong LIT_GUINT64_HIGHBIT = 0x8000000000000000;
57 const ulong LIT_GUINT32_HIGHBIT = 0x80000000;
58 const byte DECIMAL_MAX_INTFACTORS = 9;
59 static uint [] constantsDecadeInt32Factors = new uint [10]
61 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
62 10000000u, 100000000u, 1000000000u
65 public static readonly byte MaxPrecision = 38;
66 public static readonly byte MaxScale = 38;
68 // This should be 99999999999999999999999999999999999999
69 public static readonly SqlDecimal MaxValue = new SqlDecimal (MaxPrecision,
76 // This should be -99999999999999999999999999999999999999
77 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision,
84 public static readonly SqlDecimal Null;
90 public SqlDecimal (decimal value)
92 int[] binData = Decimal.GetBits (value);
94 this.precision = MaxPrecision; // this value seems unclear
96 this.scale = (byte)(((uint)binData [3]) >> SCALE_SHIFT);
98 if (this.scale > MaxScale || ((uint)binData [3] & RESERVED_SS32_BITS) != 0)
99 throw new ArgumentException(Locale.GetText ("Invalid scale"));
101 this.value = new int[4];
102 this.value[0] = binData[0];
103 this.value[1] = binData[1];
104 this.value[2] = binData[2];
113 precision = GetPrecision (value);
116 public SqlDecimal (double value) : this ((decimal)value)
119 int digits = 17 - precision;
121 n = AdjustScale (this, digits, false);
123 n = Round (this, 17);
124 this.notNull = n.notNull;
125 this.positive = n.positive;
126 this.precision = n.precision;
127 this.scale = n.scale;
128 this.value = n.value;
130 public SqlDecimal (int value) : this ((decimal)value) { }
131 public SqlDecimal (long value) : this ((decimal)value) { }
133 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
135 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
137 this.precision = bPrecision;
139 this.positive = fPositive;
140 this.value = new int[4];
141 this.value[0] = data1;
142 this.value[1] = data2;
143 this.value[2] = data3;
144 this.value[3] = data4;
147 if (precision < scale)
148 throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
151 throw new SqlTypeException (Locale.GetText ("Invalid precision/scale combination."));
153 if (this.ToDouble () > (Math.Pow (10, 38) - 1) ||
154 this.ToDouble () < -(Math.Pow (10, 38)))
155 throw new SqlTypeException ("Can't convert to SqlDecimal, Out of range ");
162 public byte[] BinData {
165 byte [] b = new byte [value.Length * 4];
168 for (int i = 0; i < value.Length; i++) {
170 b [j++] = (byte)(0xff & value [i]);
171 b [j++] = (byte)(0xff & value [i] >> 8);
172 b [j++] = (byte)(0xff & value [i] >> 16);
173 b [j++] = (byte)(0xff & value [i] >> 24);
183 throw new SqlNullValueException ();
184 // Data should always return clone, not to be modified
185 int [] ret = new int [4];
195 get { return !notNull; }
198 public bool IsPositive {
199 get { return positive; }
202 public byte Precision {
203 get { return precision; }
207 get { return scale; }
210 public decimal Value {
213 throw new SqlNullValueException ();
215 if (this.value[3] > 0)
216 throw new OverflowException ();
218 return new decimal (value[0], value[1], value[2], !positive, scale);
226 public static SqlDecimal Abs (SqlDecimal n)
230 return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
233 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
238 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
240 byte prec = n.Precision;
242 throw new SqlNullValueException ();
248 else if (digits > 0) {
249 prec = (byte)(prec + digits);
252 for (int i = 0; i < digits; i++)
254 data = Decimal.GetBits (d);
256 newScale = (byte) (n.scale + digits);
259 n = Round (n, digits + n.scale);
261 n = Round (Truncate (n, digits + n.scale), digits + n.scale);
266 return new SqlDecimal (prec, newScale, n.positive, data);
269 public static SqlDecimal Ceiling (SqlDecimal n)
273 return AdjustScale (n, -(n.Scale), true);
276 public int CompareTo (object value)
280 else if (!(value is SqlDecimal))
281 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlDecimal"));
282 else if (((SqlDecimal)value).IsNull)
285 return this.Value.CompareTo (((SqlDecimal)value).Value);
288 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
290 // return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
292 return AdjustScale (n, scale - n.scale, true);
295 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
300 public override bool Equals (object value)
302 if (!(value is SqlDecimal))
304 else if (this.IsNull && ((SqlDecimal)value).IsNull)
306 else if (((SqlDecimal)value).IsNull)
309 return (bool) (this == (SqlDecimal)value);
312 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
317 public static SqlDecimal Floor (SqlDecimal n)
319 return AdjustScale (n, -(n.Scale), false);
322 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
327 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
330 public override int GetHashCode ()
333 result = 91 * result + this.Data[0];
334 result = 91 * result + this.Data[1];
335 result = 91 * result + this.Data[2];
336 result = 91 * result + this.Data[3];
337 result = 91 * result + (int)this.Scale;
338 result = 91 * result + (int)this.Precision;
343 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
348 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
353 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
358 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
363 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
368 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
373 public static SqlDecimal Parse (string s)
376 throw new ArgumentNullException (Locale.GetText ("string s"));
378 return new SqlDecimal (Decimal.Parse (s));
381 public static SqlDecimal Power (SqlDecimal n, double exp)
384 return SqlDecimal.Null;
386 return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
389 public static SqlDecimal Round (SqlDecimal n, int position)
392 throw new SqlNullValueException ();
395 d = Decimal.Round (d, position);
396 return new SqlDecimal (d);
399 public static SqlInt32 Sign (SqlDecimal n)
403 if (n >= new SqlDecimal (0))
411 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
416 private byte GetPrecision (decimal value)
418 string str = value.ToString ();
421 foreach (char c in str) {
423 if (c >= '0' && c <= '9')
430 public double ToDouble ()
432 // FIXME: This is wrong way to do this
433 double d = (uint)this.Data [0];
434 d += ((uint)this.Data [1]) * Math.Pow (2, 32);
435 d += ((uint)this.Data [2]) * Math.Pow (2, 64);
436 d += ((uint)this.Data [3]) * Math.Pow (2, 96);
437 d = d / Math.Pow (10, scale);
442 public SqlBoolean ToSqlBoolean ()
444 return ((SqlBoolean)this);
447 public SqlByte ToSqlByte ()
449 return ((SqlByte)this);
452 public SqlDouble ToSqlDouble ()
454 return ((SqlDouble)this);
457 public SqlInt16 ToSqlInt16 ()
459 return ((SqlInt16)this);
462 public SqlInt32 ToSqlInt32 ()
464 return ((SqlInt32)this);
467 public SqlInt64 ToSqlInt64 ()
469 return ((SqlInt64)this);
472 public SqlMoney ToSqlMoney ()
474 return ((SqlMoney)this);
477 public SqlSingle ToSqlSingle ()
479 return ((SqlSingle)this);
482 public SqlString ToSqlString ()
484 return ((SqlString)this);
487 public override string ToString ()
492 // convert int [4] --> ulong [2]
493 ulong lo = (uint)this.Data [0];
494 lo += (ulong)((ulong)this.Data [1] << 32);
495 ulong hi = (uint)this.Data [2];
496 hi += (ulong)((ulong)this.Data [3] << 32);
500 StringBuilder Result = new StringBuilder ();
501 for (int i = 0; lo != 0 || hi != 0; i++) {
503 Div128By32 (ref hi, ref lo, 10, ref rest);
504 Result.Insert (0, rest.ToString ());
507 while (Result.Length < this.Precision)
510 while (Result.Length > this.Precision)
511 Result.Remove (Result.Length - 1, 1);
514 Result.Insert (Result.Length - this.Scale, ".");
517 Result.Insert (0, '-');
519 return Result.ToString ();
523 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
526 return Div128By32 (ref hi, ref lo, divider, ref t);
530 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
536 a = (uint)(hi >> 32);
544 hi = b << 32 | (uint)c;
546 a |= (uint)(lo >> 32);
553 lo = b << 32 | (uint)c;
557 return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
561 [MonoTODO("Find out what is the right way to set scale and precision")]
562 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
569 byte prec = 0; // precision
570 bool positive = ! (x.positive ^ y.positive);
572 prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
573 DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
575 sc = x.Scale - y.Scale;
577 Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
581 Div128By32(ref hi, ref lo, 10, ref r);
588 while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
591 while ((prec + sc) > MaxScale) {
592 Div128By32(ref hi, ref lo, 10, ref r);
598 int resultLo = (int)lo;
599 int resultMi = (int)(lo >> 32);
600 int resultMi2 = (int)(hi);
601 int resultHi = (int)(hi >> 32);
603 return new SqlDecimal (prec, (byte)sc, positive, resultLo,
609 private static void Rescale128 (ref ulong clo, ref ulong chi,
610 ref int scale, int texp,
611 int minScale, int maxScale,
625 while (texp > 0 && sc <= maxScale) {
627 overhang = (uint)(chi >> 64);
628 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
631 roundBit = (int)(clo & 1);
632 RShift128 (ref clo, ref chi);
634 overhang = (uint)(chi >> 32);
637 if (texp > DECIMAL_MAX_INTFACTORS)
638 i = DECIMAL_MAX_INTFACTORS;
642 if (sc + i > maxScale)
652 factor = constantsDecadeInt32Factors [i] >> i;
653 // System.Console.WriteLine ("***");
654 Mult128By32 (ref clo, ref chi, factor, 0);
655 // System.Console.WriteLine ((((double)chi) * Math.Pow (2,64) + clo));
661 roundBit = (int)(clo & 1);
662 RShift128 (ref clo, ref chi);
666 while (sc > maxScale) {
667 i = scale - maxScale;
668 if (i > DECIMAL_MAX_INTFACTORS)
669 i = DECIMAL_MAX_INTFACTORS;
671 roundBit = Div128By32 (ref clo, ref chi,
672 constantsDecadeInt32Factors[i]);
675 while (sc < minScale) {
679 if (i > DECIMAL_MAX_INTFACTORS)
680 i = DECIMAL_MAX_INTFACTORS;
682 Mult128By32 (ref clo, ref chi,
683 constantsDecadeInt32Factors[i], roundBit);
687 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
691 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
697 if ((roundFlag != 0) && (roundBit != 0))
698 RoundUp128 (ref clo, ref chi);
702 private static void RoundUp128(ref ulong lo, ref ulong hi)
709 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
723 xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
724 xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
726 ylo = (uint)y.Data [0];
727 ymi = (uint)y.Data [1];
728 ymi2 = (uint)y.Data [2];
729 yhi = (uint)y.Data [3];
731 if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
732 throw new DivideByZeroException ();
734 if (xmi == 0 && xhi == 0) {
739 // enlarge dividend to get maximal precision
740 for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
741 LShift128 (ref xmi, ref xhi);
743 // ensure that divisor is at least 2^95
744 for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
745 LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
747 thi = ((ulong)yhi) << 32 | (ulong)ymi2;
748 tmi = ((ulong)ymi) << 32 | (ulong)ylo;
751 if (xhi > thi || (xhi == thi && xmi >=tmi)) {
752 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
758 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
760 exp = 128 + ashift - bshift;
763 RShift128 (ref clo, ref chi);
764 chi += LIT_GUINT64_HIGHBIT;
768 // try loss free right shift
769 while (exp > 0 && (clo & 1) == 0) {
770 RShift128 (ref clo, ref chi);
776 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
781 lo |= LIT_GUINT64_HIGHBIT;
785 mi |= LIT_GUINT64_HIGHBIT;
791 private static void RShift128(ref ulong lo, ref ulong hi)
795 lo |= LIT_GUINT64_HIGHBIT;
800 private static void LShift128(ref ulong lo, ref ulong hi)
804 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
811 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
814 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
818 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
822 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
829 private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi,
830 uint ylo, uint ymi, uint ymi2,
831 uint yhi, ref ulong clo, ref ulong chi)
833 ulong rlo, rmi, rhi; // remainders
840 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
843 rhi = (rhi << 32) | (rmi >> 32);
844 rmi = (rmi << 32) | (rlo >> 32);
847 chi = (((ulong)h) << 32) | Div192By128To32WithRest (
848 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
851 rhi = (rhi << 32) | (rmi >> 32);
852 rmi = (rmi << 32) | (rlo >> 32);
855 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
856 ylo, ymi, ymi2, yhi);
858 // estimate lowest 32 bit (two last bits may be wrong)
863 c = (uint)(rhi / yhi);
866 clo = (((ulong)h) << 32) | c;
870 private static uint Div192By128To32WithRest(ref ulong xlo, ref ulong xmi,
871 ref ulong xhi, uint ylo,
872 uint ymi, uint ymi2, uint yhi)
874 ulong rlo, rmi, rhi; // remainder
883 if (rhi >= (((ulong)yhi << 32)))
886 c = (uint) (rhi / yhi);
888 Mult128By32To128 (ylo, ymi, ymi2, yhi, c, ref tlo, ref thi);
889 Sub192 (rlo, rmi, rhi, 0, tlo, thi, ref rlo, ref rmi, ref rhi);
891 while (((long)rhi) < 0) {
893 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
903 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
910 a = ((ulong)(uint)clo) * factor;
917 a += (clo >> 32) * factor;
920 clo = ((ulong)h1) << 32 | h0;
923 a += ((ulong)(uint)cmi) * factor;
927 a += (cmi >> 32) * factor;
930 cmi = ((ulong)h1) << 32 | h0;
932 a += ((ulong)(uint)chi) * factor;
936 a += (chi >> 32) * factor;
938 chi = ((ulong)h1) << 32 | h0;
942 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
949 a = ((ulong)(uint)clo) * factor;
957 a += (clo >> 32) * factor;
960 clo = ((ulong)h1) << 32 | h0;
963 a += ((ulong)(uint)chi) * factor;
967 a += (chi >> 32) * factor;
970 chi = ((ulong)h1) << 32 | h0;
975 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
976 uint factor, ref ulong clo, ref ulong chi)
981 a = ((ulong)xlo) * factor;
985 a += ((ulong)xmi) * factor;
989 a += ((ulong)xmi2) * factor;
993 a += ((ulong)xhi) * factor;
995 clo = ((ulong)h1) << 32 | h0;
1000 private static void Add192 (ulong xlo, ulong xmi, ulong xhi,
1001 ulong ylo, ulong ymi, ulong yhi,
1002 ref ulong clo, ref ulong cmi, ref ulong chi)
1023 private static void Sub192 (ulong xlo, ulong xmi, ulong xhi,
1024 ulong ylo, ulong ymi, ulong yhi,
1025 ref ulong lo, ref ulong mi, ref ulong hi)
1050 public static SqlDecimal Truncate (SqlDecimal n, int position)
1052 int diff = n.scale - position;
1055 int [] data = n.Data;
1056 decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
1058 for (int i = 0; i < diff; i++, x *= 10)
1060 data = Decimal.GetBits (d);
1062 return new SqlDecimal (n.precision, n.scale, n.positive, data);
1065 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
1067 // if one of them is negative, perform subtraction
1068 if (x.IsPositive && !y.IsPositive) return x - y;
1069 if (y.IsPositive && !x.IsPositive) return y - x;
1071 // adjust the scale to the larger of the two beforehand
1072 if (x.scale > y.scale)
1073 y = SqlDecimal.AdjustScale (y, x.scale - y.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1074 else if (y.scale > x.scale)
1075 x = SqlDecimal.AdjustScale (x, y.scale - x.scale, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1077 // set the precision to the greater of the two
1078 byte resultPrecision;
1079 if (x.Precision > y.Precision)
1080 resultPrecision = x.Precision;
1082 resultPrecision = y.Precision;
1084 int[] xData = x.Data;
1085 int[] yData = y.Data;
1086 int[] resultBits = new int[4];
1091 // add one at a time, and carry the results over to the next
1092 for (int i = 0; i < 4; i +=1)
1095 res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
1096 if (res > Int32.MaxValue)
1098 carry = res - Int32.MaxValue;
1099 res = Int32.MaxValue;
1101 resultBits [i] = (int)res;
1104 // if we have carry left, then throw an exception
1106 throw new OverflowException ();
1108 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1111 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1113 // return new SqlDecimal (x.Value / y.Value);
1114 return DecimalDiv (x, y);
1117 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1119 if (x.IsNull || y.IsNull)
1120 return SqlBoolean.Null;
1122 if (x.Scale > y.Scale)
1123 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1124 else if (y.Scale > x.Scale)
1125 x = SqlDecimal.AdjustScale(y, y.Scale - x.Scale, false);
1127 for (int i = 0; i < 4; i += 1)
1129 if (x.Data[i] != y.Data[i])
1130 return new SqlBoolean (false);
1132 return new SqlBoolean (true);
1135 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1137 if (x.IsNull || y.IsNull)
1138 return SqlBoolean.Null;
1140 if (x.Scale > y.Scale)
1141 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, false);
1142 else if (y.Scale > x.Scale)
1143 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, false);
1145 for (int i = 3; i >= 0; i--)
1147 if (x.Data[i] == 0 && y.Data[i] == 0)
1150 return new SqlBoolean (x.Data[i] > y.Data[i]);
1152 return new SqlBoolean (false);
1155 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1157 if (x.IsNull || y.IsNull)
1158 return SqlBoolean.Null;
1160 if (x.Scale > y.Scale)
1161 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1162 else if (y.Scale > x.Scale)
1163 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1165 for (int i = 3; i >= 0; i -= 1)
1167 if (x.Data[i] == 0 && y.Data[i] == 0)
1170 return new SqlBoolean (x.Data[i] >= y.Data[i]);
1172 return new SqlBoolean (true);
1175 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1177 if (x.IsNull || y.IsNull)
1178 return SqlBoolean.Null;
1180 if (x.Scale > y.Scale)
1181 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1182 else if (y.Scale > x.Scale)
1183 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1185 for (int i = 0; i < 4; i += 1)
1187 if (x.Data[i] != y.Data[i])
1188 return new SqlBoolean (true);
1190 return new SqlBoolean (false);
1193 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1196 if (x.IsNull || y.IsNull)
1197 return SqlBoolean.Null;
1199 if (x.Scale > y.Scale)
1200 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1201 else if (y.Scale > x.Scale)
1202 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1204 for (int i = 3; i >= 0; i -= 1)
1206 if (x.Data[i] == 0 && y.Data[i] == 0)
1209 return new SqlBoolean (x.Data[i] < y.Data[i]);
1211 return new SqlBoolean (false);
1215 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1217 if (x.IsNull || y.IsNull)
1218 return SqlBoolean.Null;
1220 if (x.Scale > y.Scale)
1221 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1222 else if (y.Scale > x.Scale)
1223 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1225 for (int i = 3; i >= 0; i -= 1)
1227 if (x.Data[i] == 0 && y.Data[i] == 0)
1230 return new SqlBoolean (x.Data[i] <= y.Data[i]);
1232 return new SqlBoolean (true);
1235 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1237 // adjust the scale to the smaller of the two beforehand
1238 if (x.Scale > y.Scale)
1239 x = SqlDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1240 else if (y.Scale > x.Scale)
1241 y = SqlDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1243 // set the precision to the greater of the two
1244 byte resultPrecision;
1245 if (x.Precision > y.Precision)
1246 resultPrecision = x.Precision;
1248 resultPrecision = y.Precision;
1250 int[] xData = x.Data;
1251 int[] yData = y.Data;
1252 int[] resultBits = new int[4];
1257 // multiply one at a time, and carry the results over to the next
1258 for (int i = 0; i < 4; i +=1)
1261 res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
1262 if (res > Int32.MaxValue)
1264 carry = res - Int32.MaxValue;
1265 res = Int32.MaxValue;
1267 resultBits [i] = (int)res;
1270 // if we have carry left, then throw an exception
1272 throw new OverflowException ();
1274 return new SqlDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
1278 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1280 if (x.IsPositive && !y.IsPositive) return x + y;
1281 if (!x.IsPositive && y.IsPositive) return -(x + y);
1282 if (!x.IsPositive && !y.IsPositive) return y - x;
1284 // otherwise, x is positive and y is positive
1285 bool resultPositive = (bool)(x > y);
1286 int[] yData = y.Data;
1288 for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
1290 SqlDecimal yInverse = new SqlDecimal (y.Precision, y.Scale, y.IsPositive, yData);
1293 return x + yInverse;
1295 return -(x + yInverse);
1298 public static SqlDecimal operator - (SqlDecimal n)
1300 return new SqlDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
1303 public static explicit operator SqlDecimal (SqlBoolean x)
1308 return new SqlDecimal ((decimal)x.ByteValue);
1311 public static explicit operator Decimal (SqlDecimal n)
1316 public static explicit operator SqlDecimal (SqlDouble x)
1322 return new SqlDecimal ((double)x.Value);
1326 public static explicit operator SqlDecimal (SqlSingle x)
1332 return new SqlDecimal ((double)x.Value);
1336 public static explicit operator SqlDecimal (SqlString x)
1339 return Parse (x.Value);
1343 public static implicit operator SqlDecimal (decimal x)
1345 return new SqlDecimal (x);
1348 public static implicit operator SqlDecimal (SqlByte x)
1353 return new SqlDecimal ((decimal)x.Value);
1356 public static implicit operator SqlDecimal (SqlInt16 x)
1361 return new SqlDecimal ((decimal)x.Value);
1364 public static implicit operator SqlDecimal (SqlInt32 x)
1369 return new SqlDecimal ((decimal)x.Value);
1372 public static implicit operator SqlDecimal (SqlInt64 x)
1377 return new SqlDecimal ((decimal)x.Value);
1380 public static implicit operator SqlDecimal (SqlMoney x)
1385 return new SqlDecimal ((decimal)x.Value);