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