**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlDecimal.cs
blob85e33561c69900eaabfafab059244793f1846237
1 //
2 // System.Data.SqlTypes.SqlDecimal
3 //
4 // Author:
5 // Tim Coleman <tim@timcoleman.com>
6 // Ville Palo <vi64pa@koti.soon.fi>
7 //
8 // (C) Copyright 2002 Tim Coleman
9 //
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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;
35 using System;
36 using System.Text;
37 using System.Globalization;
39 namespace System.Data.SqlTypes
41 public struct SqlDecimal : INullable, IComparable
43 #region Fields
45 int[] value;
46 byte precision;
47 byte scale;
48 bool positive;
50 private bool notNull;
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,
70 (byte)0,
71 true,
72 (int)-1,
73 160047679,
74 1518781562,
75 1262177448);
76 // This should be -99999999999999999999999999999999999999
77 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision,
78 (byte)0, false,
79 -1,
80 160047679,
81 1518781562,
82 1262177448);
84 public static readonly SqlDecimal Null;
86 #endregion
88 #region Constructors
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];
105 this.value[3] = 0;
107 if (value >= 0)
108 positive = true;
109 else
110 positive = false;
112 notNull = true;
113 precision = GetPrecision (value);
116 public SqlDecimal (double value) : this ((decimal)value)
118 SqlDecimal n = this;
119 int digits = 17 - precision;
120 if (digits > 0)
121 n = AdjustScale (this, digits, false);
122 else
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;
138 this.scale = bScale;
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;
145 notNull = true;
147 if (precision < scale)
148 throw new SqlTypeException (Locale.GetText ("Invalid presicion/scale combination."));
150 if (precision > 38)
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 ");
158 #endregion
160 #region Properties
162 public byte[] BinData {
163 get {
165 byte [] b = new byte [value.Length * 4];
167 int j = 0;
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);
176 return b;
180 public int[] Data {
181 get {
182 if (this.IsNull)
183 throw new SqlNullValueException ();
184 // Data should always return clone, not to be modified
185 int [] ret = new int [4];
186 ret [0] = value [0];
187 ret [1] = value [1];
188 ret [2] = value [2];
189 ret [3] = value [3];
190 return ret;
194 public bool IsNull {
195 get { return !notNull; }
198 public bool IsPositive {
199 get { return positive; }
202 public byte Precision {
203 get { return precision; }
206 public byte Scale {
207 get { return scale; }
210 public decimal Value {
211 get {
212 if (this.IsNull)
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);
222 #endregion
224 #region Methods
226 public static SqlDecimal Abs (SqlDecimal n)
228 if (!n.notNull)
229 return n;
230 return new SqlDecimal (n.Precision, n.Scale, true, n.Data);
233 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
235 return (x + y);
238 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
240 byte prec = n.Precision;
241 if (n.IsNull)
242 throw new SqlNullValueException ();
244 int [] data;
245 byte newScale;
246 if (digits == 0)
247 return n;
248 else if (digits > 0) {
249 prec = (byte)(prec + digits);
250 decimal d = n.Value;
251 if (digits > 0)
252 for (int i = 0; i < digits; i++)
253 d *= 10;
254 data = Decimal.GetBits (d);
255 data [3] = 0;
256 newScale = (byte) (n.scale + digits);
257 } else {
258 if (fRound)
259 n = Round (n, digits + n.scale);
260 else
261 n = Round (Truncate (n, digits + n.scale), digits + n.scale);
262 data = n.Data;
263 newScale = n.scale;
266 return new SqlDecimal (prec, newScale, n.positive, data);
269 public static SqlDecimal Ceiling (SqlDecimal n)
271 if (!n.notNull)
272 return n;
273 return AdjustScale (n, -(n.Scale), true);
276 public int CompareTo (object value)
278 if (value == null)
279 return 1;
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)
283 return 1;
284 else
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);
291 // FIXME: precision
292 return AdjustScale (n, scale - n.scale, true);
295 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
297 return (x / y);
300 public override bool Equals (object value)
302 if (!(value is SqlDecimal))
303 return false;
304 else if (this.IsNull && ((SqlDecimal)value).IsNull)
305 return true;
306 else if (((SqlDecimal)value).IsNull)
307 return false;
308 else
309 return (bool) (this == (SqlDecimal)value);
312 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
314 return (x == y);
317 public static SqlDecimal Floor (SqlDecimal n)
319 return AdjustScale (n, -(n.Scale), false);
322 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
324 if (x == null)
325 return Null;
326 else
327 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
330 public override int GetHashCode ()
332 int result = 10;
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;
340 return result;
343 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
345 return (x > y);
348 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
350 return (x >= y);
353 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
355 return (x < y);
358 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
360 return (x <= y);
363 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
365 return (x * y);
368 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
370 return (x != y);
373 public static SqlDecimal Parse (string s)
375 if (s == null)
376 throw new ArgumentNullException (Locale.GetText ("string s"));
377 else
378 return new SqlDecimal (Decimal.Parse (s));
381 public static SqlDecimal Power (SqlDecimal n, double exp)
383 if (n.IsNull)
384 return SqlDecimal.Null;
386 return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
389 public static SqlDecimal Round (SqlDecimal n, int position)
391 if (n.IsNull)
392 throw new SqlNullValueException ();
394 decimal d = n.Value;
395 d = Decimal.Round (d, position);
396 return new SqlDecimal (d);
399 public static SqlInt32 Sign (SqlDecimal n)
401 SqlInt32 result = 0;
403 if (n >= new SqlDecimal (0))
404 result = 1;
405 else
406 result = -1;
408 return result;
411 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
413 return (x - y);
416 private byte GetPrecision (decimal value)
418 string str = value.ToString ();
419 byte result = 0;
421 foreach (char c in str) {
423 if (c >= '0' && c <= '9')
424 result++;
427 return result;
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);
439 return d;
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 ()
489 if (this.IsNull)
490 return "Null";
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);
498 uint rest = 0;
499 String result = "";
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)
508 Result.Append ("0");
510 while (Result.Length > this.Precision)
511 Result.Remove (Result.Length - 1, 1);
513 if (this.Scale > 0)
514 Result.Insert (Result.Length - this.Scale, ".");
516 if (!positive)
517 Result.Insert (0, '-');
519 return Result.ToString ();
522 // From decimal.c
523 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
525 uint t = 0;
526 return Div128By32 (ref hi, ref lo, divider, ref t);
529 // From decimal.c
530 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
532 ulong a = 0;
533 ulong b = 0;
534 ulong c = 0;
536 a = (uint)(hi >> 32);
537 b = a / divider;
538 a -= b * divider;
539 a <<= 32;
540 a |= (uint)hi;
541 c = a / divider;
542 a -= c * divider;
543 a <<= 32;
544 hi = b << 32 | (uint)c;
546 a |= (uint)(lo >> 32);
547 b = a / divider;
548 a -= b * divider;
549 a <<= 32;
550 a |= (uint)lo;
551 c = a / divider;
552 a -= c * divider;
553 lo = b << 32 | (uint)c;
554 rest = (uint)a;
555 a <<= 1;
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)
564 ulong lo = 0;
565 ulong hi = 0;
566 int sc = 0; // scale
567 int texp = 0;
568 int rc = 0;
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);
579 uint r = 0;
580 while (prec < sc) {
581 Div128By32(ref hi, ref lo, 10, ref r);
582 sc--;
585 if (r >= 5)
586 lo++;
588 while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
589 prec++;
591 while ((prec + sc) > MaxScale) {
592 Div128By32(ref hi, ref lo, 10, ref r);
593 sc--;
594 if (r >= 5)
595 lo++;
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,
604 resultMi, resultMi2,
605 resultHi);
608 // From decimal.c
609 private static void Rescale128 (ref ulong clo, ref ulong chi,
610 ref int scale, int texp,
611 int minScale, int maxScale,
612 int roundFlag)
614 uint factor = 0;
615 uint overhang = 0;
616 int sc = 0;
617 int i = 0;
618 int rc = 0;
619 int roundBit = 0;
621 sc = scale;
622 if (texp > 0) {
624 // reduce exp
625 while (texp > 0 && sc <= maxScale) {
627 overhang = (uint)(chi >> 64);
628 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
630 if (--texp == 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;
639 else
640 i = texp;
642 if (sc + i > maxScale)
643 i = maxScale - sc;
645 if (i == 0)
646 break;
648 texp -= i;
649 sc += i;
651 // 10^i/2^i=5^i
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));
659 while (texp > 0) {
660 if (--texp == 0)
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;
670 sc -= i;
671 roundBit = Div128By32 (ref clo, ref chi,
672 constantsDecadeInt32Factors[i]);
675 while (sc < minScale) {
676 if (roundFlag == 0)
677 roundBit = 0;
678 i = minScale - sc;
679 if (i > DECIMAL_MAX_INTFACTORS)
680 i = DECIMAL_MAX_INTFACTORS;
681 sc += i;
682 Mult128By32 (ref clo, ref chi,
683 constantsDecadeInt32Factors[i], roundBit);
684 roundBit = 0;
686 scale = sc;
687 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
690 // From decimal.c
691 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
693 int sc = scale;
694 int deltaScale;
696 scale = sc;
697 if ((roundFlag != 0) && (roundBit != 0))
698 RoundUp128 (ref clo, ref chi);
701 // From decimal.c
702 private static void RoundUp128(ref ulong lo, ref ulong hi)
704 if ((++lo) == 0)
705 ++hi;
708 // From decimal.c
709 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
711 ulong xlo, xmi, xhi;
712 ulong tlo = 0;
713 ulong tmi = 0;
714 ulong thi = 0;;
715 uint ylo = 0;
716 uint ymi = 0;
717 uint ymi2 = 0;
718 uint yhi = 0;
719 int ashift = 0;
720 int bshift = 0;
721 int extraBit = 0;
723 xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
724 xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
725 xlo = (uint)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) {
735 clo = chi = 0;
736 return;
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;
749 tlo = 0;
751 if (xhi > thi || (xhi == thi && xmi >=tmi)) {
752 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
753 extraBit = 1;
754 } else {
755 extraBit = 0;
758 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
760 exp = 128 + ashift - bshift;
762 if (extraBit != 0) {
763 RShift128 (ref clo, ref chi);
764 chi += LIT_GUINT64_HIGHBIT;
765 exp--;
768 // try loss free right shift
769 while (exp > 0 && (clo & 1) == 0) {
770 RShift128 (ref clo, ref chi);
771 exp--;
775 // From decimal.c
776 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
779 lo >>= 1;
780 if ((mi & 1) != 0)
781 lo |= LIT_GUINT64_HIGHBIT;
783 mi >>= 1;
784 if ((hi & 1) != 0)
785 mi |= LIT_GUINT64_HIGHBIT;
787 hi >>= 1;
790 // From decimal.c
791 private static void RShift128(ref ulong lo, ref ulong hi)
793 lo >>=1;
794 if ((hi & 1) != 0)
795 lo |= LIT_GUINT64_HIGHBIT;
796 hi >>= 1;
799 // From decimal.c
800 private static void LShift128(ref ulong lo, ref ulong hi)
802 hi <<= 1;
804 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
805 hi++;
807 lo <<= 1;
810 // From decimal.c
811 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
813 hi <<= 1;
814 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
815 hi++;
817 mi2 <<= 1;
818 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
819 mi2++;
821 mi <<= 1;
822 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
823 mi++;
825 lo <<= 1;
828 // From decimal.c
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
834 uint h, c;
836 rlo = xlo;
837 rmi = xmi;
838 rhi = xhi;
840 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
842 // mid 32 bit
843 rhi = (rhi << 32) | (rmi >> 32);
844 rmi = (rmi << 32) | (rlo >> 32);
845 rlo <<= 32;
847 chi = (((ulong)h) << 32) | Div192By128To32WithRest (
848 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
850 // low 32 bit
851 rhi = (rhi << 32) | (rmi >> 32);
852 rmi = (rmi << 32) | (rlo >> 32);
853 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)
859 if (rhi >= yhi)
860 c = 0xFFFFFFFF;
861 else {
862 rhi <<= 32;
863 c = (uint)(rhi / yhi);
866 clo = (((ulong)h) << 32) | c;
869 // From decimal.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
875 ulong tlo = 0;
876 ulong thi = 0;
877 uint c;
879 rlo = xlo;
880 rmi = xmi;
881 rhi = xhi;
883 if (rhi >= (((ulong)yhi << 32)))
884 c = 0xFFFFFFFF;
885 else
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) {
892 c--;
893 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
895 xlo = rlo;
896 xmi = rmi;
897 xhi = rhi;
899 return c;
902 // From decimal.c
903 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
905 ulong a = 0;
906 uint h0 = 0;
907 uint h1 = 0;
908 uint h2 = 0;
910 a = ((ulong)(uint)clo) * factor;
912 if (roundBit != 0)
913 a += factor / 2;
915 h0 = (uint)a;
916 a >>= 32;
917 a += (clo >> 32) * factor;
918 h1 = (uint)a;
920 clo = ((ulong)h1) << 32 | h0;
922 a >>= 32;
923 a += ((ulong)(uint)cmi) * factor;
924 h0 = (uint)a;
926 a >>= 32;
927 a += (cmi >> 32) * factor;
928 h1 = (uint)a;
930 cmi = ((ulong)h1) << 32 | h0;
931 a >>= 32;
932 a += ((ulong)(uint)chi) * factor;
933 h0 = (uint)a;
935 a >>= 32;
936 a += (chi >> 32) * factor;
937 h1 = (uint)a;
938 chi = ((ulong)h1) << 32 | h0;
941 // From decimal.c
942 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
944 ulong a = 0;
945 uint h0 = 0;
946 uint h1 = 0;
947 uint h2 = 0;
949 a = ((ulong)(uint)clo) * factor;
951 if (roundBit != 0)
952 a += factor / 2;
954 h0 = (uint)a;
956 a >>= 32;
957 a += (clo >> 32) * factor;
958 h1 = (uint)a;
960 clo = ((ulong)h1) << 32 | h0;
962 a >>= 32;
963 a += ((ulong)(uint)chi) * factor;
964 h0 = (uint)a;
966 a >>= 32;
967 a += (chi >> 32) * factor;
968 h1 = (uint)a;
970 chi = ((ulong)h1) << 32 | h0;
974 // From decimal.c
975 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
976 uint factor, ref ulong clo, ref ulong chi)
978 ulong a;
979 uint h0, h1, h2;
981 a = ((ulong)xlo) * factor;
982 h0 = (uint)a;
984 a >>= 32;
985 a += ((ulong)xmi) * factor;
986 h1 = (uint)a;
988 a >>= 32;
989 a += ((ulong)xmi2) * factor;
990 h2 = (uint)a;
992 a >>= 32;
993 a += ((ulong)xhi) * factor;
995 clo = ((ulong)h1) << 32 | h0;
996 chi = a | h2;
999 // From decimal.c
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)
1004 xlo += ylo;
1005 if (xlo < ylo) {
1006 xmi++;
1007 if (xmi == 0)
1008 xhi++;
1011 xmi += ymi;
1013 if (xmi < ymi)
1014 xmi++;
1016 xhi += yhi;
1017 clo = xlo;
1018 cmi = xmi;
1019 chi = xhi;
1022 // From decimal.c
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)
1028 ulong clo = 0;
1029 ulong cmi = 0;
1030 ulong chi = 0;
1032 clo = xlo - ylo;
1033 cmi = xmi - ymi;
1034 chi = xhi - yhi;
1036 if (xlo < ylo) {
1037 if (cmi == 0)
1038 chi--;
1039 cmi--;
1042 if (xmi < ymi)
1043 chi--;
1045 lo = clo;
1046 mi = cmi;
1047 hi = chi;
1050 public static SqlDecimal Truncate (SqlDecimal n, int position)
1052 int diff = n.scale - position;
1053 if (diff == 0)
1054 return n;
1055 int [] data = n.Data;
1056 decimal d = new decimal (data [0], data [1], data [2], !n.positive, 0);
1057 decimal x = 10;
1058 for (int i = 0; i < diff; i++, x *= 10)
1059 d = d - d % x;
1060 data = Decimal.GetBits (d);
1061 data [3] = 0;
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;
1081 else
1082 resultPrecision = y.Precision;
1084 int[] xData = x.Data;
1085 int[] yData = y.Data;
1086 int[] resultBits = new int[4];
1088 ulong res;
1089 ulong carry = 0;
1091 // add one at a time, and carry the results over to the next
1092 for (int i = 0; i < 4; i +=1)
1094 carry = 0;
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
1105 if (carry > 0)
1106 throw new OverflowException ();
1107 else
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)
1148 continue;
1149 else
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)
1168 continue;
1169 else
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)
1207 continue;
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)
1228 continue;
1229 else
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;
1247 else
1248 resultPrecision = y.Precision;
1250 int[] xData = x.Data;
1251 int[] yData = y.Data;
1252 int[] resultBits = new int[4];
1254 ulong res;
1255 ulong carry = 0;
1257 // multiply one at a time, and carry the results over to the next
1258 for (int i = 0; i < 4; i +=1)
1260 carry = 0;
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
1271 if (carry > 0)
1272 throw new OverflowException ();
1273 else
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);
1292 if (resultPositive)
1293 return x + yInverse;
1294 else
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)
1305 if (x.IsNull)
1306 return Null;
1307 else
1308 return new SqlDecimal ((decimal)x.ByteValue);
1311 public static explicit operator Decimal (SqlDecimal n)
1313 return n.Value;
1316 public static explicit operator SqlDecimal (SqlDouble x)
1318 checked {
1319 if (x.IsNull)
1320 return Null;
1321 else
1322 return new SqlDecimal ((double)x.Value);
1326 public static explicit operator SqlDecimal (SqlSingle x)
1328 checked {
1329 if (x.IsNull)
1330 return Null;
1331 else
1332 return new SqlDecimal ((double)x.Value);
1336 public static explicit operator SqlDecimal (SqlString x)
1338 checked {
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)
1350 if (x.IsNull)
1351 return Null;
1352 else
1353 return new SqlDecimal ((decimal)x.Value);
1356 public static implicit operator SqlDecimal (SqlInt16 x)
1358 if (x.IsNull)
1359 return Null;
1360 else
1361 return new SqlDecimal ((decimal)x.Value);
1364 public static implicit operator SqlDecimal (SqlInt32 x)
1366 if (x.IsNull)
1367 return Null;
1368 else
1369 return new SqlDecimal ((decimal)x.Value);
1372 public static implicit operator SqlDecimal (SqlInt64 x)
1374 if (x.IsNull)
1375 return Null;
1376 else
1377 return new SqlDecimal ((decimal)x.Value);
1380 public static implicit operator SqlDecimal (SqlMoney x)
1382 if (x.IsNull)
1383 return Null;
1384 else
1385 return new SqlDecimal ((decimal)x.Value);
1388 #endregion