2 // System.Data.SqlTypes.SqlDecimal
5 // Tim Coleman <tim@timcoleman.com>
6 // Ville Palo <vi64pa@koti.soon.fi>
8 // (C) Copyright 2002 Tim Coleman
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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
;
37 using System
.Globalization
;
39 namespace System
.Data
.SqlTypes
41 public struct SqlDecimal
: INullable
, IComparable
52 // borrowed from System.Decimal
53 const int SCALE_SHIFT
= 16;
54 const int SIGN_SHIFT
= 31;
55 const int RESERVED_SS32_BITS
= 0x7F00FFFF;
56 const ulong LIT_GUINT64_HIGHBIT
= 0x8000000000000000;
57 const ulong LIT_GUINT32_HIGHBIT
= 0x80000000;
58 const byte DECIMAL_MAX_INTFACTORS
= 9;
59 static uint [] constantsDecadeInt32Factors
= new uint [10]
61 1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u,
62 10000000u, 100000000u, 1000000000u
65 public static readonly byte MaxPrecision
= 38;
66 public static readonly byte MaxScale
= 38;
68 // This should be 99999999999999999999999999999999999999
69 public static readonly SqlDecimal MaxValue
= new SqlDecimal (MaxPrecision
,
76 // This should be -99999999999999999999999999999999999999
77 public static readonly SqlDecimal MinValue
= new SqlDecimal (MaxPrecision
,
84 public static readonly SqlDecimal Null
;
90 public SqlDecimal (decimal value)
92 int[] binData
= Decimal
.GetBits (value);
94 this.precision
= MaxPrecision
; // this value seems unclear
96 this.scale
= (byte)(((uint)binData
[3]) >> SCALE_SHIFT
);
98 if (this.scale
> MaxScale
|| ((uint)binData
[3] & RESERVED_SS32_BITS
) != 0)
99 throw new ArgumentException(Locale
.GetText ("Invalid scale"));
101 this.value = new int[4];
102 this.value[0] = binData
[0];
103 this.value[1] = binData
[1];
104 this.value[2] = binData
[2];
113 precision
= GetPrecision (value);
116 public SqlDecimal (double value) : this ((decimal)value)
119 int digits
= 17 - precision
;
121 n
= AdjustScale (this, digits
, false);
123 n
= Round (this, 17);
124 this.notNull
= n
.notNull
;
125 this.positive
= n
.positive
;
126 this.precision
= n
.precision
;
127 this.scale
= n
.scale
;
128 this.value = n
.value;
130 public SqlDecimal (int value) : this ((decimal)value) { }
131 public SqlDecimal (long value) : this ((decimal)value) { }
133 public SqlDecimal (byte bPrecision
, byte bScale
, bool fPositive
, int[] bits
) : this (bPrecision
, bScale
, fPositive
, bits
[0], bits
[1], bits
[2], bits
[3]) { }
135 public SqlDecimal (byte bPrecision
, byte bScale
, bool fPositive
, int data1
, int data2
, int data3
, int data4
)
137 this.precision
= bPrecision
;
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
;
147 if (precision
< scale
)
148 throw new SqlTypeException (Locale
.GetText ("Invalid presicion/scale combination."));
151 throw new SqlTypeException (Locale
.GetText ("Invalid precision/scale combination."));
153 if (this.ToDouble () > (Math
.Pow (10, 38) - 1) ||
154 this.ToDouble () < -(Math
.Pow (10, 38)))
155 throw new SqlTypeException ("Can't convert to SqlDecimal, Out of range ");
162 public byte[] BinData
{
165 byte [] b
= new byte [value.Length
* 4];
168 for (int i
= 0; i
< value.Length
; i
++) {
170 b
[j
++] = (byte)(0xff & value [i
]);
171 b
[j
++] = (byte)(0xff & value [i
] >> 8);
172 b
[j
++] = (byte)(0xff & value [i
] >> 16);
173 b
[j
++] = (byte)(0xff & value [i
] >> 24);
183 throw new SqlNullValueException ();
184 // Data should always return clone, not to be modified
185 int [] ret
= new int [4];
195 get { return !notNull; }
198 public bool IsPositive
{
199 get { return positive; }
202 public byte Precision
{
203 get { return precision; }
207 get { return scale; }
210 public decimal Value
{
213 throw new SqlNullValueException ();
215 if (this.value[3] > 0)
216 throw new OverflowException ();
218 return new decimal (value[0], value[1], value[2], !positive
, scale
);
226 public static SqlDecimal
Abs (SqlDecimal n
)
230 return new SqlDecimal (n
.Precision
, n
.Scale
, true, n
.Data
);
233 public static SqlDecimal
Add (SqlDecimal x
, SqlDecimal y
)
238 public static SqlDecimal
AdjustScale (SqlDecimal n
, int digits
, bool fRound
)
240 byte prec
= n
.Precision
;
242 throw new SqlNullValueException ();
248 else if (digits
> 0) {
249 prec
= (byte)(prec
+ digits
);
252 for (int i
= 0; i
< digits
; i
++)
254 data
= Decimal
.GetBits (d
);
256 newScale
= (byte) (n
.scale
+ digits
);
259 n
= Round (n
, digits
+ n
.scale
);
261 n
= Round (Truncate (n
, digits
+ n
.scale
), digits
+ n
.scale
);
266 return new SqlDecimal (prec
, newScale
, n
.positive
, data
);
269 public static SqlDecimal
Ceiling (SqlDecimal n
)
273 return AdjustScale (n
, -(n
.Scale
), true);
276 public int CompareTo (object value)
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
)
285 return this.Value
.CompareTo (((SqlDecimal
)value).Value
);
288 public static SqlDecimal
ConvertToPrecScale (SqlDecimal n
, int precision
, int scale
)
290 // return new SqlDecimal ((byte)precision, (byte)scale, n.IsPositive, n.Data);
292 return AdjustScale (n
, scale
- n
.scale
, true);
295 public static SqlDecimal
Divide (SqlDecimal x
, SqlDecimal y
)
300 public override bool Equals (object value)
302 if (!(value is SqlDecimal
))
304 else if (this.IsNull
&& ((SqlDecimal
)value).IsNull
)
306 else if (((SqlDecimal
)value).IsNull
)
309 return (bool) (this == (SqlDecimal
)value);
312 public static SqlBoolean
Equals (SqlDecimal x
, SqlDecimal y
)
317 public static SqlDecimal
Floor (SqlDecimal n
)
319 return AdjustScale (n
, -(n
.Scale
), false);
322 internal static SqlDecimal
FromTdsBigDecimal (TdsBigDecimal x
)
327 return new SqlDecimal (x
.Precision
, x
.Scale
, !x
.IsNegative
, x
.Data
);
330 public override int GetHashCode ()
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
;
343 public static SqlBoolean
GreaterThan (SqlDecimal x
, SqlDecimal y
)
348 public static SqlBoolean
GreaterThanOrEqual (SqlDecimal x
, SqlDecimal y
)
353 public static SqlBoolean
LessThan (SqlDecimal x
, SqlDecimal y
)
358 public static SqlBoolean
LessThanOrEqual (SqlDecimal x
, SqlDecimal y
)
363 public static SqlDecimal
Multiply (SqlDecimal x
, SqlDecimal y
)
368 public static SqlBoolean
NotEquals (SqlDecimal x
, SqlDecimal y
)
373 public static SqlDecimal
Parse (string s
)
376 throw new ArgumentNullException (Locale
.GetText ("string s"));
378 return new SqlDecimal (Decimal
.Parse (s
));
381 public static SqlDecimal
Power (SqlDecimal n
, double exp
)
384 return SqlDecimal
.Null
;
386 return new SqlDecimal (Math
.Pow (n
.ToDouble (), exp
));
389 public static SqlDecimal
Round (SqlDecimal n
, int position
)
392 throw new SqlNullValueException ();
395 d
= Decimal
.Round (d
, position
);
396 return new SqlDecimal (d
);
399 public static SqlInt32
Sign (SqlDecimal n
)
403 if (n
>= new SqlDecimal (0))
411 public static SqlDecimal
Subtract (SqlDecimal x
, SqlDecimal y
)
416 private byte GetPrecision (decimal value)
418 string str
= value.ToString ();
421 foreach (char c
in str
) {
423 if (c
>= '0' && c
<= '9')
430 public double ToDouble ()
432 // FIXME: This is wrong way to do this
433 double d
= (uint)this.Data
[0];
434 d
+= ((uint)this.Data
[1]) * Math
.Pow (2, 32);
435 d
+= ((uint)this.Data
[2]) * Math
.Pow (2, 64);
436 d
+= ((uint)this.Data
[3]) * Math
.Pow (2, 96);
437 d
= d
/ Math
.Pow (10, scale
);
442 public SqlBoolean
ToSqlBoolean ()
444 return ((SqlBoolean
)this);
447 public SqlByte
ToSqlByte ()
449 return ((SqlByte
)this);
452 public SqlDouble
ToSqlDouble ()
454 return ((SqlDouble
)this);
457 public SqlInt16
ToSqlInt16 ()
459 return ((SqlInt16
)this);
462 public SqlInt32
ToSqlInt32 ()
464 return ((SqlInt32
)this);
467 public SqlInt64
ToSqlInt64 ()
469 return ((SqlInt64
)this);
472 public SqlMoney
ToSqlMoney ()
474 return ((SqlMoney
)this);
477 public SqlSingle
ToSqlSingle ()
479 return ((SqlSingle
)this);
482 public SqlString
ToSqlString ()
484 return ((SqlString
)this);
487 public override string ToString ()
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);
500 StringBuilder Result
= new StringBuilder ();
501 for (int i
= 0; lo
!= 0 || hi
!= 0; i
++) {
503 Div128By32 (ref hi
, ref lo
, 10, ref rest
);
504 Result
.Insert (0, rest
.ToString ());
507 while (Result
.Length
< this.Precision
)
510 while (Result
.Length
> this.Precision
)
511 Result
.Remove (Result
.Length
- 1, 1);
514 Result
.Insert (Result
.Length
- this.Scale
, ".");
517 Result
.Insert (0, '-');
519 return Result
.ToString ();
523 private static int Div128By32(ref ulong hi
, ref ulong lo
, uint divider
)
526 return Div128By32 (ref hi
, ref lo
, divider
, ref t
);
530 private static int Div128By32(ref ulong hi
, ref ulong lo
, uint divider
, ref uint rest
)
536 a
= (uint)(hi
>> 32);
544 hi
= b
<< 32 | (uint)c
;
546 a
|= (uint)(lo
>> 32);
553 lo
= b
<< 32 | (uint)c
;
557 return (a
> divider
|| (a
== divider
&& (c
& 1) == 1)) ? 1 : 0;
561 [MonoTODO("Find out what is the right way to set scale and precision")]
562 private static SqlDecimal
DecimalDiv (SqlDecimal x
, SqlDecimal y
)
569 byte prec
= 0; // precision
570 bool positive
= ! (x
.positive ^ y
.positive
);
572 prec
= x
.Precision
>= y
.Precision
? x
.Precision
: y
.Precision
;
573 DecimalDivSub (ref x
, ref y
, ref lo
, ref hi
, ref texp
);
575 sc
= x
.Scale
- y
.Scale
;
577 Rescale128 (ref lo
, ref hi
, ref sc
, texp
, 0, 38, 1);
581 Div128By32(ref hi
, ref lo
, 10, ref r
);
588 while ((((double)hi
) * Math
.Pow(2,64) + lo
) - Math
.Pow (10, prec
) > 0)
591 while ((prec
+ sc
) > MaxScale
) {
592 Div128By32(ref hi
, ref lo
, 10, ref r
);
598 int resultLo
= (int)lo
;
599 int resultMi
= (int)(lo
>> 32);
600 int resultMi2
= (int)(hi
);
601 int resultHi
= (int)(hi
>> 32);
603 return new SqlDecimal (prec
, (byte)sc
, positive
, resultLo
,
609 private static void Rescale128 (ref ulong clo
, ref ulong chi
,
610 ref int scale
, int texp
,
611 int minScale
, int maxScale
,
625 while (texp
> 0 && sc
<= maxScale
) {
627 overhang
= (uint)(chi
>> 64);
628 while (texp
> 0 && (((clo
& 1) == 0) || overhang
> 0)) {
631 roundBit
= (int)(clo
& 1);
632 RShift128 (ref clo
, ref chi
);
634 overhang
= (uint)(chi
>> 32);
637 if (texp
> DECIMAL_MAX_INTFACTORS
)
638 i
= DECIMAL_MAX_INTFACTORS
;
642 if (sc
+ i
> maxScale
)
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));
661 roundBit
= (int)(clo
& 1);
662 RShift128 (ref clo
, ref chi
);
666 while (sc
> maxScale
) {
667 i
= scale
- maxScale
;
668 if (i
> DECIMAL_MAX_INTFACTORS
)
669 i
= DECIMAL_MAX_INTFACTORS
;
671 roundBit
= Div128By32 (ref clo
, ref chi
,
672 constantsDecadeInt32Factors
[i
]);
675 while (sc
< minScale
) {
679 if (i
> DECIMAL_MAX_INTFACTORS
)
680 i
= DECIMAL_MAX_INTFACTORS
;
682 Mult128By32 (ref clo
, ref chi
,
683 constantsDecadeInt32Factors
[i
], roundBit
);
687 Normalize128 (ref clo
, ref chi
, ref sc
, roundFlag
, roundBit
);
691 private static void Normalize128(ref ulong clo
, ref ulong chi
, ref int scale
, int roundFlag
, int roundBit
)
697 if ((roundFlag
!= 0) && (roundBit
!= 0))
698 RoundUp128 (ref clo
, ref chi
);
702 private static void RoundUp128(ref ulong lo
, ref ulong hi
)
709 private static void DecimalDivSub (ref SqlDecimal x
, ref SqlDecimal y
, ref ulong clo
, ref ulong chi
, ref int exp
)
723 xhi
= (ulong)((ulong)x
.Data
[3] << 32) | (ulong)x
.Data
[2];
724 xmi
= (ulong)((ulong)x
.Data
[1] << 32) | (ulong)x
.Data
[0];
726 ylo
= (uint)y
.Data
[0];
727 ymi
= (uint)y
.Data
[1];
728 ymi2
= (uint)y
.Data
[2];
729 yhi
= (uint)y
.Data
[3];
731 if (ylo
== 0 && ymi
== 0 && ymi2
== 0 && yhi
== 0)
732 throw new DivideByZeroException ();
734 if (xmi
== 0 && xhi
== 0) {
739 // enlarge dividend to get maximal precision
740 for (ashift
= 0; (xhi
& LIT_GUINT64_HIGHBIT
) == 0; ++ashift
)
741 LShift128 (ref xmi
, ref xhi
);
743 // ensure that divisor is at least 2^95
744 for (bshift
= 0; (yhi
& LIT_GUINT32_HIGHBIT
) == 0; ++bshift
)
745 LShift128 (ref ylo
, ref ymi
, ref ymi2
, ref yhi
);
747 thi
= ((ulong)yhi
) << 32 | (ulong)ymi2
;
748 tmi
= ((ulong)ymi
) << 32 | (ulong)ylo
;
751 if (xhi
> thi
|| (xhi
== thi
&& xmi
>=tmi
)) {
752 Sub192(xlo
, xmi
, xhi
, tlo
, tmi
, thi
, ref xlo
, ref xmi
, ref xhi
);
758 Div192By128To128 (xlo
, xmi
, xhi
, ylo
, ymi
, ymi2
, yhi
, ref clo
, ref chi
);
760 exp
= 128 + ashift
- bshift
;
763 RShift128 (ref clo
, ref chi
);
764 chi
+= LIT_GUINT64_HIGHBIT
;
768 // try loss free right shift
769 while (exp
> 0 && (clo
& 1) == 0) {
770 RShift128 (ref clo
, ref chi
);
776 private static void RShift192(ref ulong lo
, ref ulong mi
, ref ulong hi
)
781 lo
|= LIT_GUINT64_HIGHBIT
;
785 mi
|= LIT_GUINT64_HIGHBIT
;
791 private static void RShift128(ref ulong lo
, ref ulong hi
)
795 lo
|= LIT_GUINT64_HIGHBIT
;
800 private static void LShift128(ref ulong lo
, ref ulong hi
)
804 if ((lo
& LIT_GUINT64_HIGHBIT
) != 0)
811 private static void LShift128(ref uint lo
, ref uint mi
, ref uint mi2
, ref uint hi
)
814 if ((mi2
& LIT_GUINT32_HIGHBIT
) != 0)
818 if ((mi
& LIT_GUINT32_HIGHBIT
) != 0)
822 if ((lo
& LIT_GUINT32_HIGHBIT
) != 0)
829 private static void Div192By128To128 (ulong xlo
, ulong xmi
, ulong xhi
,
830 uint ylo
, uint ymi
, uint ymi2
,
831 uint yhi
, ref ulong clo
, ref ulong chi
)
833 ulong rlo
, rmi
, rhi
; // remainders
840 h
= Div192By128To32WithRest (ref rlo
, ref rmi
, ref rhi
, ylo
, ymi
, ymi2
, yhi
);
843 rhi
= (rhi
<< 32) | (rmi
>> 32);
844 rmi
= (rmi
<< 32) | (rlo
>> 32);
847 chi
= (((ulong)h
) << 32) | Div192By128To32WithRest (
848 ref rlo
, ref rmi
, ref rhi
, ylo
, ymi
, ymi2
, yhi
);
851 rhi
= (rhi
<< 32) | (rmi
>> 32);
852 rmi
= (rmi
<< 32) | (rlo
>> 32);
855 h
= Div192By128To32WithRest (ref rlo
, ref rmi
, ref rhi
,
856 ylo
, ymi
, ymi2
, yhi
);
858 // estimate lowest 32 bit (two last bits may be wrong)
863 c
= (uint)(rhi
/ yhi
);
866 clo
= (((ulong)h
) << 32) | c
;
870 private static uint Div192By128To32WithRest(ref ulong xlo
, ref ulong xmi
,
871 ref ulong xhi
, uint ylo
,
872 uint ymi
, uint ymi2
, uint yhi
)
874 ulong rlo
, rmi
, rhi
; // remainder
883 if (rhi
>= (((ulong)yhi
<< 32)))
886 c
= (uint) (rhi
/ yhi
);
888 Mult128By32To128 (ylo
, ymi
, ymi2
, yhi
, c
, ref tlo
, ref thi
);
889 Sub192 (rlo
, rmi
, rhi
, 0, tlo
, thi
, ref rlo
, ref rmi
, ref rhi
);
891 while (((long)rhi
) < 0) {
893 Add192 (rlo
, rmi
, rhi
, 0, (((ulong)ymi
) << 32) | ylo
, yhi
| ymi2
, ref rlo
, ref rmi
, ref rhi
);
903 private static void Mult192By32 (ref ulong clo
, ref ulong cmi
, ref ulong chi
, ulong factor
, int roundBit
)
910 a
= ((ulong)(uint)clo
) * factor
;
917 a
+= (clo
>> 32) * factor
;
920 clo
= ((ulong)h1
) << 32 | h0
;
923 a
+= ((ulong)(uint)cmi
) * factor
;
927 a
+= (cmi
>> 32) * factor
;
930 cmi
= ((ulong)h1
) << 32 | h0
;
932 a
+= ((ulong)(uint)chi
) * factor
;
936 a
+= (chi
>> 32) * factor
;
938 chi
= ((ulong)h1
) << 32 | h0
;
942 private static void Mult128By32 (ref ulong clo
, ref ulong chi
, uint factor
, int roundBit
)
949 a
= ((ulong)(uint)clo
) * factor
;
957 a
+= (clo
>> 32) * factor
;
960 clo
= ((ulong)h1
) << 32 | h0
;
963 a
+= ((ulong)(uint)chi
) * factor
;
967 a
+= (chi
>> 32) * factor
;
970 chi
= ((ulong)h1
) << 32 | h0
;
975 private static void Mult128By32To128(uint xlo
, uint xmi
, uint xmi2
, uint xhi
,
976 uint factor
, ref ulong clo
, ref ulong chi
)
981 a
= ((ulong)xlo
) * factor
;
985 a
+= ((ulong)xmi
) * factor
;
989 a
+= ((ulong)xmi2
) * factor
;
993 a
+= ((ulong)xhi
) * factor
;
995 clo
= ((ulong)h1
) << 32 | h0
;
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
)
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
)
1050 public static SqlDecimal
Truncate (SqlDecimal n
, int position
)
1052 int diff
= n
.scale
- position
;
1055 int [] data
= n
.Data
;
1056 decimal d
= new decimal (data
[0], data
[1], data
[2], !n
.positive
, 0);
1058 for (int i
= 0; i
< diff
; i
++, x
*= 10)
1060 data
= Decimal
.GetBits (d
);
1062 return new SqlDecimal (n
.precision
, n
.scale
, n
.positive
, data
);
1065 public static SqlDecimal
operator + (SqlDecimal x
, SqlDecimal y
)
1067 // if one of them is negative, perform subtraction
1068 if (x
.IsPositive
&& !y
.IsPositive
) return x
- y
;
1069 if (y
.IsPositive
&& !x
.IsPositive
) return y
- x
;
1071 // adjust the scale to the larger of the two beforehand
1072 if (x
.scale
> y
.scale
)
1073 y
= SqlDecimal
.AdjustScale (y
, x
.scale
- y
.scale
, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1074 else if (y
.scale
> x
.scale
)
1075 x
= SqlDecimal
.AdjustScale (x
, y
.scale
- x
.scale
, true); // FIXME: should be false (fix it after AdjustScale(,,false) is fixed)
1077 // set the precision to the greater of the two
1078 byte resultPrecision
;
1079 if (x
.Precision
> y
.Precision
)
1080 resultPrecision
= x
.Precision
;
1082 resultPrecision
= y
.Precision
;
1084 int[] xData
= x
.Data
;
1085 int[] yData
= y
.Data
;
1086 int[] resultBits
= new int[4];
1091 // add one at a time, and carry the results over to the next
1092 for (int i
= 0; i
< 4; i
+=1)
1095 res
= (ulong)(xData
[i
]) + (ulong)(yData
[i
]) + carry
;
1096 if (res
> Int32
.MaxValue
)
1098 carry
= res
- Int32
.MaxValue
;
1099 res
= Int32
.MaxValue
;
1101 resultBits
[i
] = (int)res
;
1104 // if we have carry left, then throw an exception
1106 throw new OverflowException ();
1108 return new SqlDecimal (resultPrecision
, x
.Scale
, x
.IsPositive
, resultBits
);
1111 public static SqlDecimal
operator / (SqlDecimal x
, SqlDecimal y
)
1113 // return new SqlDecimal (x.Value / y.Value);
1114 return DecimalDiv (x
, y
);
1117 public static SqlBoolean
operator == (SqlDecimal x
, SqlDecimal y
)
1119 if (x
.IsNull
|| y
.IsNull
)
1120 return SqlBoolean
.Null
;
1122 if (x
.Scale
> y
.Scale
)
1123 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, false);
1124 else if (y
.Scale
> x
.Scale
)
1125 x
= SqlDecimal
.AdjustScale(y
, y
.Scale
- x
.Scale
, false);
1127 for (int i
= 0; i
< 4; i
+= 1)
1129 if (x
.Data
[i
] != y
.Data
[i
])
1130 return new SqlBoolean (false);
1132 return new SqlBoolean (true);
1135 public static SqlBoolean
operator > (SqlDecimal x
, SqlDecimal y
)
1137 if (x
.IsNull
|| y
.IsNull
)
1138 return SqlBoolean
.Null
;
1140 if (x
.Scale
> y
.Scale
)
1141 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, false);
1142 else if (y
.Scale
> x
.Scale
)
1143 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, false);
1145 for (int i
= 3; i
>= 0; i
--)
1147 if (x
.Data
[i
] == 0 && y
.Data
[i
] == 0)
1150 return new SqlBoolean (x
.Data
[i
] > y
.Data
[i
]);
1152 return new SqlBoolean (false);
1155 public static SqlBoolean
operator >= (SqlDecimal x
, SqlDecimal y
)
1157 if (x
.IsNull
|| y
.IsNull
)
1158 return SqlBoolean
.Null
;
1160 if (x
.Scale
> y
.Scale
)
1161 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, true);
1162 else if (y
.Scale
> x
.Scale
)
1163 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, true);
1165 for (int i
= 3; i
>= 0; i
-= 1)
1167 if (x
.Data
[i
] == 0 && y
.Data
[i
] == 0)
1170 return new SqlBoolean (x
.Data
[i
] >= y
.Data
[i
]);
1172 return new SqlBoolean (true);
1175 public static SqlBoolean
operator != (SqlDecimal x
, SqlDecimal y
)
1177 if (x
.IsNull
|| y
.IsNull
)
1178 return SqlBoolean
.Null
;
1180 if (x
.Scale
> y
.Scale
)
1181 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, true);
1182 else if (y
.Scale
> x
.Scale
)
1183 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, true);
1185 for (int i
= 0; i
< 4; i
+= 1)
1187 if (x
.Data
[i
] != y
.Data
[i
])
1188 return new SqlBoolean (true);
1190 return new SqlBoolean (false);
1193 public static SqlBoolean
operator < (SqlDecimal x
, SqlDecimal y
)
1196 if (x
.IsNull
|| y
.IsNull
)
1197 return SqlBoolean
.Null
;
1199 if (x
.Scale
> y
.Scale
)
1200 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, true);
1201 else if (y
.Scale
> x
.Scale
)
1202 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, true);
1204 for (int i
= 3; i
>= 0; i
-= 1)
1206 if (x
.Data
[i
] == 0 && y
.Data
[i
] == 0)
1209 return new SqlBoolean (x
.Data
[i
] < y
.Data
[i
]);
1211 return new SqlBoolean (false);
1215 public static SqlBoolean
operator <= (SqlDecimal x
, SqlDecimal y
)
1217 if (x
.IsNull
|| y
.IsNull
)
1218 return SqlBoolean
.Null
;
1220 if (x
.Scale
> y
.Scale
)
1221 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, true);
1222 else if (y
.Scale
> x
.Scale
)
1223 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, true);
1225 for (int i
= 3; i
>= 0; i
-= 1)
1227 if (x
.Data
[i
] == 0 && y
.Data
[i
] == 0)
1230 return new SqlBoolean (x
.Data
[i
] <= y
.Data
[i
]);
1232 return new SqlBoolean (true);
1235 public static SqlDecimal
operator * (SqlDecimal x
, SqlDecimal y
)
1237 // adjust the scale to the smaller of the two beforehand
1238 if (x
.Scale
> y
.Scale
)
1239 x
= SqlDecimal
.AdjustScale(x
, y
.Scale
- x
.Scale
, true);
1240 else if (y
.Scale
> x
.Scale
)
1241 y
= SqlDecimal
.AdjustScale(y
, x
.Scale
- y
.Scale
, true);
1243 // set the precision to the greater of the two
1244 byte resultPrecision
;
1245 if (x
.Precision
> y
.Precision
)
1246 resultPrecision
= x
.Precision
;
1248 resultPrecision
= y
.Precision
;
1250 int[] xData
= x
.Data
;
1251 int[] yData
= y
.Data
;
1252 int[] resultBits
= new int[4];
1257 // multiply one at a time, and carry the results over to the next
1258 for (int i
= 0; i
< 4; i
+=1)
1261 res
= (ulong)(xData
[i
]) * (ulong)(yData
[i
]) + carry
;
1262 if (res
> Int32
.MaxValue
)
1264 carry
= res
- Int32
.MaxValue
;
1265 res
= Int32
.MaxValue
;
1267 resultBits
[i
] = (int)res
;
1270 // if we have carry left, then throw an exception
1272 throw new OverflowException ();
1274 return new SqlDecimal (resultPrecision
, x
.Scale
, (x
.IsPositive
== y
.IsPositive
), resultBits
);
1278 public static SqlDecimal
operator - (SqlDecimal x
, SqlDecimal y
)
1280 if (x
.IsPositive
&& !y
.IsPositive
) return x
+ y
;
1281 if (!x
.IsPositive
&& y
.IsPositive
) return -(x
+ y
);
1282 if (!x
.IsPositive
&& !y
.IsPositive
) return y
- x
;
1284 // otherwise, x is positive and y is positive
1285 bool resultPositive
= (bool)(x
> y
);
1286 int[] yData
= y
.Data
;
1288 for (int i
= 0; i
< 4; i
+= 1) yData
[i
] = -yData
[i
];
1290 SqlDecimal yInverse
= new SqlDecimal (y
.Precision
, y
.Scale
, y
.IsPositive
, yData
);
1293 return x
+ yInverse
;
1295 return -(x
+ yInverse
);
1298 public static SqlDecimal
operator - (SqlDecimal n
)
1300 return new SqlDecimal (n
.Precision
, n
.Scale
, !n
.IsPositive
, n
.Data
);
1303 public static explicit operator SqlDecimal (SqlBoolean x
)
1308 return new SqlDecimal ((decimal)x
.ByteValue
);
1311 public static explicit operator Decimal (SqlDecimal n
)
1316 public static explicit operator SqlDecimal (SqlDouble x
)
1322 return new SqlDecimal ((double)x
.Value
);
1326 public static explicit operator SqlDecimal (SqlSingle x
)
1332 return new SqlDecimal ((double)x
.Value
);
1336 public static explicit operator SqlDecimal (SqlString x
)
1339 return Parse (x
.Value
);
1343 public static implicit operator SqlDecimal (decimal x
)
1345 return new SqlDecimal (x
);
1348 public static implicit operator SqlDecimal (SqlByte x
)
1353 return new SqlDecimal ((decimal)x
.Value
);
1356 public static implicit operator SqlDecimal (SqlInt16 x
)
1361 return new SqlDecimal ((decimal)x
.Value
);
1364 public static implicit operator SqlDecimal (SqlInt32 x
)
1369 return new SqlDecimal ((decimal)x
.Value
);
1372 public static implicit operator SqlDecimal (SqlInt64 x
)
1377 return new SqlDecimal ((decimal)x
.Value
);
1380 public static implicit operator SqlDecimal (SqlMoney x
)
1385 return new SqlDecimal ((decimal)x
.Value
);