**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Data.SybaseClient / Mono.Data.SybaseTypes / SybaseDecimal.cs
blob62a4b99cd055152a9f07495ceab3fea9937be5ca
1 //
2 // Mono.Data.SybaseTypes.SybaseDecimal
3 //
4 // Author:
5 // Tim Coleman <tim@timcoleman.com>
6 //
7 // Based on System.Data.SqlTypes.SqlDecimal
8 //
9 // (C) Ximian, Inc. 2002-2003
10 // (C) Copyright Tim Coleman, 2002
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using Mono.Data.Tds.Protocol;
35 using System;
36 using System.Data.SqlTypes;
37 using System.Globalization;
38 using System.Text;
40 namespace Mono.Data.SybaseTypes {
41 public struct SybaseDecimal : INullable, IComparable
44 #region Fields
46 int[] value;
47 byte precision;
48 byte scale;
49 bool positive;
51 bool notNull;
53 // borrowed from System.Decimal
54 const int SCALE_SHIFT = 16;
55 const int SIGN_SHIFT = 31;
56 const int RESERVED_SS32_BITS = 0x7F00FFFF;
57 const ulong LIT_GUINT64_HIGHBIT = 0x8000000000000000;
58 const ulong LIT_GUINT32_HIGHBIT = 0x80000000;
59 const byte DECIMAL_MAX_INTFACTORS = 9;
60 static uint [] constantsDecadeInt32Factors = new uint [10]
62 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
63 10000000u, 100000000u, 1000000000u
66 public static readonly byte MaxPrecision = 38;
67 public static readonly byte MaxScale = 38;
69 public static readonly SybaseDecimal MaxValue = new SybaseDecimal (MaxPrecision, (byte)0, true, (int)716002642, Int32.MaxValue, (int)1518778966, (int)1262177448);
70 public static readonly SybaseDecimal MinValue = new SybaseDecimal (MaxPrecision, (byte)0, false, (int)716002642, Int32.MaxValue, (int)1518778966, (int)1262177448);
71 public static readonly SybaseDecimal Null;
73 #endregion
75 #region Constructors
77 public SybaseDecimal (decimal value)
79 int[] binData = Decimal.GetBits (value);
81 this.scale = (byte)(binData[3] >> SCALE_SHIFT);
82 if (this.scale > MaxScale || (this.scale & RESERVED_SS32_BITS) != 0)
83 throw new ArgumentException(Locale.GetText ("Invalid scale"));
85 this.value = new int[4];
86 this.value[0] = binData[0];
87 this.value[1] = binData[1];
88 this.value[2] = binData[2];
89 this.value[3] = 0;
90 notNull = true;
92 positive = (value >= 0);
93 precision = GetPrecision (value);
96 public SybaseDecimal (double value) : this ((decimal)value) { }
97 public SybaseDecimal (int value) : this ((decimal)value) { }
98 public SybaseDecimal (long value) : this ((decimal)value) { }
100 public SybaseDecimal (byte bPrecision, byte bScale, bool fPositive, int[] bits) : this (bPrecision, bScale, fPositive, bits[0], bits[1], bits[2], bits[3]) { }
102 public SybaseDecimal (byte bPrecision, byte bScale, bool fPositive, int data1, int data2, int data3, int data4)
104 this.precision = bPrecision;
105 this.scale = bScale;
106 this.positive = fPositive;
107 this.value = new int[4];
108 this.value[0] = data1;
109 this.value[1] = data2;
110 this.value[2] = data3;
111 this.value[3] = data4;
112 notNull = true;
114 if (precision < scale)
115 throw new ArgumentException ("Invalid scale");
116 if (this.ToDouble () > (System.Math.Pow (10, 38) -1) || this.ToDouble () < -(System.Math.Pow (10, 38)))
117 throw new SybaseTypeException ("Can't convert to SybaseDecimal.");
120 #endregion
122 #region Properties
124 public byte[] BinData {
125 get {
126 byte[] b = new byte [value.Length * 4];
127 int j = 0;
128 for (int i = 0; i < value.Length; i += 1) {
129 b [j++] = (byte) (0xff & value [i]);
130 b [j++] = (byte) (0xff & value [i] >> 8);
131 b [j++] = (byte) (0xff & value [i] >> 16);
132 b [j++] = (byte) (0xff & value [i] >> 24);
134 return b;
138 public int[] Data {
139 get {
140 if (this.IsNull)
141 throw new SybaseNullValueException ();
142 else
143 return (value);
147 public bool IsNull {
148 get { return !notNull; }
151 public bool IsPositive {
152 get { return positive; }
155 public byte Precision {
156 get { return precision; }
159 public byte Scale {
160 get { return scale; }
163 public decimal Value {
164 get {
165 if (this.IsNull)
166 throw new SybaseNullValueException ();
167 if (this.value[3] > 0)
168 throw new OverflowException ();
169 return new decimal (value[0], value[1], value[2], !positive, scale);
173 #endregion
175 #region Methods
177 public static SybaseDecimal Abs (SybaseDecimal n)
179 return new SybaseDecimal (n.Precision, n.Scale, true, n.BinData [0], n.BinData [1], n.BinData [2], n.BinData [3]);
182 public static SybaseDecimal Add (SybaseDecimal x, SybaseDecimal y)
184 return (x + y);
187 public static SybaseDecimal AdjustScale (SybaseDecimal n, int digits, bool fRound)
189 byte prec = n.Precision;
190 if (n.IsNull)
191 throw new SybaseNullValueException ();
192 if (digits > 0)
193 prec = (byte) (prec + digits);
194 if (fRound)
195 n = Round (n, digits + n.Scale);
196 return new SybaseDecimal (prec, (byte) (n.Scale + digits), n.IsPositive, n.Data);
199 public static SybaseDecimal Ceiling (SybaseDecimal n)
201 return AdjustScale (n, -(n.Scale), true);
204 public int CompareTo (object value)
206 if (value == null)
207 return 1;
208 else if (!(value is SybaseDecimal))
209 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SybaseTypes.SybaseDecimal"));
210 else if (((SybaseDecimal)value).IsNull)
211 return 1;
212 else
213 return this.Value.CompareTo (((SybaseDecimal)value).Value);
216 public static SybaseDecimal ConvertToPrecScale (SybaseDecimal n, int precision, int scale)
218 return new SybaseDecimal ((byte) precision, (byte) scale, n.IsPositive, n.Data);
221 public static SybaseDecimal Divide (SybaseDecimal x, SybaseDecimal y)
223 return (x / y);
226 public override bool Equals (object value)
228 if (!(value is SybaseDecimal))
229 return false;
230 else if (this.IsNull && ((SybaseDecimal) value).IsNull)
231 return true;
232 else if (((SybaseDecimal) value).IsNull)
233 return false;
234 else
235 return (bool) (this == (SybaseDecimal)value);
238 public static SybaseBoolean Equals (SybaseDecimal x, SybaseDecimal y)
240 return (x == y);
243 public static SybaseDecimal Floor (SybaseDecimal n)
245 return AdjustScale (n, -(n.Scale), false);
248 internal static SybaseDecimal FromTdsBigDecimal (TdsBigDecimal x)
250 if (x == null)
251 return Null;
252 else
253 return new SybaseDecimal (x.Precision, x.Scale, !x.IsNegative, x.Data);
256 public override int GetHashCode ()
258 int result = 10;
259 result = 91 * result + this.Data [0];
260 result = 91 * result + this.Data [1];
261 result = 91 * result + this.Data [2];
262 result = 91 * result + this.Data [3];
263 result = 91 * result + (int) this.Scale;
264 result = 91 * result + (int) this.Precision;
266 return result;
269 public static SybaseBoolean GreaterThan (SybaseDecimal x, SybaseDecimal y)
271 return (x > y);
274 public static SybaseBoolean GreaterThanOrEqual (SybaseDecimal x, SybaseDecimal y)
276 return (x >= y);
279 public static SybaseBoolean LessThan (SybaseDecimal x, SybaseDecimal y)
281 return (x < y);
284 public static SybaseBoolean LessThanOrEqual (SybaseDecimal x, SybaseDecimal y)
286 return (x <= y);
289 public static SybaseDecimal Multiply (SybaseDecimal x, SybaseDecimal y)
291 return (x * y);
294 public static SybaseBoolean NotEquals (SybaseDecimal x, SybaseDecimal y)
296 return (x != y);
299 public static SybaseDecimal Parse (string s)
301 if (s == null)
302 throw new ArgumentNullException ();
303 else
304 return SybaseDouble.Parse (s).ToSybaseDecimal ();
307 public static SybaseDecimal Power (SybaseDecimal n, double exp)
309 if (n.IsNull)
310 return SybaseDecimal.Null;
311 return new SybaseDecimal (System.Math.Pow (n.ToDouble (), exp));
314 public static SybaseDecimal Round (SybaseDecimal n, int position)
316 if (n.IsNull)
317 throw new SybaseNullValueException ();
318 SybaseDecimal result = new SybaseDecimal (System.Math.Round ((double) (n.ToDouble () * System.Math.Pow (10, position))));
319 result = result / new SybaseDecimal (System.Math.Pow (10, position));
320 return result;
323 public static SybaseInt32 Sign (SybaseDecimal n)
325 SybaseInt32 result = 0;
326 if (n >= new SybaseDecimal (0))
327 result = 1;
328 else
329 result = -1;
330 return result;
333 public static SybaseDecimal Subtract (SybaseDecimal x, SybaseDecimal y)
335 return (x - y);
338 private static byte GetPrecision (decimal value)
340 string str = value.ToString ();
341 byte result = 0;
342 foreach (char c in str)
343 if (c >= '0' && c <= '9')
344 result ++;
345 return result;
348 public double ToDouble ()
350 // FIXME: This is the wrong way to do this
351 double d = (uint) this.Data [0];
352 d += ((uint) this.Data [1]) * System.Math.Pow (2, 32);
353 d += ((uint) this.Data [2]) * System.Math.Pow (2, 64);
354 d += ((uint) this.Data [3]) * System.Math.Pow (2, 96);
355 d /= System.Math.Pow (10, scale);
356 return d;
359 public SybaseBoolean ToSybaseBoolean ()
361 return ((SybaseBoolean)this);
364 public SybaseByte ToSybaseByte ()
366 return ((SybaseByte)this);
369 public SybaseDouble ToSybaseDouble ()
371 return ((SybaseDouble)this);
374 public SybaseInt16 ToSybaseInt16 ()
376 return ((SybaseInt16)this);
379 public SybaseInt32 ToSybaseInt32 ()
381 return ((SybaseInt32)this);
384 public SybaseInt64 ToSybaseInt64 ()
386 return ((SybaseInt64)this);
389 public SybaseMoney ToSybaseMoney ()
391 return ((SybaseMoney)this);
394 public SybaseSingle ToSybaseSingle ()
396 return ((SybaseSingle)this);
399 public SybaseString ToSybaseString ()
401 return ((SybaseString)this);
404 public override string ToString ()
406 if (this.IsNull)
407 return String.Empty;
409 // convert int [4] -> ulong [2]
410 ulong lo = (uint) this.Data [0] + (ulong) ((ulong) this.Data [1] << 32);
411 ulong hi = (uint) this.Data [2] + (ulong) ((ulong) this.Data [3] << 32);
413 uint rest = 0;
414 StringBuilder result = new StringBuilder ();
415 for (int i = 0; lo != 0 || hi != 0; i += 1) {
416 Div128By32 (ref hi, ref lo, 10, ref rest);
417 result.Insert (0, rest.ToString ());
419 while (result.Length < Precision)
420 result.Append ("0");
421 while (result.Length > Precision)
422 result.Remove (result.Length - 1, 1);
423 if (Scale > 0)
424 result.Insert (result.Length - Scale, ".");
425 return result.ToString ();
428 // from decimal.c
429 private static int Div128By32 (ref ulong hi, ref ulong lo, uint divider)
431 uint t = 0;
432 return Div128By32 (ref hi, ref lo, divider, ref t);
435 // from decimal.c
436 private static int Div128By32 (ref ulong hi, ref ulong lo, uint divider, ref uint rest)
438 ulong a = 0;
439 ulong b = 0;
440 ulong c = 0;
442 a = (uint) (hi >> 32);
443 b = a / divider;
444 a -= b * divider;
445 a <<= 32;
446 a |= (uint) hi;
447 c = a / divider;
448 a -= c * divider;
449 a <<= 32;
450 hi = b << 32 | (uint) c;
452 a = (uint) (lo >> 32);
453 b = a / divider;
454 a -= b * divider;
455 a <<= 32;
456 a |= (uint) lo;
457 c = a / divider;
458 a -= c * divider;
459 a <<= 32;
460 lo = b << 32 | (uint) c;
462 rest = (uint) a;
463 a <<= 1;
465 return (a > divider || (a == divider && (c & 1) == 1)) ? 1 : 0;
468 [MonoTODO ("Find out what is the right way to set scale and precision")]
469 private static SybaseDecimal DecimalDiv (SybaseDecimal x, SybaseDecimal y)
471 ulong lo = 0;
472 ulong hi = 0;
473 int sc = 0; // scale
474 int texp = 0;
475 byte prec = 0;
477 prec = x.Precision >= y.Precision ? x.Precision : y.Precision;
478 DecimalDivSub (ref x, ref y, ref lo, ref hi, ref texp);
480 sc = x.Scale - y.Scale;
482 Rescale128 (ref lo, ref hi, ref sc, texp, 0, 38, 1);
484 uint r = 0;
485 while (prec < sc) {
486 Div128By32 (ref hi, ref lo, 10, ref r);
487 sc -= 1;
490 if (r >= 5)
491 lo += 1;
493 while ((((double) hi) * System.Math.Pow (2, 64) + lo) - System.Math.Pow (10, prec) > 0)
494 prec += 1;
496 while ((prec + sc) > MaxScale) {
497 Div128By32 (ref hi, ref lo, 10, ref r);
498 sc -= 1;
499 if (r >= 5)
500 lo += 1;
503 int resultLo = (int) lo;
504 int resultMi = (int) (lo >> 32);
505 int resultMi2 = (int) hi;
506 int resultHi = (int) (hi >> 32);
508 return new SybaseDecimal (prec, (byte) sc, true, resultLo, resultMi, resultMi2, resultHi);
511 // From decimal.c
512 private static void Rescale128 (ref ulong clo, ref ulong chi, ref int scale, int texp, int minScale, int maxScale, int roundFlag)
514 uint factor = 0;
515 uint overhang = 0;
516 int sc = 0;
517 int i = 0;
518 int roundBit = 0;
520 sc = scale;
521 if (texp > 0) {
522 // reduce exp
523 while (texp > 0 && sc <= maxScale) {
524 overhang = (uint) (chi >> 64);
525 while (texp > 0 && (((clo & 1) == 0) || overhang > 0)) {
526 if (--texp == 0)
527 roundBit = (int) (clo & 1);
528 RShift128 (ref clo, ref chi);
529 overhang = (uint) (chi >> 32);
532 if (texp > DECIMAL_MAX_INTFACTORS)
533 i = DECIMAL_MAX_INTFACTORS;
534 else
535 i = texp;
537 if (sc + i > maxScale)
538 i = maxScale - sc;
539 if (i == 0)
540 break;
542 texp -= i;
543 sc += i;
545 // 10^i/2^i=5^i
546 factor = constantsDecadeInt32Factors [i] >> i;
547 Mult128By32 (ref clo, ref chi, factor, 0);
550 while (texp > 0) {
551 if (--texp == 0)
552 roundBit = (int) (clo & 1);
553 RShift128 (ref clo, ref chi);
558 while (sc > maxScale) {
559 i = scale - maxScale;
560 if (i > DECIMAL_MAX_INTFACTORS)
561 i = DECIMAL_MAX_INTFACTORS;
562 sc -= i;
563 roundBit = Div128By32 (ref clo, ref chi, constantsDecadeInt32Factors [i]);
566 while (sc < minScale) {
567 if (roundFlag == 0)
568 roundBit = 0;
569 i = minScale - sc;
570 if (i > DECIMAL_MAX_INTFACTORS)
571 i = DECIMAL_MAX_INTFACTORS;
572 sc += i;
573 Mult128By32 (ref clo, ref chi, constantsDecadeInt32Factors [i], roundBit);
574 roundBit = 0;
576 scale = sc;
577 Normalize128 (ref clo, ref chi, ref sc, roundFlag, roundBit);
580 // from decimal.c
581 private static void Normalize128 (ref ulong clo, ref ulong chi, ref int scale, int roundFlag, int roundBit)
583 if ((roundFlag != 0) && (roundBit != 0))
584 RoundUp128 (ref clo, ref chi);
587 // from decimal.c
588 private static void RoundUp128 (ref ulong lo, ref ulong hi)
590 if ((++lo) == 0)
591 ++hi;
594 // from decimal.c
595 private static void DecimalDivSub (ref SybaseDecimal x, ref SybaseDecimal y, ref ulong clo, ref ulong chi, ref int exp)
597 ulong xlo, xmi, xhi;
598 ulong tlo = 0;
599 ulong tmi = 0;
600 ulong thi = 0;
601 uint ylo = 0;
602 uint ymi = 0;
603 uint ymi2 = 0;
604 uint yhi = 0;
605 int ashift = 0;
606 int bshift = 0;
607 int extraBit = 0;
609 xhi = (ulong) ((ulong) x.Data [3] << 32) | (ulong) x.Data [2];
610 xmi = (ulong) ((ulong) x.Data [1] << 32) | (ulong) x.Data [0];
611 xlo = (uint) 0;
612 ylo = (uint) y.Data [0];
613 ymi = (uint) y.Data [1];
614 ymi2 = (uint) y.Data [2];
615 yhi = (uint) y.Data [3];
617 if (ylo == 0 && ymi == 0 && ymi2 == 0 && yhi == 0)
618 throw new DivideByZeroException ();
619 if (xmi == 0 && xhi == 0) {
620 clo = chi = 0;
621 return;
624 // enlarge dividend to get maximal precision
625 for (ashift = 0; (xhi & LIT_GUINT64_HIGHBIT) == 0; ++ashift)
626 LShift128 (ref xmi, ref xhi);
628 // ensure that divisor is at least 2^95
629 for (bshift = 0; (yhi & LIT_GUINT32_HIGHBIT) == 0; ++bshift)
630 LShift128 (ref ylo, ref ymi, ref ymi2, ref yhi);
632 thi = ((ulong) yhi) << 32 | (ulong) ymi2;
633 tmi = ((ulong) ymi) << 32 | (ulong) ylo;
634 tlo = 0;
636 if (xhi > thi || (xhi == thi && xmi >= tmi)) {
637 Sub192 (xlo, xmi, xhi, tlo, tmi, thi, ref xlo, ref xmi, ref xhi);
638 extraBit = 1;
639 } else {
640 extraBit = 0;
643 Div192By128To128 (xlo, xmi, xhi, ylo, ymi, ymi2, yhi, ref clo, ref chi);
645 exp = 128 + ashift - bshift;
647 if (extraBit != 0) {
648 RShift128 (ref clo, ref chi);
649 chi += LIT_GUINT64_HIGHBIT;
650 exp -= 1;
653 // try loss free right shift
654 while (exp > 0 && (clo & 1) == 0) {
655 RShift128 (ref clo, ref chi);
656 exp -= 1;
660 // From decimal.c
661 private static void RShift192 (ref ulong lo, ref ulong mi, ref ulong hi)
663 lo >>= 1;
664 if ((mi & 1) != 0)
665 lo |= LIT_GUINT64_HIGHBIT;
667 mi >>= 1;
668 if ((hi & 1) != 0)
669 mi |= LIT_GUINT64_HIGHBIT;
671 hi >>= 1;
674 // From decimal.c
675 private static void RShift128 (ref ulong lo, ref ulong hi)
677 lo >>= 1;
678 if ((hi & 1) != 0)
679 lo |= LIT_GUINT64_HIGHBIT;
680 hi >>= 1;
683 // From decimal.c
684 private static void LShift128 (ref ulong lo, ref ulong hi)
686 hi <<= 1;
688 if ((lo & LIT_GUINT64_HIGHBIT) != 0)
689 hi += 1;
691 lo <<= 1;
694 // From decimal.c
695 private static void LShift128 (ref uint lo, ref uint mi, ref uint mi2, ref uint hi)
697 hi <<= 1;
698 if ((mi2 & LIT_GUINT32_HIGHBIT) != 0)
699 hi += 1;
701 mi2 <<= 1;
702 if ((mi & LIT_GUINT32_HIGHBIT) != 0)
703 mi2 += 1;
705 mi <<= 1;
706 if ((lo & LIT_GUINT32_HIGHBIT) != 0)
707 mi += 1;
709 lo <<= 1;
712 // From decimal.c
713 private static void Div192By128To128 (ulong xlo, ulong xmi, ulong xhi, uint ylo, uint ymi, uint ymi2, uint yhi, ref ulong clo, ref ulong chi)
715 ulong rlo, rmi, rhi; // remainders
716 uint h, c;
718 rlo = xlo;
719 rmi = xmi;
720 rhi = xhi;
722 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
724 // mid 32 bit
725 rhi = (rhi << 32) | (rmi >> 32);
726 rmi = (rmi << 32) | (rlo >> 32);
727 rlo <<= 32;
729 chi = (((ulong)h) << 32) | Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
731 // low 32 bit
732 rhi = (rhi << 32) | (rmi >> 32);
733 rmi = (rmi << 32) | (rlo >> 32);
734 rlo <<= 32;
736 h = Div192By128To32WithRest (ref rlo, ref rmi, ref rhi, ylo, ymi, ymi2, yhi);
738 // estimate lowest 32 bit (two last bits may be wrong)
739 if (rhi >= yhi)
740 c = 0xFFFFFFFF;
741 else {
742 rhi <<= 32;
743 c = (uint)(rhi / yhi);
746 clo = (((ulong)h) << 32) | c;
749 // From decimal.c
750 private static uint Div192By128To32WithRest (ref ulong xlo, ref ulong xmi, ref ulong xhi, uint ylo, uint ymi, uint ymi2, uint yhi)
752 ulong rlo, rmi, rhi; // remainder
753 ulong tlo = 0;
754 ulong thi = 0;
755 uint c;
757 rlo = xlo;
758 rmi = xmi;
759 rhi = xhi;
761 if (rhi >= (((ulong)yhi << 32)))
762 c = 0xFFFFFFFF;
763 else
764 c = (uint) (rhi / yhi);
766 Mult128By32To128 (ylo, ymi, ymi2, yhi, c, ref tlo, ref thi);
767 Sub192 (rlo, rmi, rhi, 0, tlo, thi, ref rlo, ref rmi, ref rhi);
769 while (((long)rhi) < 0) {
770 c--;
771 Add192 (rlo, rmi, rhi, 0, (((ulong)ymi) << 32) | ylo, yhi | ymi2, ref rlo, ref rmi, ref rhi);
773 xlo = rlo;
774 xmi = rmi;
775 xhi = rhi;
777 return c;
780 // From decimal.c
781 private static void Mult192By32 (ref ulong clo, ref ulong cmi, ref ulong chi, ulong factor, int roundBit)
783 ulong a = 0;
784 uint h0 = 0;
785 uint h1 = 0;
787 a = ((ulong)(uint)clo) * factor;
789 if (roundBit != 0)
790 a += factor / 2;
792 h0 = (uint)a;
793 a >>= 32;
794 a += (clo >> 32) * factor;
795 h1 = (uint)a;
797 clo = ((ulong)h1) << 32 | h0;
799 a >>= 32;
800 a += ((ulong)(uint)cmi) * factor;
801 h0 = (uint)a;
803 a >>= 32;
804 a += (cmi >> 32) * factor;
805 h1 = (uint)a;
807 cmi = ((ulong)h1) << 32 | h0;
808 a >>= 32;
809 a += ((ulong)(uint)chi) * factor;
810 h0 = (uint)a;
812 a >>= 32;
813 a += (chi >> 32) * factor;
814 h1 = (uint)a;
815 chi = ((ulong)h1) << 32 | h0;
818 // From decimal.c
819 private static void Mult128By32 (ref ulong clo, ref ulong chi, uint factor, int roundBit)
821 ulong a = 0;
822 uint h0 = 0;
823 uint h1 = 0;
825 a = ((ulong)(uint)clo) * factor;
827 if (roundBit != 0)
828 a += factor / 2;
830 h0 = (uint)a;
832 a >>= 32;
833 a += (clo >> 32) * factor;
834 h1 = (uint)a;
836 clo = ((ulong)h1) << 32 | h0;
838 a >>= 32;
839 a += ((ulong)(uint)chi) * factor;
840 h0 = (uint)a;
842 a >>= 32;
843 a += (chi >> 32) * factor;
844 h1 = (uint)a;
846 chi = ((ulong)h1) << 32 | h0;
849 // From decimal.c
850 private static void Mult128By32To128 (uint xlo, uint xmi, uint xmi2, uint xhi, uint factor, ref ulong clo, ref ulong chi)
852 ulong a;
853 uint h0, h1, h2;
855 a = ((ulong)xlo) * factor;
856 h0 = (uint)a;
858 a >>= 32;
859 a += ((ulong)xmi) * factor;
860 h1 = (uint)a;
862 a >>= 32;
863 a += ((ulong)xmi2) * factor;
864 h2 = (uint)a;
866 a >>= 32;
867 a += ((ulong)xhi) * factor;
869 clo = ((ulong)h1) << 32 | h0;
870 chi = a | h2;
873 // From decimal.c
874 private static void Add192 (ulong xlo, ulong xmi, ulong xhi, ulong ylo, ulong ymi, ulong yhi, ref ulong clo, ref ulong cmi, ref ulong chi)
876 xlo += ylo;
877 if (xlo < ylo) {
878 xmi++;
879 if (xmi == 0)
880 xhi++;
883 xmi += ymi;
885 if (xmi < ymi)
886 xmi++;
888 xhi += yhi;
889 clo = xlo;
890 cmi = xmi;
891 chi = xhi;
894 // From decimal.c
895 private static void Sub192 (ulong xlo, ulong xmi, ulong xhi, ulong ylo, ulong ymi, ulong yhi, ref ulong lo, ref ulong mi, ref ulong hi)
897 ulong clo = 0;
898 ulong cmi = 0;
899 ulong chi = 0;
901 clo = xlo - ylo;
902 cmi = xmi - ymi;
903 chi = xhi - yhi;
905 if (xlo < ylo) {
906 if (cmi == 0)
907 chi--;
908 cmi--;
911 if (xmi < ymi)
912 chi--;
914 lo = clo;
915 mi = cmi;
916 hi = chi;
919 public static SybaseDecimal Truncate (SybaseDecimal n, int position)
921 return new SybaseDecimal ((byte) n.Precision, (byte) position, n.IsPositive, n.Data);
924 public static SybaseDecimal operator + (SybaseDecimal x, SybaseDecimal y)
926 // if one of them is negative, perform subtraction
927 if (x.IsPositive && !y.IsPositive) return x - y;
928 if (y.IsPositive && !x.IsPositive) return y - x;
930 // adjust the scale to the smaller of the two beforehand
931 if (x.Scale > y.Scale)
932 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
933 else if (y.Scale > x.Scale)
934 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
936 // set the precision to the greater of the two
937 byte resultPrecision;
938 if (x.Precision > y.Precision)
939 resultPrecision = x.Precision;
940 else
941 resultPrecision = y.Precision;
943 int[] xData = x.Data;
944 int[] yData = y.Data;
945 int[] resultBits = new int[4];
947 ulong res;
948 ulong carry = 0;
950 // add one at a time, and carry the results over to the next
951 for (int i = 0; i < 4; i +=1)
953 carry = 0;
954 res = (ulong)(xData[i]) + (ulong)(yData[i]) + carry;
955 if (res > Int32.MaxValue)
957 carry = res - Int32.MaxValue;
958 res = Int32.MaxValue;
960 resultBits [i] = (int)res;
963 // if we have carry left, then throw an exception
964 if (carry > 0)
965 throw new OverflowException ();
966 else
967 return new SybaseDecimal (resultPrecision, x.Scale, x.IsPositive, resultBits);
970 public static SybaseDecimal operator / (SybaseDecimal x, SybaseDecimal y)
972 return DecimalDiv (x, y);
975 public static SybaseBoolean operator == (SybaseDecimal x, SybaseDecimal y)
977 if (x.IsNull || y.IsNull)
978 return SybaseBoolean.Null;
980 if (x.Scale > y.Scale)
981 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
982 else if (y.Scale > x.Scale)
983 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
985 for (int i = 0; i < 4; i += 1)
987 if (x.Data[i] != y.Data[i])
988 return new SybaseBoolean (false);
990 return new SybaseBoolean (true);
993 public static SybaseBoolean operator > (SybaseDecimal x, SybaseDecimal y)
995 if (x.IsNull || y.IsNull)
996 return SybaseBoolean.Null;
998 if (x.Scale > y.Scale)
999 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1000 else if (y.Scale > x.Scale)
1001 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1003 for (int i = 3; i >= 0; i -= 1)
1005 if (x.Data[i] == 0 && y.Data[i] == 0)
1006 continue;
1007 else
1008 return new SybaseBoolean (x.Data[i] > y.Data[i]);
1010 return new SybaseBoolean (false);
1013 public static SybaseBoolean operator >= (SybaseDecimal x, SybaseDecimal y)
1015 if (x.IsNull || y.IsNull)
1016 return SybaseBoolean.Null;
1018 if (x.Scale > y.Scale)
1019 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1020 else if (y.Scale > x.Scale)
1021 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1023 for (int i = 3; i >= 0; i -= 1)
1025 if (x.Data[i] == 0 && y.Data[i] == 0)
1026 continue;
1027 else
1028 return new SybaseBoolean (x.Data[i] >= y.Data[i]);
1030 return new SybaseBoolean (true);
1033 public static SybaseBoolean operator != (SybaseDecimal x, SybaseDecimal y)
1035 if (x.IsNull || y.IsNull)
1036 return SybaseBoolean.Null;
1038 if (x.Scale > y.Scale)
1039 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1040 else if (y.Scale > x.Scale)
1041 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1043 for (int i = 0; i < 4; i += 1)
1045 if (x.Data[i] != y.Data[i])
1046 return new SybaseBoolean (true);
1048 return new SybaseBoolean (false);
1051 public static SybaseBoolean operator < (SybaseDecimal x, SybaseDecimal y)
1053 if (x.IsNull || y.IsNull)
1054 return SybaseBoolean.Null;
1056 if (x.Scale > y.Scale)
1057 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1058 else if (y.Scale > x.Scale)
1059 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1061 for (int i = 3; i >= 0; i -= 1)
1063 if (x.Data[i] == 0 && y.Data[i] == 0)
1064 continue;
1066 return new SybaseBoolean (x.Data[i] < y.Data[i]);
1068 return new SybaseBoolean (false);
1071 public static SybaseBoolean operator <= (SybaseDecimal x, SybaseDecimal y)
1073 if (x.IsNull || y.IsNull)
1074 return SybaseBoolean.Null;
1076 if (x.Scale > y.Scale)
1077 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1078 else if (y.Scale > x.Scale)
1079 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1081 for (int i = 3; i >= 0; i -= 1)
1083 if (x.Data[i] == 0 && y.Data[i] == 0)
1084 continue;
1085 else
1086 return new SybaseBoolean (x.Data[i] <= y.Data[i]);
1088 return new SybaseBoolean (true);
1091 public static SybaseDecimal operator * (SybaseDecimal x, SybaseDecimal y)
1093 // adjust the scale to the smaller of the two beforehand
1094 if (x.Scale > y.Scale)
1095 x = SybaseDecimal.AdjustScale(x, y.Scale - x.Scale, true);
1096 else if (y.Scale > x.Scale)
1097 y = SybaseDecimal.AdjustScale(y, x.Scale - y.Scale, true);
1099 // set the precision to the greater of the two
1100 byte resultPrecision;
1101 if (x.Precision > y.Precision)
1102 resultPrecision = x.Precision;
1103 else
1104 resultPrecision = y.Precision;
1106 int[] xData = x.Data;
1107 int[] yData = y.Data;
1108 int[] resultBits = new int[4];
1110 ulong res;
1111 ulong carry = 0;
1113 // multiply one at a time, and carry the results over to the next
1114 for (int i = 0; i < 4; i +=1)
1116 carry = 0;
1117 res = (ulong)(xData[i]) * (ulong)(yData[i]) + carry;
1118 if (res > Int32.MaxValue)
1120 carry = res - Int32.MaxValue;
1121 res = Int32.MaxValue;
1123 resultBits [i] = (int)res;
1126 // if we have carry left, then throw an exception
1127 if (carry > 0)
1128 throw new OverflowException ();
1129 else
1130 return new SybaseDecimal (resultPrecision, x.Scale, (x.IsPositive == y.IsPositive), resultBits);
1134 public static SybaseDecimal operator - (SybaseDecimal x, SybaseDecimal y)
1136 if (x.IsPositive && !y.IsPositive) return x + y;
1137 if (!x.IsPositive && y.IsPositive) return -(x + y);
1138 if (!x.IsPositive && !y.IsPositive) return y - x;
1140 // otherwise, x is positive and y is positive
1141 bool resultPositive = (bool)(x > y);
1142 int[] yData = y.Data;
1144 for (int i = 0; i < 4; i += 1) yData[i] = -yData[i];
1146 SybaseDecimal yInverse = new SybaseDecimal (y.Precision, y.Scale, y.IsPositive, yData);
1148 if (resultPositive)
1149 return x + yInverse;
1150 else
1151 return -(x + yInverse);
1154 public static SybaseDecimal operator - (SybaseDecimal n)
1156 return new SybaseDecimal (n.Precision, n.Scale, !n.IsPositive, n.Data);
1159 public static explicit operator SybaseDecimal (SybaseBoolean x)
1161 if (x.IsNull)
1162 return Null;
1163 else
1164 return new SybaseDecimal ((decimal)x.ByteValue);
1167 public static explicit operator Decimal (SybaseDecimal n)
1169 return n.Value;
1172 public static explicit operator SybaseDecimal (SybaseDouble x)
1174 if (x.IsNull)
1175 return Null;
1176 else
1177 return new SybaseDecimal ((decimal)x.Value);
1180 public static explicit operator SybaseDecimal (SybaseSingle x)
1182 if (x.IsNull)
1183 return Null;
1184 else
1185 return new SybaseDecimal ((decimal)x.Value);
1188 [MonoTODO]
1189 public static explicit operator SybaseDecimal (SybaseString x)
1191 throw new NotImplementedException ();
1194 public static implicit operator SybaseDecimal (decimal x)
1196 return new SybaseDecimal (x);
1199 public static implicit operator SybaseDecimal (SybaseByte x)
1201 if (x.IsNull)
1202 return Null;
1203 else
1204 return new SybaseDecimal ((decimal)x.Value);
1207 public static implicit operator SybaseDecimal (SybaseInt16 x)
1209 if (x.IsNull)
1210 return Null;
1211 else
1212 return new SybaseDecimal ((decimal)x.Value);
1215 public static implicit operator SybaseDecimal (SybaseInt32 x)
1217 if (x.IsNull)
1218 return Null;
1219 else
1220 return new SybaseDecimal ((decimal)x.Value);
1223 public static implicit operator SybaseDecimal (SybaseInt64 x)
1225 if (x.IsNull)
1226 return Null;
1227 else
1228 return new SybaseDecimal ((decimal)x.Value);
1231 public static implicit operator SybaseDecimal (SybaseMoney x)
1233 if (x.IsNull)
1234 return Null;
1235 else
1236 return new SybaseDecimal ((decimal)x.Value);
1239 #endregion