2002-11-21 Tim Coleman <tim@timcoleman.com>
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlDecimal.cs
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 //
10
11 using Mono.Data.Tds.Protocol;
12 using System;
13 using System.Text;
14 using System.Globalization;
15
16 namespace System.Data.SqlTypes
17 {
18         public struct SqlDecimal : INullable, IComparable
19         {
20                 #region Fields
21
22                 int[] value;
23                 byte precision;
24                 byte scale;
25                 bool positive;
26
27                 private bool notNull;
28
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]
37                         {
38                                 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 
39                                 10000000u, 100000000u, 1000000000u
40                         };
41
42                 public static readonly byte MaxPrecision = 38; 
43                 public static readonly byte MaxScale = 38;
44
45                 // This should be 99999999999999999999999999999999999999
46                 public static readonly SqlDecimal MaxValue = new SqlDecimal (MaxPrecision, 
47                                                                              (byte)0, 
48                                                                              true, 
49                                                                              (int)-1, 
50                                                                              160047679,
51                                                                              1518781562, 
52                                                                              1262177448);
53                 // This should be -99999999999999999999999999999999999999
54                 public static readonly SqlDecimal MinValue = new SqlDecimal (MaxPrecision, 
55                                                                              (byte)0, false,
56                                                                              -1,                                                
57                                                                              160047679,
58                                                                              1518781562, 
59                                                                              1262177448);
60
61                 public static readonly SqlDecimal Null;
62
63                 #endregion
64
65                 #region Constructors
66
67                 public SqlDecimal (decimal value) 
68                 {
69                         int[] binData = Decimal.GetBits (value);
70
71                         this.precision = MaxPrecision; // this value seems unclear
72
73                         this.scale = (byte)(((uint)binData [3]) >> SCALE_SHIFT);
74                         
75                         if (this.scale > MaxScale || ((uint)binData [3] & RESERVED_SS32_BITS) != 0)
76                                 throw new ArgumentException(Locale.GetText ("Invalid scale"));
77
78                         this.value = new int[4];
79                         this.value[0] = binData[0];
80                         this.value[1] = binData[1];
81                         this.value[2] = binData[2];
82                         this.value[3] = 0;
83
84                         if (value >= 0)
85                                 positive = true;
86                         else 
87                                 positive = false;
88
89                         notNull = true;
90                         precision = GetPrecision (value);
91                 }
92                                 
93                 public SqlDecimal (double value) : this ((decimal)value) { }
94                 public SqlDecimal (int value) : this ((decimal)value) { }
95                 public SqlDecimal (long value) : this ((decimal)value) { }
96
97                 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
98
99                 [MonoTODO]
100                 public SqlDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4) 
101                 {
102                         this.precision = bPrecision;
103                         this.scale = bScale;
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;
110                         notNull = true;
111                         
112                         if (precision < scale)
113                                 throw new ArgumentException(Locale.GetText ("Invalid scale"));
114
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");
119                 }
120
121                 #endregion
122
123                 #region Properties
124
125                 public byte[] BinData {
126                         get { 
127
128                                 byte [] b = new byte [value.Length * 4];
129                                 
130                                 int j = 0;
131                                 for (int i = 0; i < value.Length; i++) {
132
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);
137                                 }
138
139                                 return b;
140                         }
141                 }
142
143                 public int[] Data { 
144                         get { 
145                                 if (this.IsNull)
146                                         throw new SqlNullValueException ();
147                                 else
148                                         return (value);
149                         }
150                 }
151
152                 public bool IsNull { 
153                         get { return !notNull; }
154                 }
155
156                 public bool IsPositive { 
157                         get { return positive; }
158                 }
159
160                 public byte Precision { 
161                         get { return precision; }
162                 }
163
164                 public byte Scale { 
165                         get { return scale; }
166                 }
167
168                 public decimal Value { 
169                         get { 
170                                 if (this.IsNull) 
171                                         throw new SqlNullValueException ();
172
173                                 if (this.value[3] > 0)
174                                         throw new OverflowException ();
175
176                                 return new decimal (value[0], value[1], value[2], !positive, scale);
177                         }
178                 }
179
180                 #endregion
181
182                 #region Methods
183
184                 public static SqlDecimal Abs (SqlDecimal n)
185                 {
186                                 return new SqlDecimal (n.Precision, n.Scale, true, 
187                                                        n.BinData [0], n.BinData [1], 
188                                                        n.BinData [2], n.BinData [3]);
189                 }
190
191                 public static SqlDecimal Add (SqlDecimal x, SqlDecimal y)
192                 {
193                         return (x + y);
194                 }
195
196                 public static SqlDecimal AdjustScale (SqlDecimal n, int digits, bool fRound)
197                 {
198                         byte prec = n.Precision;
199                         if (n.IsNull)
200                                 throw new SqlNullValueException ();
201
202                         if (digits > 0)
203                                 prec = (byte)(prec + digits);
204
205                         if (fRound)
206                                 n = Round (n, digits + n.Scale);
207
208                         return new SqlDecimal (prec, 
209                                                (byte)(n.Scale + digits), 
210                                                n.IsPositive, n.Data);
211                 }
212
213                 public static SqlDecimal Ceiling (SqlDecimal n)
214                 {
215                         return AdjustScale (n, -(n.Scale), true);
216                 }
217
218                 public int CompareTo (object value)
219                 {
220                         if (value == null)
221                                 return 1;
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)
225                                 return 1;
226                         else
227                                 return this.Value.CompareTo (((SqlDecimal)value).Value);
228                 }
229
230                 public static SqlDecimal ConvertToPrecScale (SqlDecimal n, int precision, int scale)
231                 {
232                         return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
233                 }
234
235                 public static SqlDecimal Divide (SqlDecimal x, SqlDecimal y)
236                 {
237                         return (x / y);
238                 }
239
240                 public override bool Equals (object value)
241                 {
242                         if (!(value is SqlDecimal))
243                                 return false;
244                         else if (this.IsNull && ((SqlDecimal)value).IsNull)
245                                 return true;                    
246                         else if (((SqlDecimal)value).IsNull)
247                                 return false;
248                         else
249                                 return (bool) (this == (SqlDecimal)value);
250                 }
251
252                 public static SqlBoolean Equals (SqlDecimal x, SqlDecimal y)
253                 {
254                         return (x == y);
255                 }
256
257                 public static SqlDecimal Floor (SqlDecimal n)
258                 {
259                         return AdjustScale (n, -(n.Scale), false);
260                 }
261
262                 internal static SqlDecimal FromTdsBigDecimal (TdsBigDecimal x)
263                 {
264                         if (x == null)
265                                 return Null;
266                         else
267                                 return new SqlDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
268                 }
269
270                 public override int GetHashCode ()
271                 {
272                         int result = 10;
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;
279
280                         return result;
281                 }
282
283                 public static SqlBoolean GreaterThan (SqlDecimal x, SqlDecimal y)
284                 {
285                         return (x > y);
286                 }
287
288                 public static SqlBoolean GreaterThanOrEqual (SqlDecimal x, SqlDecimal y)
289                 {
290                         return (x >= y);
291                 }
292
293                 public static SqlBoolean LessThan (SqlDecimal x, SqlDecimal y)
294                 {
295                         return (x < y);
296                 }
297
298                 public static SqlBoolean LessThanOrEqual (SqlDecimal x, SqlDecimal y)
299                 {
300                         return (x <= y);
301                 }
302
303                 public static SqlDecimal Multiply (SqlDecimal x, SqlDecimal y)
304                 {
305                         return (x * y);
306                 }
307
308                 public static SqlBoolean NotEquals (SqlDecimal x, SqlDecimal y)
309                 {
310                         return (x != y);
311                 }
312
313                 [MonoTODO]
314                 public static SqlDecimal Parse (string s)
315                 {
316                         // FIXME: Huh, There must be better way to do this
317                         if (s == null)
318                                 throw new ArgumentNullException ();
319                         else 
320                                 return SqlDouble.Parse (s).ToSqlDecimal ();
321                 }
322
323                 public static SqlDecimal Power (SqlDecimal n, double exp)
324                 {
325                         if (n.IsNull)
326                                 return SqlDecimal.Null;
327
328                         return new SqlDecimal (Math.Pow (n.ToDouble (), exp));
329                 }
330
331                 [MonoTODO]
332                 public static SqlDecimal Round (SqlDecimal n, int position)
333                 {
334                         // FIXME: There must be better way to do this
335                         if (n.IsNull)
336                                 throw new SqlNullValueException ();
337
338                         SqlDecimal result = new SqlDecimal (Math.Round (
339                                 (double)(n.ToDouble () * Math.Pow (10, position))));
340
341                         result = result / new SqlDecimal(Math.Pow (10, position));
342                         
343                         return result;                          
344                 }
345
346                 public static SqlInt32 Sign (SqlDecimal n)
347                 {
348                         SqlInt32 result = 0;
349
350                         if (n >= new SqlDecimal (0))
351                                 result = 1;
352                         else
353                                 result = -1;
354
355                         return result;
356                 }
357
358                 public static SqlDecimal Subtract (SqlDecimal x, SqlDecimal y)
359                 {
360                         return (x - y);
361                 }
362
363                 private byte GetPrecision (decimal value)
364                 {
365                         string str = value.ToString ();
366                         byte result = 0;
367
368                         foreach (char c in str) {
369                                 
370                                 if (c >= '0' && c <= '9')
371                                         result++;
372                         }
373                         
374                         return result;
375                 }
376
377                 public double ToDouble ()
378                 {
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);
385
386                         return d;
387                 }
388
389                 public SqlBoolean ToSqlBoolean ()
390                 {
391                         return ((SqlBoolean)this);
392                 }
393                 
394                 public SqlByte ToSqlByte ()
395                 {
396                         return ((SqlByte)this);
397                 }
398
399                 public SqlDouble ToSqlDouble ()
400                 {
401                         return ((SqlDouble)this);
402                 }
403
404                 public SqlInt16 ToSqlInt16 ()
405                 {
406                         return ((SqlInt16)this);
407                 }
408
409                 public SqlInt32 ToSqlInt32 ()
410                 {
411                         return ((SqlInt32)this);
412                 }
413
414                 public SqlInt64 ToSqlInt64 ()
415                 {
416                         return ((SqlInt64)this);
417                 }
418
419                 public SqlMoney ToSqlMoney ()
420                 {
421                         return ((SqlMoney)this);
422                 }
423
424                 public SqlSingle ToSqlSingle ()
425                 {
426                         return ((SqlSingle)this);
427                 }
428
429                 public SqlString ToSqlString ()
430                 {
431                         return ((SqlString)this);
432                 }
433
434                 public override string ToString ()
435                 {
436                         if (this.IsNull)
437                                 return String.Empty;
438                         
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);
444
445                         uint rest = 0;
446                         String result = "";
447                         StringBuilder Result = new StringBuilder ();
448                         for (int i = 0; lo != 0 || hi != 0; i++) {
449                         
450                                 Div128By32 (ref hi, ref lo, 10, ref rest);
451                                 Result.Insert (0, rest.ToString ());
452                         }
453
454                         while (Result.Length < this.Precision)
455                                 Result.Append ("0");
456
457                         while (Result.Length > this.Precision)
458                                Result.Remove (Result.Length - 1, 1);
459  
460                         if (this.Scale > 0)
461                                 Result.Insert (Result.Length - this.Scale, ".");
462
463                         return Result.ToString ();
464                 }
465
466                 // From decimal.c
467                 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider)
468                 {
469                         uint t = 0;
470                         return Div128By32 (ref hi, ref lo, divider, ref t);
471                 }
472
473                 // From decimal.c
474                 private static int Div128By32(ref ulong hi, ref ulong lo, uint divider, ref uint rest)
475                 {
476                         ulong a = 0;
477                         ulong b = 0;
478                         ulong c = 0;    
479                         
480                         a = (uint)(hi >> 32);
481                         b = a / divider;
482                         a -= b * divider;
483                         a <<= 32;
484                         a |= (uint)hi;
485                         c = a / divider;
486                         a -= c * divider;
487                         a <<= 32;
488                         hi = b << 32 | (uint)c;
489                         
490                         a |= (uint)(lo >> 32);
491                         b = a / divider;
492                         a -= b * divider;
493                         a <<= 32;
494                         a |= (uint)lo;
495                         c = a / divider;
496                         a -= c * divider;
497                         lo = b << 32 | (uint)c;
498                         rest = (uint)a;
499                         a <<= 1;
500
501                         return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
502
503                 }
504
505                 [MonoTODO("Find out what is the right way to set scale and precision")]
506                 private static SqlDecimal DecimalDiv (SqlDecimal x, SqlDecimal y)
507                 {
508                         ulong lo = 0; 
509                         ulong hi = 0;                   
510                         int sc = 0; // scale
511                         int texp = 0;
512                         int rc = 0;
513                         byte prec = 0; // precision
514
515                         prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
516                         DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
517
518                         sc = x.Scale - y.Scale;
519
520                         Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
521
522                         uint r = 0;
523                         while (prec < sc) {
524                                 Div128By32(ref hi, ref lo, 10, ref r);
525                                 sc--;
526                         }                               
527                                 
528                         if (r >= 5) 
529                                 lo++;
530                        
531                         while ((((double)hi) * Math.Pow(2,64) + lo) - Math.Pow (10, prec) > 0)
532                                 prec++;
533
534                         while ((prec + sc) > MaxScale) {
535                                 Div128By32(ref hi, ref lo, 10, ref r);
536                                 sc--;
537                                 if (r >= 5)
538                                         lo++;
539                         }
540                                 
541                         int resultLo = (int)lo;
542                         int resultMi = (int)(lo >> 32);
543                         int resultMi2 = (int)(hi);
544                         int resultHi = (int)(hi >> 32);
545
546                         return new SqlDecimal (prec, (byte)sc, true, resultLo,
547                                                        resultMi, resultMi2,
548                                                        resultHi);
549                 }
550
551                 // From decimal.c
552                 private static void Rescale128 (ref ulong clo, ref ulong chi, 
553                                              ref int scale, int texp,
554                                              int minScale, int maxScale,
555                                              int roundFlag)
556                 {
557                         uint factor = 0;
558                         uint overhang = 0;
559                         int sc = 0;
560                         int i = 0;
561                         int rc = 0;
562                         int roundBit = 0;
563
564                         sc = scale;
565                         if (texp > 0) {
566
567                                 // reduce exp 
568                                 while (texp > 0 && sc <= maxScale) {
569
570                                                 overhang = (uint)(chi >> 64);
571                                         while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
572                                                 
573                                                 if (--texp == 0)
574                                                         roundBit = (int)(clo & 1);
575                                                 RShift128 (ref clo, ref chi);
576
577                                                 overhang = (uint)(chi >> 32);
578                                         }
579
580                                         if (texp > DECIMAL_MAX_INTFACTORS)
581                                                 i = DECIMAL_MAX_INTFACTORS;
582                                         else 
583                                                 i = texp;
584
585                                         if (sc + i > maxScale) 
586                                                 i = maxScale - sc;
587
588                                         if (i == 0)
589                                                 break;
590
591                                         texp -= i;
592                                         sc += i;
593
594                                         // 10^i/2^i=5^i 
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));
599
600                                 }
601
602                                 while (texp > 0) {
603                                         if (--texp == 0) 
604                                                 roundBit = (int)(clo & 1);
605                                         RShift128 (ref clo, ref chi);
606                                 }
607                         }
608         
609                         while (sc > maxScale) {
610                                 i = scale - maxScale;
611                                 if (i > DECIMAL_MAX_INTFACTORS)
612                                         i = DECIMAL_MAX_INTFACTORS;
613                                 sc -= i;
614                                 roundBit = Div128By32 (ref clo, ref chi, 
615                                                        constantsDecadeInt32Factors[i]);
616                         }
617
618                         while (sc < minScale) {
619                                 if (roundFlag == 0)
620                                         roundBit = 0;
621                                 i = minScale - sc;
622                                 if (i > DECIMAL_MAX_INTFACTORS)
623                                         i = DECIMAL_MAX_INTFACTORS;
624                                 sc += i;
625                                 Mult128By32 (ref clo, ref chi, 
626                                              constantsDecadeInt32Factors[i], roundBit);
627                                 roundBit = 0;
628                         }
629                         scale = sc;
630                         Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
631                 }
632
633                 // From decimal.c
634                 private static void Normalize128(ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
635                 {
636                         int sc = scale;
637                         int deltaScale;
638                         
639                         scale = sc;
640                         if ((roundFlag != 0) && (roundBit != 0)) 
641                                 RoundUp128 (ref clo, ref chi); 
642                 }
643
644                 // From decimal.c
645                 private static void RoundUp128(ref ulong lo, ref ulong hi)
646                 {
647                             if ((++lo) == 0) 
648                                     ++hi;
649                 }
650                 
651                 // From decimal.c
652                 private static void DecimalDivSub (ref SqlDecimal x, ref SqlDecimal y, ref ulong clo, ref ulong chi, ref int exp)
653                 {
654                         ulong xlo, xmi, xhi;
655                         ulong tlo = 0; 
656                         ulong tmi = 0;
657                         ulong thi = 0;;
658                         uint ylo = 0;
659                         uint ymi = 0;
660                         uint ymi2 = 0;
661                         uint yhi = 0;
662                         int ashift = 0; 
663                         int bshift = 0;
664                         int extraBit = 0;
665
666                         xhi = (ulong)((ulong)x.Data [3] << 32) | (ulong)x.Data [2];
667                         xmi = (ulong)((ulong)x.Data [1] << 32) | (ulong)x.Data [0];
668                         xlo = (uint)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];
673                         
674                         if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
675                                 throw new DivideByZeroException ();
676
677                         if (xmi == 0 && xhi == 0) {
678                                 clo = chi = 0;
679                                 return;
680                         }
681                         
682                         // enlarge dividend to get maximal precision
683                         for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
684                                 LShift128 (ref xmi, ref xhi);
685                         
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);
689                         
690                         thi = ((ulong)yhi) << 32 | (ulong)ymi2;
691                         tmi = ((ulong)ymi) << 32 | (ulong)ylo;
692                         tlo = 0;
693
694                         if (xhi > thi || (xhi == thi && xmi >=tmi)) {
695                                 Sub192(xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
696                                 extraBit = 1;
697                         } else {
698                                 extraBit = 0;
699                         }
700                         
701                         Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
702  
703                         exp = 128 + ashift - bshift;
704
705                         if (extraBit != 0) {
706                                 RShift128 (ref clo, ref chi);
707                                 chi += LIT_GUINT64_HIGHBIT;
708                                 exp--;
709                         }
710                          
711                         // try loss free right shift
712                         while (exp > 0 && (clo & 1) == 0) {
713                                 RShift128 (ref clo, ref chi);
714                                 exp--;
715                         }                       
716                 }
717
718                 // From decimal.c
719                 private static void RShift192(ref ulong lo, ref ulong mi, ref ulong hi)
720                 {
721                         
722                         lo >>= 1;
723                         if ((mi & 1) != 0)
724                                 lo |= LIT_GUINT64_HIGHBIT;
725                         
726                         mi >>= 1;
727                         if ((hi & 1) != 0)
728                                 mi |= LIT_GUINT64_HIGHBIT;
729
730                         hi >>= 1;
731                 }
732
733                 // From decimal.c
734                 private static void RShift128(ref ulong lo, ref ulong hi)
735                 {
736                         lo >>=1;
737                         if ((hi & 1) != 0) 
738                                 lo |= LIT_GUINT64_HIGHBIT;
739                         hi >>= 1;
740                 }
741                 
742                 // From decimal.c
743                 private static void LShift128(ref ulong lo, ref ulong hi)
744                 {
745                         hi <<= 1;
746
747                         if ((lo & LIT_GUINT64_HIGHBIT) != 0) 
748                                 hi++;
749
750                         lo <<= 1;
751                 }
752                 
753                 // From decimal.c
754                 private static void LShift128(ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
755                 {
756                         hi <<= 1;
757                         if ((mi2 & LIT_GUINT32_HIGHBIT) != 0) 
758                                 hi++;
759
760                         mi2 <<= 1;
761                         if ((mi & LIT_GUINT32_HIGHBIT) != 0) 
762                                 mi2++;
763                         
764                         mi <<= 1;
765                         if ((lo & LIT_GUINT32_HIGHBIT) != 0) 
766                                mi++;
767
768                         lo <<= 1;
769                 }
770
771                 // From decimal.c
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)
775                 {
776                         ulong rlo, rmi, rhi; // remainders
777                         uint h, c;
778
779                         rlo = xlo;
780                         rmi = xmi;
781                         rhi = xhi;
782
783                         h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
784
785                         // mid 32 bit
786                         rhi = (rhi << 32) | (rmi >> 32);
787                         rmi = (rmi << 32) | (rlo >> 32);
788                         rlo <<= 32;
789
790                         chi = (((ulong)h) << 32) | Div192By128To32WithRest (
791                                 ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
792
793                         // low 32 bit
794                         rhi = (rhi << 32) | (rmi >> 32);
795                         rmi = (rmi << 32) | (rlo >> 32);
796                         rlo <<= 32;
797
798                         h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi,
799                                                      ylo, ymi, ymi2, yhi);
800
801                         // estimate lowest 32 bit (two last bits may be wrong)
802                         if (rhi >= yhi) 
803                                 c =  0xFFFFFFFF;
804                         else {
805                                 rhi <<= 32;
806                                 c = (uint)(rhi / yhi);
807                         }
808                                 
809                         clo = (((ulong)h) << 32) | c;
810                 }
811                         
812                 // From decimal.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)
816                 {
817                         ulong rlo, rmi, rhi; // remainder                      
818                         ulong tlo = 0;
819                         ulong thi = 0;
820                         uint c;
821                         
822                         rlo = xlo;
823                         rmi = xmi;
824                         rhi = xhi;
825
826                         if (rhi >= (((ulong)yhi << 32)))
827                                 c = 0xFFFFFFFF;
828                         else
829                                 c = (uint) (rhi / yhi);
830
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);
833
834                         while (((long)rhi) < 0) {
835                                 c--;
836                                 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
837                         }
838                         xlo = rlo;
839                         xmi = rmi;
840                         xhi = rhi;
841
842                         return c;                       
843                 }
844
845                 // From decimal.c
846                 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
847                 {
848                         ulong a = 0;
849                         uint h0 = 0;
850                         uint h1 = 0;
851                         uint h2 = 0;
852
853                         a = ((ulong)(uint)clo) * factor;
854
855                         if (roundBit != 0)
856                                 a += factor / 2;
857
858                         h0 = (uint)a;
859                         a >>= 32;
860                         a += (clo >> 32) * factor;
861                         h1 = (uint)a;
862                         
863                         clo = ((ulong)h1) << 32 | h0;
864
865                         a >>= 32;
866                         a += ((ulong)(uint)cmi) * factor;                      
867                         h0 = (uint)a;
868                         
869                         a >>= 32;
870                         a += (cmi >> 32) * factor;
871                         h1 = (uint)a;
872                         
873                         cmi = ((ulong)h1) << 32 | h0;
874                         a >>= 32;
875                         a += ((ulong)(uint)chi) * factor;                      
876                         h0 = (uint)a;
877
878                         a >>= 32;
879                         a += (chi >> 32) * factor;
880                         h1 = (uint)a;
881                         chi = ((ulong)h1) << 32 | h0;
882                 }
883
884                 // From decimal.c
885                 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
886                 {
887                         ulong a = 0;
888                         uint h0 = 0;
889                         uint h1 = 0;
890                         uint h2 = 0;
891
892                         a = ((ulong)(uint)clo) * factor;
893
894                         if (roundBit != 0)
895                                 a += factor / 2;
896
897                         h0 = (uint)a;
898
899                         a >>= 32;
900                         a += (clo >> 32) * factor;
901                         h1 = (uint)a;
902                         
903                         clo = ((ulong)h1) << 32 | h0;
904
905                         a >>= 32;
906                         a += ((ulong)(uint)chi) * factor;                      
907                         h0 = (uint)a;
908                         
909                         a >>= 32;
910                         a += (chi >> 32) * factor;
911                         h1 = (uint)a;
912                         
913                         chi = ((ulong)h1) << 32 | h0;
914                 }
915                                                  
916
917                 // From decimal.c
918                 private static void Mult128By32To128(uint xlo, uint xmi, uint xmi2, uint xhi,
919                                          uint factor, ref ulong clo, ref ulong chi)
920                 {
921                         ulong a;
922                         uint h0, h1, h2;
923
924                         a = ((ulong)xlo) * factor;
925                         h0 = (uint)a;
926                         
927                         a >>= 32;
928                         a += ((ulong)xmi) * factor;
929                         h1 = (uint)a;
930
931                         a >>= 32;
932                         a += ((ulong)xmi2) * factor;
933                         h2 = (uint)a;
934
935                         a >>= 32;
936                         a += ((ulong)xhi) * factor;
937                         
938                         clo = ((ulong)h1) << 32 | h0;
939                         chi = a | h2;
940                 }
941
942                 // From decimal.c
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)
946                 {
947                         xlo += ylo;
948                         if (xlo < ylo) {
949                                 xmi++;
950                                 if (xmi == 0)
951                                         xhi++;
952                         }
953
954                         xmi += ymi;
955
956                         if (xmi < ymi)
957                                 xmi++;
958
959                         xhi += yhi;
960                         clo = xlo;
961                         cmi = xmi;
962                         chi = xhi;                            
963                 }
964
965                 // From decimal.c
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)
969                 {
970                         
971                         ulong clo = 0;
972                         ulong cmi = 0;
973                         ulong chi = 0;
974                         
975                         clo = xlo - ylo;
976                         cmi = xmi - ymi;
977                         chi = xhi - yhi;
978
979                         if (xlo < ylo) {
980                                 if (cmi == 0)
981                                         chi--;
982                                 cmi--;
983                         }
984
985                         if (xmi < ymi)
986                                 chi--;
987
988                         lo = clo;
989                         mi = cmi;
990                         hi = chi;
991                 }
992
993                 public static SqlDecimal Truncate (SqlDecimal n, int position)
994                 {
995                         int prec = n.Precision;// + (position - n.Scale);
996                         int sc = position;
997                         return new SqlDecimal ((byte)prec, (byte)sc,
998                                                n.IsPositive, n.Data);
999                 }
1000
1001                 public static SqlDecimal operator + (SqlDecimal x, SqlDecimal y)
1002                 {
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;
1006                 
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);
1012
1013                         // set the precision to the greater of the two
1014                         byte resultPrecision;
1015                         if (x.Precision > y.Precision)
1016                                 resultPrecision = x.Precision;
1017                         else
1018                                 resultPrecision = y.Precision;
1019                                 
1020                         int[] xData = x.Data;
1021                         int[] yData = y.Data;
1022                         int[] resultBits = new int[4];
1023
1024                         ulong res; 
1025                         ulong carry = 0;
1026
1027                         // add one at a time, and carry the results over to the next
1028                         for (int i = 0; i < 4; i +=1)
1029                         {
1030                                 carry = 0;
1031                                 res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
1032                                 if (res > Int32.MaxValue)
1033                                 {
1034                                         carry = res - Int32.MaxValue;
1035                                         res = Int32.MaxValue;
1036                                 }
1037                                 resultBits [i] = (int)res;
1038                         }
1039
1040                         // if we have carry left, then throw an exception
1041                         if (carry > 0)
1042                                 throw new OverflowException ();
1043                         else
1044                                 return new SqlDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
1045                 }
1046
1047                 public static SqlDecimal operator / (SqlDecimal x, SqlDecimal y)
1048                 {
1049                         //                      return new SqlDecimal (x.Value / y.Value);
1050                         return DecimalDiv (x, y);
1051                 }
1052
1053                 public static SqlBoolean operator == (SqlDecimal x, SqlDecimal y)
1054                 {
1055                         if (x.IsNull || y.IsNull) 
1056                                 return SqlBoolean.Null;
1057
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);
1062
1063                         for (int i = 0; i < 4; i += 1)
1064                         {
1065                                 if (x.Data[i] != y.Data[i])
1066                                         return new SqlBoolean (false);
1067                         }
1068                         return new SqlBoolean (true);
1069                 }
1070
1071                 public static SqlBoolean operator > (SqlDecimal x, SqlDecimal y)
1072                 {
1073                         if (x.IsNull || y.IsNull) 
1074                                 return SqlBoolean.Null;
1075
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);
1080
1081                         for (int i = 3; i >= 0; i--)
1082                         {
1083                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1084                                         continue;
1085                                 else
1086                                         return new SqlBoolean (x.Data[i] > y.Data[i]);
1087                         }
1088                         return new SqlBoolean (false);
1089                 }
1090
1091                 public static SqlBoolean operator >= (SqlDecimal x, SqlDecimal y)
1092                 {
1093                         if (x.IsNull || y.IsNull) 
1094                                 return SqlBoolean.Null;
1095
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);
1100
1101                         for (int i = 3; i >= 0; i -= 1)
1102                         {
1103                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1104                                         continue;
1105                                 else
1106                                         return new SqlBoolean (x.Data[i] >= y.Data[i]);
1107                         }
1108                         return new SqlBoolean (true);
1109                 }
1110
1111                 public static SqlBoolean operator != (SqlDecimal x, SqlDecimal y)
1112                 {
1113                         if (x.IsNull || y.IsNull) 
1114                                 return SqlBoolean.Null;
1115
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);
1120
1121                         for (int i = 0; i < 4; i += 1)
1122                         {
1123                                 if (x.Data[i] != y.Data[i])
1124                                         return new SqlBoolean (true);
1125                         }
1126                         return new SqlBoolean (false);
1127                 }
1128
1129                 public static SqlBoolean operator < (SqlDecimal x, SqlDecimal y)
1130                 {
1131
1132                         if (x.IsNull || y.IsNull) 
1133                                 return SqlBoolean.Null;
1134
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);
1139
1140                         for (int i = 3; i >= 0; i -= 1)
1141                         {
1142                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1143                                         continue;
1144
1145                                 return new SqlBoolean (x.Data[i] < y.Data[i]);
1146                         }
1147                         return new SqlBoolean (false);
1148
1149                 }
1150
1151                 public static SqlBoolean operator <= (SqlDecimal x, SqlDecimal y)
1152                 {
1153                         if (x.IsNull || y.IsNull) 
1154                                 return SqlBoolean.Null;
1155
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);
1160
1161                         for (int i = 3; i >= 0; i -= 1)
1162                         {
1163                                 if (x.Data[i] == 0 && y.Data[i] == 0) 
1164                                         continue;
1165                                 else
1166                                         return new SqlBoolean (x.Data[i] <= y.Data[i]);
1167                         }
1168                         return new SqlBoolean (true);
1169                 }
1170
1171                 public static SqlDecimal operator * (SqlDecimal x, SqlDecimal y)
1172                 {
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);
1178
1179                         // set the precision to the greater of the two
1180                         byte resultPrecision;
1181                         if (x.Precision > y.Precision)
1182                                 resultPrecision = x.Precision;
1183                         else
1184                                 resultPrecision = y.Precision;
1185                                 
1186                         int[] xData = x.Data;
1187                         int[] yData = y.Data;
1188                         int[] resultBits = new int[4];
1189
1190                         ulong res; 
1191                         ulong carry = 0;
1192
1193                         // multiply one at a time, and carry the results over to the next
1194                         for (int i = 0; i < 4; i +=1)
1195                         {
1196                                 carry = 0;
1197                                 res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
1198                                 if (res > Int32.MaxValue)
1199                                 {
1200                                         carry = res - Int32.MaxValue;
1201                                         res = Int32.MaxValue;
1202                                 }
1203                                 resultBits [i] = (int)res;
1204                         }
1205
1206                         // if we have carry left, then throw an exception
1207                         if (carry > 0)
1208                                 throw new OverflowException ();
1209                         else
1210                                 return new SqlDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
1211                                 
1212                 }
1213
1214                 public static SqlDecimal operator - (SqlDecimal x, SqlDecimal y)
1215                 {
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;
1219
1220                         // otherwise, x is positive and y is positive
1221                         bool resultPositive = (bool)(x > y);
1222                         int[] yData = y.Data;
1223
1224                         for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
1225
1226                         SqlDecimal yInverse = new SqlDecimal (y.Precision, y.Scale, y.IsPositive, yData);
1227
1228                         if (resultPositive)
1229                                 return x + yInverse;
1230                         else
1231                                 return -(x + yInverse);
1232                 }
1233
1234                 public static SqlDecimal operator - (SqlDecimal n)
1235                 {
1236                         return new SqlDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
1237                 }
1238
1239                 public static explicit operator SqlDecimal (SqlBoolean x)
1240                 {
1241                         if (x.IsNull) 
1242                                 return Null;
1243                         else
1244                                 return new SqlDecimal ((decimal)x.ByteValue);
1245                 }
1246
1247                 public static explicit operator Decimal (SqlDecimal n)
1248                 {
1249                         return n.Value;
1250                 }
1251
1252                 public static explicit operator SqlDecimal (SqlDouble x)
1253                 {
1254                         checked {
1255                                 if (x.IsNull) 
1256                                         return Null;
1257                                 else
1258                                         return new SqlDecimal ((decimal)x.Value);
1259                         }
1260                 }
1261
1262                 public static explicit operator SqlDecimal (SqlSingle x)
1263                 {
1264                         checked {
1265                                 if (x.IsNull) 
1266                                         return Null;
1267                                 else
1268                                         return new SqlDecimal ((decimal)x.Value);
1269                         }
1270                 }
1271
1272                 public static explicit operator SqlDecimal (SqlString x)
1273                 {
1274                         checked {
1275                                 return Parse (x.Value);
1276                         }
1277                 }
1278
1279                 public static implicit operator SqlDecimal (decimal x)
1280                 {
1281                         return new SqlDecimal (x);
1282                 }
1283
1284                 public static implicit operator SqlDecimal (SqlByte x)
1285                 {
1286                         if (x.IsNull) 
1287                                 return Null;
1288                         else
1289                                 return new SqlDecimal ((decimal)x.Value);
1290                 }
1291
1292                 public static implicit operator SqlDecimal (SqlInt16 x)
1293                 {
1294                         if (x.IsNull) 
1295                                 return Null;
1296                         else
1297                                 return new SqlDecimal ((decimal)x.Value);
1298                 }
1299
1300                 public static implicit operator SqlDecimal (SqlInt32 x)
1301                 {
1302                         if (x.IsNull) 
1303                                 return Null;
1304                         else
1305                                 return new SqlDecimal ((decimal)x.Value);
1306                 }
1307
1308                 public static implicit operator SqlDecimal (SqlInt64 x)
1309                 {
1310                         if (x.IsNull) 
1311                                 return Null;
1312                         else
1313                                 return new SqlDecimal ((decimal)x.Value);
1314                 }
1315
1316                 public static implicit operator SqlDecimal (SqlMoney x)
1317                 {
1318                         if (x.IsNull) 
1319                                 return Null;
1320                         else
1321                                 return new SqlDecimal ((decimal)x.Value);
1322                 }
1323
1324                 #endregion
1325         }
1326 }