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