Merge remote branch 'upstream/master'
[mono.git] / mcs / class / corlib / System / Decimal.cs
1 //
2 // System.Decimal.cs
3 //
4 // Represents a floating-point decimal data type with up to 29 
5 // significant digits, suitable for financial and commercial calculations.
6 //
7 // Author:
8 //   Martin Weindel (martin.weindel@t-online.de)
9 //
10 // (C) 2001 Martin Weindel
11 //
12
13 //
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35
36 using System;
37 using System.Globalization;
38 using System.Text;
39 using System.Runtime.CompilerServices;
40 using System.Runtime.ConstrainedExecution;
41 using System.Runtime.Serialization;
42
43 #if MSTEST
44 using System.Runtime.InteropServices;
45 #endif
46
47
48 namespace System
49 {
50         /// <summary>
51         /// Represents a floating-point decimal data type with up to 29 significant
52         /// digits, suitable for financial and commercial calculations
53         /// </summary>
54         [Serializable]
55         [System.Runtime.InteropServices.ComVisible (true)]
56         public struct Decimal: IFormattable, IConvertible, IComparable, IComparable<Decimal>, IEquatable <Decimal>
57 #if NET_4_0
58                 , IDeserializationCallback
59 #endif
60         {
61                 public const decimal MinValue = -79228162514264337593543950335m;
62                 public const decimal MaxValue =  79228162514264337593543950335m;
63
64                 public const decimal MinusOne = -1;
65                 public const decimal One = 1;
66                 public const decimal Zero = 0;
67
68                 private static readonly Decimal MaxValueDiv10 = MaxValue / 10;
69
70                 // some constants
71                 private const uint MAX_SCALE = 28;
72                 private const uint SIGN_FLAG = 0x80000000;
73                 private const int SCALE_SHIFT = 16;
74                 private const uint RESERVED_SS32_BITS = 0x7F00FFFF;
75
76                 // internal representation of decimal
77                 private uint flags;
78                 private uint hi;
79                 private uint lo;
80                 private uint mid;
81
82                 public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
83                 {
84                         unchecked 
85                         {
86                                 this.lo = (uint) lo;
87                                 this.mid = (uint) mid;
88                                 this.hi = (uint) hi;
89
90                                 if (scale > MAX_SCALE) 
91                                         throw new ArgumentOutOfRangeException (Locale.GetText ("scale must be between 0 and 28"));
92
93                                 flags = scale;
94                                 flags <<= SCALE_SHIFT;
95                                 if (isNegative) flags |= SIGN_FLAG;
96                         }
97                 }
98
99                 public Decimal (int value) 
100                 {
101                         unchecked 
102                         {
103                                 hi = mid = 0;
104                                 if (value < 0) 
105                                 {
106                                         flags = SIGN_FLAG;
107                                         lo = ((uint)~value) + 1;
108                                 }
109                                 else 
110                                 {
111                                         flags = 0;
112                                         lo = (uint) value;
113                                 }
114                         }
115                 }
116
117                 [CLSCompliant(false)]
118                 public Decimal (uint value) 
119                 {
120                         lo = value;
121                         flags = hi = mid = 0;
122                 }
123
124                 public Decimal (long value) 
125                 {
126                         unchecked 
127                         {
128                                 hi = 0;
129                                 if (value < 0) 
130                                 {
131                                         flags = SIGN_FLAG;
132                                         ulong u = ((ulong)~value) + 1;
133                                         lo = (uint)u;
134                                         mid = (uint)(u >> 32);
135                                 }
136                                 else 
137                                 {
138                                         flags = 0;
139                                         ulong u = (ulong)value;
140                                         lo = (uint)u;
141                                         mid = (uint)(u >> 32);
142                                 }
143                         }
144                 }
145
146                 [CLSCompliant(false)]
147                 public Decimal (ulong value) 
148                 {
149                         unchecked 
150                         {
151                                 flags = hi = 0;
152                                 lo = (uint)value;
153                                 mid = (uint)(value >> 32);
154                         }
155                 }
156
157                 public Decimal (float value) 
158                 {
159 #if false
160                         //
161                         // We cant use the double2decimal method
162                         // because it incorrectly turns the floating point
163                         // value 1.23456789E-25F which should be:
164                         //    0.0000000000000000000000001235
165                         // into the incorrect:
166                         //   0.0000000000000000000000001234
167                         //
168                         //    The code currently parses the double value 0.6 as
169                         //    0.600000000000000
170                         //
171                         // And we have a patch for that called (trim
172                         if (double2decimal (out this, value, 7) != 0)
173                                 throw new OverflowException ();
174 #else
175                         if (value > (float)Decimal.MaxValue || value < (float)Decimal.MinValue ||
176                                 float.IsNaN (value) || float.IsNegativeInfinity (value) || float.IsPositiveInfinity (value)) {
177                                 throw new OverflowException (Locale.GetText (
178                                         "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
179                         }
180                         
181                         // we must respect the precision (double2decimal doesn't)
182                         Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
183                                         NumberStyles.Float, CultureInfo.InvariantCulture);
184                         flags = d.flags;
185                         hi = d.hi;
186                         lo = d.lo;
187                         mid = d.mid;
188 #endif
189                 }
190
191                 public Decimal (double value) 
192                 {
193 #if false
194                         //
195                         // We cant use the double2decimal method
196                         // because it incorrectly turns the floating point
197                         // value 1.23456789E-25F which should be:
198                         //    0.0000000000000000000000001235
199                         // into the incorrect:
200                         //   0.0000000000000000000000001234
201                         //
202                         //    The code currently parses the double value 0.6 as
203                         //    0.600000000000000
204                         //
205                         // And we have a patch for that called (trim
206                         if (double2decimal (out this, value, 15) != 0)
207                                 throw new OverflowException ();
208 #else
209                         if (value > (double)Decimal.MaxValue || value < (double)Decimal.MinValue ||
210                                 double.IsNaN (value) || double.IsNegativeInfinity (value) || double.IsPositiveInfinity (value)) {
211                                 throw new OverflowException (Locale.GetText (
212                                         "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
213                         }
214                         // we must respect the precision (double2decimal doesn't)
215                         Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
216                                         NumberStyles.Float, CultureInfo.InvariantCulture);
217                         flags = d.flags;
218                         hi = d.hi;
219                         lo = d.lo;
220                         mid = d.mid;
221 #endif
222                 }
223
224                 public Decimal (int[] bits) 
225                 {
226                         if (bits == null) 
227                         {
228                                 throw new ArgumentNullException (Locale.GetText ("Bits is a null reference"));
229                         }
230
231                         if (bits.GetLength(0) != 4) 
232                         {
233                                 throw new ArgumentException (Locale.GetText ("bits does not contain four values"));
234                         }
235
236                         unchecked {
237                                 lo = (uint) bits[0];
238                                 mid = (uint) bits[1];
239                                 hi = (uint) bits[2];
240                                 flags = (uint) bits[3];
241                                 byte scale = (byte)(flags >> SCALE_SHIFT);
242                                 if (scale > MAX_SCALE || (flags & RESERVED_SS32_BITS) != 0) 
243                                 {
244                                         throw new ArgumentException (Locale.GetText ("Invalid bits[3]"));
245                                 }
246                         }
247                 }
248
249                 public static decimal FromOACurrency (long cy)
250                 {
251                         return (decimal)cy / (decimal)10000;
252                 }
253
254                 public static int[] GetBits (Decimal d) 
255                 {
256                         unchecked 
257                         {
258                                 return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags };
259                         }
260                 }
261
262                 public static Decimal Negate (Decimal d) 
263                 {
264                         d.flags ^= SIGN_FLAG;
265                         return d;
266                 }
267
268                 public static Decimal Add (Decimal d1, Decimal d2) 
269                 {
270                         if (decimalIncr (ref d1, ref d2) == 0)
271                                 return d1;
272                         else
273                                 throw new OverflowException (Locale.GetText ("Overflow on adding decimal number"));
274                 }
275
276                 public static Decimal Subtract (Decimal d1, Decimal d2) 
277                 {
278                         d2.flags ^= SIGN_FLAG;
279                         int result = decimalIncr (ref d1, ref d2);
280                         if (result == 0)
281                                 return d1;
282                         else
283                                 throw new OverflowException (Locale.GetText ("Overflow on subtracting decimal numbers ("+result+")"));
284                 }
285
286                 public override int GetHashCode () 
287                 {
288                         return (int) (flags ^ hi ^ lo ^ mid);
289                 }
290
291                 public static Decimal operator + (Decimal d1, Decimal d2)
292                 {
293                         return Add (d1, d2);
294                 }
295
296                 public static Decimal operator -- (Decimal d) 
297                 {
298                         return Add(d, MinusOne);
299                 }
300
301                 public static Decimal operator ++ (Decimal d) 
302                 {
303                         return Add (d, One);
304                 }
305
306                 public static Decimal operator - (Decimal d1, Decimal d2) 
307                 {
308                         return Subtract (d1, d2);
309                 }
310
311                 public static Decimal operator - (Decimal d) 
312                 {
313                         return Negate (d);
314                 }
315
316                 public static Decimal operator + (Decimal d) 
317                 {
318                         return d;
319                 }
320
321                 public static Decimal operator * (Decimal d1, Decimal d2)
322                 {
323                         return Multiply (d1, d2);
324                 }
325                 
326                 public static Decimal operator / (Decimal d1, Decimal d2) 
327                 {
328                         return Divide (d1, d2);
329                 }
330                 
331                 public static Decimal operator % (Decimal d1, Decimal d2) 
332                 {
333                         return Remainder (d1, d2);
334                 }
335
336                 private static ulong u64 (Decimal value) 
337                 {
338                         ulong result;
339
340                         decimalFloorAndTrunc (ref value, 0);
341                         if (decimal2UInt64 (ref value, out result) != 0) {
342                                 throw new System.OverflowException ();
343                         }
344                         return result;
345                 }
346
347                 private static long s64 (Decimal value) 
348                 {
349                         long result;
350
351                         decimalFloorAndTrunc (ref value, 0);
352                         if (decimal2Int64 (ref value, out result) != 0) {
353                                 throw new System.OverflowException ();
354                         }
355                         return result;
356                 }
357
358                 public static explicit operator byte (Decimal value)
359                 {
360                         ulong result = u64 (value);
361                         return checked ((byte) result);
362                 }
363
364                 [CLSCompliant (false)]
365                 public static explicit operator sbyte (Decimal value)
366                 {
367                         long result = s64 (value);
368                         return checked ((sbyte) result);
369                 }
370
371                 public static explicit operator char (Decimal value) 
372                 {
373                         ulong result = u64 (value);
374                         return checked ((char) result);
375                 }
376
377                 public static explicit operator short (Decimal value) 
378                 {
379                         long result = s64 (value);
380                         return checked ((short) result);
381                 }
382
383                 [CLSCompliant (false)]
384                 public static explicit operator ushort (Decimal value) 
385                 {
386                         ulong result = u64 (value);
387                         return checked ((ushort) result);
388                 }
389
390                 public static explicit operator int (Decimal value) 
391                 {
392                         long result = s64 (value);
393                         return checked ((int) result);
394                 }
395
396                 [CLSCompliant(false)]
397                 public static explicit operator uint (Decimal value) 
398                 {
399                         ulong result = u64 (value);
400                         return checked ((uint) result);
401                 }
402
403                 public static explicit operator long (Decimal value) 
404                 {
405                         return s64 (value);
406                 }
407
408                 [CLSCompliant(false)]
409                 public static explicit operator ulong (Decimal value) 
410                 {
411                         return u64 (value);
412                 }
413
414                 public static implicit operator Decimal (byte value) 
415                 {
416                         return new Decimal (value);
417                 }
418
419                 [CLSCompliant(false)]
420                 public static implicit operator Decimal (sbyte value) 
421                 {
422                         return new Decimal (value);
423                 }
424
425                 public static implicit operator Decimal (short value) 
426                 {
427                         return new Decimal (value);
428                 }
429
430                 [CLSCompliant(false)]
431                 public static implicit operator Decimal (ushort value) 
432                 {
433                         return new Decimal (value);
434                 }
435
436                 public static implicit operator Decimal (char value) 
437                 {
438                         return new Decimal (value);
439                 }
440
441                 public static implicit operator Decimal (int value) 
442                 {
443                         return new Decimal (value);
444                 }
445
446                 [CLSCompliant(false)]
447                 public static implicit operator Decimal (uint value) 
448                 {
449                         return new Decimal (value);
450                 }
451
452                 public static implicit operator Decimal (long value) 
453                 {
454                         return new Decimal (value);
455                 }
456
457                 [CLSCompliant(false)]
458                 public static implicit operator Decimal (ulong value) 
459                 {
460                         return new Decimal (value);
461                 }
462
463                 public static explicit operator Decimal (float value) 
464                 {
465                         return new Decimal (value);
466                 }
467
468                 public static explicit operator Decimal (double value)
469                 {
470                         return new Decimal (value);
471                 }
472
473                 public static explicit operator float (Decimal value)
474                 {
475                         return (float) (double) value;
476                 }
477
478                 public static explicit operator double (Decimal value)
479                 {
480                         return decimal2double (ref value);
481                 }
482
483
484                 public static bool operator != (Decimal d1, Decimal d2) 
485                 {
486                         return !Equals (d1, d2);
487                 }
488
489                 public static bool operator == (Decimal d1, Decimal d2) 
490                 {
491                         return Equals (d1, d2);
492                 }
493
494                 public static bool operator > (Decimal d1, Decimal d2) 
495                 {
496                         return Compare (d1, d2) > 0;
497                 }
498
499                 public static bool operator >= (Decimal d1, Decimal d2) 
500                 {
501                         return Compare (d1, d2) >= 0;
502                 }
503
504                 public static bool operator < (Decimal d1, Decimal d2) 
505                 {
506                         return Compare (d1, d2) < 0;
507                 }
508
509                 public static bool operator <= (Decimal d1, Decimal d2) 
510                 {
511                         return Compare (d1, d2) <= 0;
512                 }
513
514                 public static bool Equals (Decimal d1, Decimal d2) 
515                 {
516                         return Compare (d1, d2) == 0;
517                 }
518
519                 public override bool Equals (object value) 
520                 {
521                         if (!(value is Decimal))
522                                 return false;
523
524                         return Equals ((Decimal) value, this);
525                 }
526
527                 // avoid unmanaged call
528                 private bool IsZero () 
529                 {
530                         return ((hi == 0) && (lo == 0) && (mid == 0));
531                 }
532
533                 // avoid unmanaged call
534                 private bool IsNegative () 
535                 {
536                         return ((flags & 0x80000000) == 0x80000000);
537                 }
538
539                 public static Decimal Floor (Decimal d) 
540                 {
541                         decimalFloorAndTrunc (ref d, 1);
542                         return d;
543                 }
544
545                 public static Decimal Truncate (Decimal d) 
546                 {
547                         decimalFloorAndTrunc (ref d, 0);
548                         return d;
549                 }
550
551                 public static Decimal Round (Decimal d, int decimals) 
552                 {
553                         return Round (d, decimals, MidpointRounding.ToEven);
554                 }
555
556                 public static Decimal Round (Decimal d, int decimals, MidpointRounding mode) 
557                 {
558                         if ((mode != MidpointRounding.ToEven) && (mode != MidpointRounding.AwayFromZero))
559                                 throw new ArgumentException ("The value '" + mode + "' is not valid for this usage of the type MidpointRounding.", "mode");
560
561                         if (decimals < 0 || decimals > 28) {
562                                 throw new ArgumentOutOfRangeException ("decimals", "[0,28]");
563                         }
564
565                         bool negative = d.IsNegative ();
566                         if (negative)
567                                 d.flags ^= SIGN_FLAG;
568
569                         // Moved from Math.cs because it's easier to fix the "sign"
570                         // issue here :( as the logic is OK only for positive numbers
571                         decimal p = (decimal) Math.Pow (10, decimals);
572                         decimal int_part = Decimal.Floor (d);
573                         decimal dec_part = d - int_part;
574                         dec_part *= 10000000000000000000000000000M;
575                         dec_part = Decimal.Floor(dec_part);
576                         dec_part /= (10000000000000000000000000000M / p);
577                         dec_part = Math.Round (dec_part, mode);
578                         dec_part /= p;
579                         decimal result = int_part + dec_part;
580
581                         // that fixes the precision/scale (which we must keep for output)
582                         // (moved and adapted from System.Data.SqlTypes.SqlMoney)
583                         long scaleDiff = decimals - ((result.flags & 0x7FFF0000) >> 16);
584                         // integrify
585                         if (scaleDiff > 0) {
586                                 // note: here we always work with positive numbers
587                                 while (scaleDiff > 0) {
588                                         if (result > MaxValueDiv10)
589                                                 break;
590                                         result *= 10;
591                                         scaleDiff--;
592                                 }
593                         }
594                         else if (scaleDiff < 0) {
595                                 while (scaleDiff < 0) {
596                                         result /= 10;
597                                         scaleDiff++;
598                                 }
599                         }
600                         result.flags = (uint)((decimals - scaleDiff) << SCALE_SHIFT);
601
602                         if (negative)
603                                 result.flags ^= SIGN_FLAG;
604                         return result;
605                 }
606
607                 public static Decimal Round (Decimal d)
608                 {
609                         return Math.Round (d);
610                 }
611
612                 public static Decimal Round (Decimal d, MidpointRounding mode)
613                 {
614                         return Math.Round (d, mode);
615                 }
616
617                 public static Decimal Multiply (Decimal d1, Decimal d2) 
618                 {
619                         if (d1.IsZero () || d2.IsZero ())
620                                 return Decimal.Zero;
621
622                         if (decimalMult (ref d1, ref d2) != 0)
623                                 throw new OverflowException ();
624                         return d1;
625                 }
626
627                 public static Decimal Divide (Decimal d1, Decimal d2) 
628                 {
629                         if (d2.IsZero ())
630                                 throw new DivideByZeroException ();
631                         if (d1.IsZero ())
632                                 return Decimal.Zero;
633
634                         d1.flags ^= SIGN_FLAG;
635                         d1.flags ^= SIGN_FLAG;
636
637                         Decimal result;
638                         if (decimalDiv (out result, ref d1, ref d2) != 0)
639                                 throw new OverflowException ();
640
641                         return result;
642                 }
643
644                 public static Decimal Remainder (Decimal d1, Decimal d2) 
645                 {
646                         if (d2.IsZero ())
647                                 throw new DivideByZeroException ();
648                         if (d1.IsZero ())
649                                 return Decimal.Zero;
650
651                         bool negative = d1.IsNegative ();
652                         if (negative)
653                                 d1.flags ^= SIGN_FLAG;
654                         if (d2.IsNegative ())
655                                 d2.flags ^= SIGN_FLAG;
656
657                         Decimal result;
658                         if (d1 == d2) {
659                                 return Decimal.Zero;
660                         }
661                         else if (d2 > d1) {
662                                 result = d1;
663                         }
664                         else {
665                                 if (decimalDiv (out result, ref d1, ref d2) != 0)
666                                         throw new OverflowException ();
667                                 result = Decimal.Truncate (result);
668
669                                 // FIXME: not really performant here
670                                 result = d1 - result * d2;
671                         }
672
673                         if (negative)
674                                 result.flags ^= SIGN_FLAG;
675                         return result;
676                 }
677
678                 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
679                 public static int Compare (Decimal d1, Decimal d2) 
680                 {
681                         return decimalCompare (ref d1, ref d2);
682                 }
683
684                 public int CompareTo (object value)
685                 {
686                         if (value == null)
687                                 return 1;
688
689                         if (!(value is Decimal))
690                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Decimal"));
691
692                         return Compare (this, (Decimal)value);
693                 }
694
695                 public int CompareTo (Decimal value)
696                 {
697                         return Compare (this, value);
698                 }
699
700                 public bool Equals (Decimal value) 
701                 {
702                         return Equals (value, this);
703                 }
704
705                 public static Decimal Ceiling (Decimal d)
706                 {
707                         return Math.Ceiling (d);
708                 }
709
710                 public static Decimal Parse (string s) 
711                 {
712                         return Parse (s, NumberStyles.Number, null);
713                 }
714
715                 public static Decimal Parse (string s, NumberStyles style) 
716                 {
717                         return Parse (s, style, null);
718                 }
719
720                 public static Decimal Parse (string s, IFormatProvider provider) 
721                 {
722                         return Parse (s, NumberStyles.Number, provider);
723                 }
724
725                 static void ThrowAtPos (int pos)
726                 {
727                         throw new FormatException (String.Format (Locale.GetText ("Invalid character at position {0}"), pos));
728                 }
729
730                 static void ThrowInvalidExp ()
731                 {
732                         throw new FormatException (Locale.GetText ("Invalid exponent"));
733                 }
734
735                 private static string stripStyles (string s, NumberStyles style, NumberFormatInfo nfi, 
736                   out int decPos, out bool isNegative, out bool expFlag, out int exp, bool throwex)
737                 {
738                         isNegative = false;
739                         expFlag = false;
740                         exp = 0;
741                         decPos = -1;
742
743                         bool hasSign = false;
744                         bool hasOpeningParentheses = false;
745                         bool hasDecimalPoint = false;
746                         bool allowedLeadingWhiteSpace = ((style & NumberStyles.AllowLeadingWhite) != 0);
747                         bool allowedTrailingWhiteSpace = ((style & NumberStyles.AllowTrailingWhite) != 0);
748                         bool allowedLeadingSign = ((style & NumberStyles.AllowLeadingSign) != 0);
749                         bool allowedTrailingSign = ((style & NumberStyles.AllowTrailingSign) != 0);
750                         bool allowedParentheses = ((style & NumberStyles.AllowParentheses) != 0);
751                         bool allowedThousands = ((style & NumberStyles.AllowThousands) != 0);
752                         bool allowedDecimalPoint = ((style & NumberStyles.AllowDecimalPoint) != 0);
753                         bool allowedExponent = ((style & NumberStyles.AllowExponent) != 0);
754
755                         /* get rid of currency symbol */
756                         bool hasCurrency = false;
757                         if ((style & NumberStyles.AllowCurrencySymbol) != 0)
758                         {
759                                 int index = s.IndexOf (nfi.CurrencySymbol);
760                                 if (index >= 0) 
761                                 {
762                                         s = s.Remove (index, nfi.CurrencySymbol.Length);
763                                         hasCurrency = true;
764                                 }
765                         }
766
767                         string decimalSep = (hasCurrency) ? nfi.CurrencyDecimalSeparator : nfi.NumberDecimalSeparator;
768                         string groupSep = (hasCurrency) ? nfi.CurrencyGroupSeparator : nfi.NumberGroupSeparator;
769
770                         int pos = 0;
771                         int len = s.Length;
772
773                         StringBuilder sb = new StringBuilder (len);
774
775                         // leading
776                         while (pos < len) 
777                         {
778                                 char ch = s[pos];
779                                 if (Char.IsDigit (ch))
780                                 {
781                                         break; // end of leading
782                                 }
783                                 else if (allowedLeadingWhiteSpace && Char.IsWhiteSpace (ch))
784                                 {
785                                         pos++;
786                                 }
787                                 else if (allowedParentheses && ch == '(' && !hasSign && !hasOpeningParentheses) 
788                                 {
789                                         hasOpeningParentheses = true;
790                                         hasSign = true;
791                                         isNegative = true;
792                                         pos++;
793                                 }
794                                 else if (allowedLeadingSign && ch == nfi.NegativeSign[0] && !hasSign) 
795                                 {
796                                         int slen = nfi.NegativeSign.Length;
797                                         if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos) 
798                                         {
799                                                 hasSign = true;
800                                                 isNegative = true;
801                                                 pos += slen;
802                                         }
803                                 }
804                                 else if (allowedLeadingSign && ch == nfi.PositiveSign[0] && !hasSign) 
805                                 {
806                                         int slen = nfi.PositiveSign.Length;
807                                         if (slen == 1 || s.IndexOf (nfi.PositiveSign, pos, slen) == pos) 
808                                         {
809                                                 hasSign = true;
810                                                 pos += slen;
811                                         }
812                                 }
813                                 else if (allowedDecimalPoint && ch == decimalSep[0])
814                                 {
815                                         int slen = decimalSep.Length;
816                                         if (slen != 1 && s.IndexOf (decimalSep, pos, slen) != pos) 
817                                         {
818                                                 if (throwex)
819                                                         ThrowAtPos (pos);
820                                                 else
821                                                         return null;
822                                         }
823                                         break;
824                                 }
825                                 else
826                                 {
827                                         if (throwex)
828                                                 ThrowAtPos (pos);
829                                         else
830                                                 return null;
831                                 }
832                         }
833
834                         if (pos == len) {
835                                 if (throwex)
836                                         throw new FormatException (Locale.GetText ("No digits found"));
837                                 else
838                                         return null;
839                         }
840
841                         // digits 
842                         while (pos < len)
843                         {
844                                 char ch = s[pos];
845                                 if (Char.IsDigit (ch)) 
846                                 {
847                                         sb.Append(ch);
848                                         pos++;
849                                 }
850                                 else if (allowedThousands && ch == groupSep[0] && ch != decimalSep [0]) 
851                                 {
852                                         int slen = groupSep.Length;
853                                         if (slen != 1 && s.IndexOf(groupSep, pos, slen) != pos) 
854                                         {
855                                                 if (throwex)
856                                                         ThrowAtPos (pos);
857                                                 else
858                                                         return null;
859                                         }
860                                         pos += slen;
861                                 }
862                                 else if (allowedDecimalPoint && ch == decimalSep[0] && !hasDecimalPoint)
863                                 {
864                                         int slen = decimalSep.Length;
865                                         if (slen == 1 || s.IndexOf(decimalSep, pos, slen) == pos) 
866                                         {
867                                                 decPos = sb.Length;
868                                                 hasDecimalPoint = true;
869                                                 pos += slen;
870                                         }
871                                 }
872                                 else
873                                 {
874                                         break;
875                                 }
876                         }
877
878                         // exponent
879                         if (pos < len)
880                         {
881                                 char ch = s[pos];
882                                 if (allowedExponent && Char.ToUpperInvariant (ch) == 'E')
883                                 {
884                                         expFlag = true;
885                                         pos++;
886                                         if (pos >= len){
887                                                 if (throwex)
888                                                         ThrowInvalidExp ();
889                                                 else
890                                                         return null;
891                                         }
892                                         ch = s[pos];
893                                         bool isNegativeExp = false;
894                                         if (ch == nfi.PositiveSign[0])
895                                         {
896                                                 int slen = nfi.PositiveSign.Length;
897                                                 if (slen == 1 || s.IndexOf (nfi.PositiveSign, pos, slen) == pos) 
898                                                 {
899                                                         pos += slen;
900                                                         if (pos >= len) {
901                                                                 if (throwex)
902                                                                         ThrowInvalidExp ();
903                                                                 else
904                                                                         return null;
905                                                         }
906                                                 }
907                                         }
908                                         else if (ch == nfi.NegativeSign[0])
909                                         {
910                                                 int slen = nfi.NegativeSign.Length;
911                                                 if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos) 
912                                                 {
913                                                         pos += slen;
914                                                         if (pos >= len) {
915                                                                 if (throwex)
916                                                                         ThrowInvalidExp ();
917                                                                 else
918                                                                         return null;
919                                                         }
920                                                         isNegativeExp = true;
921                                                 }
922                                         }
923                                         ch = s[pos];
924                                         if (!Char.IsDigit(ch)) {
925                                                 if (throwex)
926                                                         ThrowInvalidExp ();
927                                                 else
928                                                         return null;
929                                         }
930
931                                         exp = ch - '0';
932                                         pos++;
933                                         while (pos < len && Char.IsDigit (s[pos])) 
934                                         {
935                                                 exp *= 10;
936                                                 exp += s[pos] - '0';
937                                                 pos++;
938                                         }
939                                         if (isNegativeExp) exp *= -1;
940                                 }
941                         }
942
943                         // trailing
944                         while (pos < len)
945                         {
946                                 char ch = s[pos];
947                                 if (allowedTrailingWhiteSpace && Char.IsWhiteSpace (ch)) 
948                                 {
949                                         pos++;
950                                 }
951                                 else if (allowedParentheses && ch == ')' && hasOpeningParentheses) 
952                                 {
953                                         hasOpeningParentheses = false;
954                                         pos++;
955                                 }
956                                 else if (allowedTrailingSign && ch == nfi.NegativeSign[0] && !hasSign) 
957                                 {
958                                         int slen = nfi.NegativeSign.Length;
959                                         if (slen == 1 || s.IndexOf (nfi.NegativeSign, pos, slen) == pos) 
960                                         {
961                                                 hasSign = true;
962                                                 isNegative = true;
963                                                 pos += slen;
964                                         }
965                                 }
966                                 else if (allowedTrailingSign && ch == nfi.PositiveSign[0] && !hasSign) 
967                                 {
968                                         int slen = nfi.PositiveSign.Length;
969                                         if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos) 
970                                         {
971                                                 hasSign = true;
972                                                 pos += slen;
973                                         }
974                                 }
975                                 else
976                                 {
977                                         // trailing zero characters are allowed
978                                         if (ch == 0){
979                                                 while (++pos < len && s [pos] == 0)
980                                                         ;
981                                                 if (pos == len)
982                                                         break;
983                                         }
984                                         
985                                         if (throwex)
986                                                 ThrowAtPos (pos);
987                                         else
988                                                 return null;
989                                 }
990                         }
991
992                         if (hasOpeningParentheses) {
993                                 if (throwex)
994                                         throw new FormatException (Locale.GetText ("Closing Parentheses not found"));
995                                 else
996                                         return null;
997                         }
998
999                         if (!hasDecimalPoint)
1000                                 decPos = sb.Length;
1001
1002                         return sb.ToString ();
1003                 }
1004
1005                 public static Decimal Parse (string s, NumberStyles style, IFormatProvider provider) 
1006                 {
1007                         if (s == null)
1008                                 throw new ArgumentNullException ("s");
1009
1010                         if ((style & NumberStyles.AllowHexSpecifier) != 0)
1011                                 throw new ArgumentException ("Decimal.TryParse does not accept AllowHexSpecifier", "style");
1012
1013                         Decimal result;
1014                         PerformParse (s, style, provider, out result, true);
1015                         return result;
1016                 }
1017         
1018                 public static bool TryParse (string s, out Decimal result)
1019                 {
1020                         if (s == null){
1021                                 result = 0;
1022                                 return false;
1023                         }
1024                         return PerformParse (s, NumberStyles.Number, null, out result, false);
1025                 }
1026
1027                 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out decimal result)
1028                 {
1029                         if (s == null || (style & NumberStyles.AllowHexSpecifier) != 0){
1030                                 result = 0;
1031                                 return false;
1032                         }
1033
1034                         return PerformParse (s, style, provider, out result, false);
1035                 }
1036
1037                 static bool PerformParse (string s, NumberStyles style, IFormatProvider provider, out Decimal res, bool throwex) 
1038                 {
1039                         NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
1040
1041                         int iDecPos, exp;
1042                         bool isNegative, expFlag;
1043                         s = stripStyles(s, style, nfi, out iDecPos, out isNegative, out expFlag, out exp, throwex);
1044                         if (s == null){
1045                                 res = 0;
1046                                 return false;
1047                         }
1048
1049                         if (iDecPos < 0){
1050                                 if (throwex)
1051                                         throw new Exception (Locale.GetText ("Error in System.Decimal.Parse"));
1052                                 res = 0;
1053                                 return false;
1054                         }
1055
1056                         // first we remove leading 0
1057                         int len = s.Length;
1058                         int i = 0;
1059                         while ((i < iDecPos) && (s [i] == '0'))
1060                                 i++;
1061                         if ((i > 1) && (len > 1)) {
1062                                 s = s.Substring (i, len - i);
1063                                 iDecPos -= i;
1064                         }
1065
1066                         // first 0. may not be here but is part of the maximum length
1067                         int max = ((iDecPos == 0) ? 27 : 28);
1068                         len = s.Length;
1069                         if (len >= max + 1) {
1070                                 // number lower than MaxValue (base-less) can have better precision
1071                                 if (String.Compare (s, 0, "79228162514264337593543950335", 0, max + 1,
1072                                         false, CultureInfo.InvariantCulture) <= 0) {
1073                                         max++;
1074                                 }
1075                         }
1076
1077                         // then we trunc the string
1078                         if ((len > max) && (iDecPos < len)) {
1079                                 int round = (s [max] - '0');
1080                                 s = s.Substring (0, max);
1081
1082                                 bool addone = false;
1083                                 if (round > 5) {
1084                                         addone = true;
1085                                 }
1086                                 else if (round == 5) {
1087                                         if (isNegative) {
1088                                                 addone = true;
1089                                         }
1090                                         else {
1091                                                 // banker rounding applies :(
1092                                                 int previous = (s [max - 1] - '0');
1093                                                 addone = ((previous & 0x01) == 0x01);
1094                                         }
1095                                 }
1096                                 if (addone) {
1097                                         char[] array = s.ToCharArray ();
1098                                         int p = max - 1;
1099                                         while (p >= 0) {
1100                                                 int b = (array [p] - '0');
1101                                                 if (array [p] != '9') {
1102                                                         array [p] = (char)(b + '1');
1103                                                         break;
1104                                                 }
1105                                                 else {
1106                                                         array [p--] = '0';
1107                                                 }
1108                                         }
1109                                         if ((p == -1) && (array [0] == '0')) {
1110                                                 iDecPos++;
1111                                                 s = "1".PadRight (iDecPos, '0');
1112                                         }
1113                                         else
1114                                                 s = new String (array);
1115                                 }
1116                         }
1117
1118                         Decimal result;
1119                         // always work in positive (rounding issues)
1120                         if (string2decimal (out result, s, (uint)iDecPos, 0) != 0){
1121                                 if (throwex)
1122                                         throw new OverflowException ();
1123                                 res = 0;
1124                                 return false;
1125                         }
1126
1127                         if (expFlag) {
1128                                 if (decimalSetExponent (ref result, exp) != 0){
1129                                         if (throwex)
1130                                                 throw new OverflowException ();
1131                                         res = 0;
1132                                         return false;
1133                                 }
1134                         }
1135
1136                         if (isNegative)
1137                                 result.flags ^= SIGN_FLAG;
1138
1139                         res = result;
1140                         return true;
1141                 }
1142
1143                 public TypeCode GetTypeCode ()
1144                 {
1145                         return TypeCode.Decimal;
1146                 }
1147
1148                 public static byte ToByte (decimal value)
1149                 {
1150                         if (value > Byte.MaxValue || value < Byte.MinValue)
1151                                 throw new OverflowException (Locale.GetText (
1152                                         "Value is greater than Byte.MaxValue or less than Byte.MinValue"));
1153
1154                         // return truncated value
1155                         return (byte)(Decimal.Truncate (value));
1156                 }
1157
1158                 public static double ToDouble (decimal d)
1159                 {
1160                         return Convert.ToDouble (d);
1161                 }
1162
1163                 public static short ToInt16 (decimal value)
1164                 {
1165                         if (value > Int16.MaxValue || value < Int16.MinValue)
1166                                 throw new OverflowException (Locale.GetText (
1167                                         "Value is greater than Int16.MaxValue or less than Int16.MinValue"));
1168
1169                         // return truncated value
1170                         return (Int16)(Decimal.Truncate (value));
1171                 }
1172
1173                 public static int ToInt32 (decimal d)
1174                 {
1175                         if (d > Int32.MaxValue || d < Int32.MinValue)
1176                                 throw new OverflowException (Locale.GetText (
1177                                         "Value is greater than Int32.MaxValue or less than Int32.MinValue"));
1178
1179                         // return truncated value
1180                         return (Int32)(Decimal.Truncate (d));
1181                 }
1182         
1183                 public static long ToInt64 (decimal d)
1184                 {
1185                         if (d > Int64.MaxValue || d < Int64.MinValue)
1186                                 throw new OverflowException (Locale.GetText (
1187                                         "Value is greater than Int64.MaxValue or less than Int64.MinValue"));
1188
1189                         // return truncated value
1190                         return (Int64)(Decimal.Truncate (d));
1191                 }
1192
1193                 public static long ToOACurrency (decimal value)
1194                 {
1195                         return (long) (value * 10000);
1196                 }
1197
1198                 [CLSCompliant(false)]
1199                 public static sbyte ToSByte (decimal value)
1200                 {
1201                         if (value > SByte.MaxValue || value < SByte.MinValue)
1202                                 throw new OverflowException (Locale.GetText (
1203                                         "Value is greater than SByte.MaxValue or less than SByte.MinValue"));
1204
1205                         // return truncated value
1206                         return (SByte)(Decimal.Truncate (value));
1207                 }
1208         
1209                 public static float ToSingle (decimal d)
1210                 {
1211                         return Convert.ToSingle (d);
1212                 }
1213
1214                 [CLSCompliant(false)]
1215                 public static ushort ToUInt16 (decimal value)
1216                 {
1217                         if (value > UInt16.MaxValue || value < UInt16.MinValue)
1218                                 throw new OverflowException (Locale.GetText (
1219                                         "Value is greater than UInt16.MaxValue or less than UInt16.MinValue"));
1220
1221                         // return truncated value
1222                         return (UInt16)(Decimal.Truncate (value));
1223                 }
1224
1225                 [CLSCompliant(false)]
1226                 public static uint ToUInt32 (decimal d)
1227                 {
1228                         if (d > UInt32.MaxValue || d < UInt32.MinValue)
1229                                 throw new OverflowException (Locale.GetText (
1230                                         "Value is greater than UInt32.MaxValue or less than UInt32.MinValue"));
1231
1232                         // return truncated value
1233                         return (UInt32)(Decimal.Truncate (d));
1234                 }
1235
1236                 [CLSCompliant(false)]
1237                 public static ulong ToUInt64 (decimal d)
1238                 {
1239                         if (d > UInt64.MaxValue || d < UInt64.MinValue)
1240                                 throw new OverflowException (Locale.GetText (
1241                                         "Value is greater than UInt64.MaxValue or less than UInt64.MinValue"));
1242
1243                         // return truncated value
1244                         return (UInt64)(Decimal.Truncate (d));
1245                 }
1246
1247                 object IConvertible.ToType (Type targetType, IFormatProvider provider)
1248                 {
1249                         if (targetType == null)
1250                                 throw new ArgumentNullException ("targetType");
1251                         return Convert.ToType (this, targetType, provider, false);
1252                 }
1253
1254                 bool IConvertible.ToBoolean (IFormatProvider provider)
1255                 {
1256                         return Convert.ToBoolean (this);
1257                 }
1258
1259                 byte IConvertible.ToByte (IFormatProvider provider)
1260                 {
1261                         return Convert.ToByte (this);
1262                 }
1263
1264                 char IConvertible.ToChar (IFormatProvider provider)
1265                 {
1266                         throw new InvalidCastException ();
1267                 }
1268
1269                 DateTime IConvertible.ToDateTime (IFormatProvider provider)
1270                 {
1271                         throw new InvalidCastException ();
1272                 }
1273
1274                 decimal IConvertible.ToDecimal (IFormatProvider provider)
1275                 {
1276                         return this;
1277                 }
1278
1279                 double IConvertible.ToDouble (IFormatProvider provider)
1280                 {
1281                         return Convert.ToDouble (this);
1282                 }
1283
1284                 short IConvertible.ToInt16 (IFormatProvider provider)
1285                 {
1286                         return Convert.ToInt16 (this);
1287                 }
1288
1289                 int IConvertible.ToInt32 (IFormatProvider provider)
1290                 {
1291                         return Convert.ToInt32 (this);
1292                 }
1293
1294                 long IConvertible.ToInt64 (IFormatProvider provider)
1295                 {
1296                         return Convert.ToInt64 (this);
1297                 }
1298
1299                 sbyte IConvertible.ToSByte (IFormatProvider provider)
1300                 {
1301                         return Convert.ToSByte (this);
1302                 }
1303
1304                 float IConvertible.ToSingle (IFormatProvider provider)
1305                 {
1306                         return Convert.ToSingle (this);
1307                 }
1308
1309                 ushort IConvertible.ToUInt16 (IFormatProvider provider)
1310                 {
1311                         return Convert.ToUInt16 (this);
1312                 }
1313
1314                 uint IConvertible.ToUInt32 (IFormatProvider provider)
1315                 {
1316                         return Convert.ToUInt32 (this);
1317                 }
1318
1319                 ulong IConvertible.ToUInt64 (IFormatProvider provider)
1320                 {
1321                         return Convert.ToUInt64 (this);
1322                 }
1323
1324                 public string ToString (string format, IFormatProvider provider) 
1325                 {
1326                         return NumberFormatter.NumberToString (format, this, provider);
1327                 }
1328
1329                 public override string ToString () 
1330                 {
1331                         return ToString ("G", null);
1332                 }
1333
1334                 public string ToString (string format) 
1335                 {
1336                         return ToString (format, null);
1337                 }
1338
1339                 public string ToString (IFormatProvider provider) 
1340                 {
1341                         return ToString ("G", provider);
1342                 }
1343                 
1344 #if NET_4_0
1345                 void IDeserializationCallback.OnDeserialization(object sender)
1346                 {
1347                 }
1348 #endif
1349
1350 #if !MSTEST
1351                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1352                 private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
1353
1354                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1355                 private static extern int decimal2Int64 (ref Decimal val, out long result);
1356
1357                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1358                 private static extern int double2decimal (out Decimal erg, double val, int digits);
1359
1360                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1361                 private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
1362
1363                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1364                 internal static extern int decimal2string (ref Decimal val, 
1365                     int digits, int decimals, char[] bufDigits, int bufSize, out int decPos, out int sign);
1366
1367                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1368                 internal static extern int string2decimal (out Decimal val, String sDigits, uint decPos, int sign);
1369
1370                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1371                 internal static extern int decimalSetExponent (ref Decimal val, int exp);
1372
1373                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1374                 private static extern double decimal2double (ref Decimal val);
1375
1376                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1377                 private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
1378
1379 //              [MethodImplAttribute(MethodImplOptions.InternalCall)]
1380 //              private static extern void decimalRound (ref Decimal val, int decimals);
1381
1382                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1383                 private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
1384
1385                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1386                 private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1387
1388                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1389                 private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1390
1391                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1392                 private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);
1393 #else
1394                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1395                 [DllImport("libdec", EntryPoint="decimal2UInt64")]
1396                 private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
1397
1398                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1399                 [DllImport("libdec", EntryPoint="decimal2Int64")]
1400                 private static extern int decimal2Int64 (ref Decimal val, out long result);
1401
1402                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1403                 [DllImport("libdec", EntryPoint="double2decimal")]
1404                 private static extern int double2decimal (out Decimal erg, double val, int digits);
1405
1406                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1407                 [DllImport("libdec", EntryPoint="decimalIncr")]
1408                 private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
1409
1410                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1411                 [DllImport("libdec", EntryPoint="decimal2string")]
1412                 internal static extern int decimal2string (ref Decimal val, 
1413                     int digits, int decimals,
1414                     [MarshalAs(UnmanagedType.LPWStr)]StringBuilder bufDigits, 
1415                     int bufSize, out int decPos, out int sign);
1416
1417                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1418                 [DllImport("libdec", EntryPoint="string2decimal")]
1419                 internal static extern int string2decimal (out Decimal val,
1420                     [MarshalAs(UnmanagedType.LPWStr)]String sDigits,
1421                     uint decPos, int sign);
1422
1423                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1424                 [DllImport("libdec", EntryPoint="decimalSetExponent")]
1425                 internal static extern int decimalSetExponent (ref Decimal val, int exp);
1426
1427                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1428                 [DllImport("libdec", EntryPoint="decimal2double")]
1429                 private static extern double decimal2double (ref Decimal val);
1430
1431                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1432                 [DllImport("libdec", EntryPoint="decimalFloorAndTrunc")]
1433                 private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
1434
1435                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1436                 [DllImport("libdec", EntryPoint="decimalRound")]
1437                 private static extern void decimalRound (ref Decimal val, int decimals);
1438
1439                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1440                 [DllImport("libdec", EntryPoint="decimalMult")]
1441                 private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
1442
1443                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1444                 [DllImport("libdec", EntryPoint="decimalDiv")]
1445                 private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1446
1447                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1448                 [DllImport("libdec", EntryPoint="decimalIntDiv")]
1449                 private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1450
1451                 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1452                 [DllImport("libdec", EntryPoint="decimalCompare")]
1453                 private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);
1454
1455 #endif
1456         }
1457 }