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