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