2004-04-24 Andreas Nahr <ClassDevelopment@A-SoftTech.com>
[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 using System;
14 using System.Globalization;
15 using System.Text;
16 using System.Runtime.CompilerServices;
17 #if MSTEST
18 using System.Runtime.InteropServices;
19 #endif
20
21
22 namespace System
23 {
24     /// <summary>
25     /// Represents a floating-point decimal data type with up to 29 significant
26     /// digits, suitable for financial and commercial calculations
27     /// </summary>
28         [Serializable]
29     public struct Decimal: IComparable, IFormattable, IConvertible
30     {
31         // LAMESPEC: the attributes aren't mentioned, but show up in CorCompare
32         // Unfortunately, corcompare starts throwing security exceptions when
33         // these attributes are present...
34             
35         [DecimalConstantAttribute(0, 1, unchecked((uint)-1), unchecked((uint)-1), unchecked((uint)-1))]
36         public static readonly Decimal MinValue = new Decimal(-1, -1, -1, true, 0);
37         [DecimalConstantAttribute(0, 0, unchecked((uint)-1), unchecked((uint)-1), unchecked((uint)-1))]
38         public static readonly Decimal MaxValue = new Decimal(-1, -1, -1, false, 0);
39         [DecimalConstantAttribute(0, 1, 0, 0, 1)]
40         public static readonly Decimal MinusOne = new Decimal(1, 0, 0, true, 0);
41         [DecimalConstantAttribute(0, 0, 0, 0, 1)]
42         public static readonly Decimal One = new Decimal(1, 0, 0, false, 0);
43         [DecimalConstantAttribute(0, 0, 0, 0, 0)]
44         public static readonly Decimal Zero = new Decimal(0, 0, 0, false, 0);
45
46         // maximal decimal value as double
47         private static readonly double dDecMaxValue = 7.922816251426433759354395033e28;
48         // epsilon decimal value as double
49         private static readonly double dDecEpsilon = 0.5e-28;  // == 0.5 * 1 / 10^28
50
51         // some constants
52         private const int DECIMAL_DIVIDE_BY_ZERO = 5;
53         private const uint MAX_SCALE = 28;
54         private const int iMAX_SCALE = 28;
55         private const uint SIGN_FLAG = 0x80000000;
56         private const uint SCALE_MASK = 0x00FF0000;
57         private const int SCALE_SHIFT = 16;
58         private const uint RESERVED_SS32_BITS = 0x7F00FFFF;
59
60         // internal representation of decimal
61         private uint ss32;
62         private uint hi32;
63         private uint lo32;
64         private uint mid32;
65
66         // LAMESPEC: this constructor is missing in specification
67         // but exists in MS Csharp implementation 
68         public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
69         {
70             unchecked 
71             {
72                 lo32 = (uint) lo;
73                 mid32 = (uint) mid;
74                 hi32 = (uint) hi;
75             
76                 if (scale > MAX_SCALE) 
77                 {
78                         throw new ArgumentOutOfRangeException (Locale.GetText ("scale must be between 0 and 28"));
79                 }
80
81                 ss32 = scale;
82                 ss32 <<= SCALE_SHIFT;
83                 if (isNegative) ss32 |= SIGN_FLAG;
84             }
85         }
86
87         public Decimal(int val) 
88         {
89             unchecked 
90             {
91                 hi32 = mid32 = 0;
92                 if (val < 0) 
93                 {
94                     ss32 = SIGN_FLAG;
95                     lo32 = ((uint)~val) + 1;
96                 }
97                 else 
98                 {
99                     ss32 = 0;
100                     lo32 = (uint) val;
101                 }
102             }
103         }
104
105         [CLSCompliant(false)]
106         public Decimal(uint val) 
107         {
108             lo32 = val;
109             ss32 = hi32 = mid32 = 0;
110         }
111
112         public Decimal(long val) 
113         {
114             unchecked 
115             {
116                 hi32 = 0;
117                 if (val < 0) 
118                 {
119                     ss32 = SIGN_FLAG;
120                     ulong u = ((ulong)~val) + 1;
121                     lo32 = (uint)u;
122                     mid32 = (uint)(u >> 32);
123                 }
124                 else 
125                 {
126                     ss32 = 0;
127                     ulong u = (ulong)val;
128                     lo32 = (uint)u;
129                     mid32 = (uint)(u >> 32);
130                 }
131             }
132         }
133
134         [CLSCompliant(false)]
135         public Decimal(ulong uval) 
136         {
137             unchecked 
138             {
139                 ss32 = hi32 = 0;
140                 lo32 = (uint)uval;
141                 mid32 = (uint)(uval >> 32);
142             }
143         }
144
145         public Decimal(float val) 
146         {
147             if (double2decimal(out this, val, 7) != 0) 
148             {
149                 throw new OverflowException();
150             }
151         }
152
153         public Decimal(double val) 
154         {
155             if (double2decimal(out this, val, 15) != 0) 
156             {
157                 throw new OverflowException();
158             }
159         }
160
161         public Decimal(int[] bits) 
162         {
163             if (bits == null) 
164             {
165                 throw new ArgumentNullException(Locale.GetText ("Bits is a null reference"));
166             }
167
168             if (bits.GetLength(0) != 4) 
169             {
170                 throw new ArgumentException(Locale.GetText ("bits does not contain four values"));
171             }
172
173             unchecked {
174                 lo32 = (uint) bits[0];
175                 mid32 = (uint) bits[1];
176                 hi32 = (uint) bits[2];
177                 ss32 = (uint) bits[3];
178                 byte scale = (byte)(ss32 >> SCALE_SHIFT);
179                 if (scale > MAX_SCALE || (ss32 & RESERVED_SS32_BITS) != 0) 
180                 {
181                     throw new ArgumentException(Locale.GetText ("Invalid bits[3]"));
182                 }
183             }
184         }
185
186                 public static decimal FromOACurrency(long cy)
187                 {
188                         return (decimal)cy / (decimal)10000;
189                 }
190         
191         public static int[] GetBits(Decimal d) 
192         {
193             unchecked 
194             {
195                 return new int[] { (int)d.lo32, (int)d.mid32, (int)d.hi32, 
196                                      (int)d.ss32 };
197             }
198         }
199
200         public static Decimal Negate(Decimal d) 
201         {
202             d.ss32 ^= SIGN_FLAG;
203             return d;
204         }
205
206
207         public static Decimal Add(Decimal d1, Decimal d2) 
208         {
209             if (decimalIncr(ref d1, ref d2) == 0)
210                 return d1;
211             else
212                 throw new OverflowException(Locale.GetText ("Overflow on adding decimal number"));
213         }
214
215         public static Decimal Subtract(Decimal d1, Decimal d2) 
216         {
217             d2.ss32 ^= SIGN_FLAG;
218             int result = decimalIncr(ref d1, ref d2);
219             if (result == 0)
220                 return d1;
221             else
222                 throw new OverflowException(Locale.GetText ("Overflow on subtracting decimal numbers ("+result+")"));
223         }
224
225         public override int GetHashCode() 
226         {
227             return (int)lo32;
228         }
229
230         public static Decimal operator +(Decimal d1, Decimal d2)
231         {
232             return Add(d1, d2);
233         }
234
235         public static Decimal operator --(Decimal d) 
236         {
237             return Add(d, MinusOne);
238         }
239
240         public static Decimal operator ++(Decimal d) 
241         {
242             return Add(d, One);
243         }
244
245         public static Decimal operator -(Decimal d1, Decimal d2) 
246         {
247             return Subtract(d1, d2);
248         }
249
250         public static Decimal operator -(Decimal d) 
251         {
252             return Negate(d);
253         }
254
255         public static Decimal operator +(Decimal d) 
256         {
257             return d;
258         }
259
260         public static Decimal operator *(Decimal d1, Decimal d2)
261         {
262             return Multiply(d1, d2);
263         }
264
265         public static Decimal operator /(Decimal d1, Decimal d2) 
266         {
267             return Divide(d1, d2);
268         }
269
270         public static Decimal operator %(Decimal d1, Decimal d2) 
271         {
272             return Remainder(d1, d2);
273         }
274
275         public static explicit operator byte(Decimal val)
276         {
277             ulong result;
278
279             if (decimal2UInt64(ref val, out result) != 0)
280             {
281                 throw new System.OverflowException();
282             }
283
284             if (result > Byte.MaxValue || result < Byte.MinValue) 
285             {
286                 throw new System.OverflowException();
287             }
288
289             return (byte) result;
290         }
291
292         [CLSCompliant(false)]
293         public static explicit operator sbyte(Decimal val) 
294         {
295             long result;
296
297             if (decimal2Int64(ref val, out result) != 0)
298             {
299                 throw new System.OverflowException();
300             }
301
302             if (result > SByte.MaxValue || result < SByte.MinValue) 
303             {
304                 throw new System.OverflowException();
305             }
306
307             return (sbyte) result;
308         }
309
310         public static explicit operator char(Decimal val) 
311         {
312             ulong result;
313
314             if (decimal2UInt64(ref val, out result) != 0)
315             {
316                 throw new System.OverflowException();
317             }
318
319             if (result > Char.MaxValue || result < Char.MinValue) 
320             {
321                 throw new System.OverflowException();
322             }
323
324             return (char) result;
325         }
326
327         public static explicit operator short(Decimal val) 
328         {
329             long result;
330
331             if (decimal2Int64(ref val, out result) != 0)
332             {
333                 throw new System.OverflowException();
334             }
335
336             if (result > Int16.MaxValue || result < Int16.MinValue) 
337             {
338                 throw new System.OverflowException();
339             }
340
341             return (short) result;
342         }
343
344         [CLSCompliant(false)]
345         public static explicit operator ushort(Decimal val) 
346         {
347             ulong result;
348
349             if (decimal2UInt64(ref val, out result) != 0)
350             {
351                 throw new System.OverflowException();
352             }
353
354             if (result > UInt16.MaxValue || result < UInt16.MinValue) 
355             {
356                 throw new System.OverflowException();
357             }
358
359             return (ushort) result;
360         }
361
362         public static explicit operator int(Decimal val) 
363         {
364             long result;
365
366             if (decimal2Int64(ref val, out result) != 0)
367             {
368                 throw new System.OverflowException();
369             }
370
371             if (result > Int32.MaxValue || result < Int32.MinValue) 
372             {
373                 throw new System.OverflowException();
374             }
375
376             return (int) result;
377         }
378
379         [CLSCompliant(false)]
380         public static explicit operator uint(Decimal val) 
381         {
382             ulong result;
383
384             if (decimal2UInt64(ref val, out result) != 0)
385             {
386                 throw new System.OverflowException();
387             }
388
389             if (result > UInt32.MaxValue || result < UInt32.MinValue) 
390             {
391                 throw new System.OverflowException();
392             }
393
394             return (uint) result;
395         }
396
397         public static explicit operator long(Decimal val) 
398         {
399             long result;
400
401             if (decimal2Int64(ref val, out result) != 0)
402             {
403                 throw new System.OverflowException();
404             }
405
406             return result;
407         }
408
409         [CLSCompliant(false)]
410         public static explicit operator ulong(Decimal val) 
411         {
412             ulong result;
413
414             if (decimal2UInt64(ref val, out result) != 0)
415             {
416                 throw new System.OverflowException();
417             }
418
419             return result;
420         }
421
422         public static implicit operator Decimal(byte val) 
423         {
424             return new Decimal(val);
425         }
426
427         [CLSCompliant(false)]
428         public static implicit operator Decimal(sbyte val) 
429         {
430             return new Decimal(val);
431         }
432
433         public static implicit operator Decimal(short val) 
434         {
435             return new Decimal(val);
436         }
437
438         [CLSCompliant(false)]
439         public static implicit operator Decimal(ushort val) 
440         {
441             return new Decimal(val);
442         }
443
444         public static implicit operator Decimal(char val) 
445         {
446             return new Decimal(val);
447         }
448
449         public static implicit operator Decimal(int val) 
450         {
451             return new Decimal(val);
452         }
453
454         [CLSCompliant(false)]
455         public static implicit operator Decimal(uint val) 
456         {
457             return new Decimal(val);
458         }
459
460         public static implicit operator Decimal(long val) 
461         {
462             return new Decimal(val);
463         }
464
465         [CLSCompliant(false)]
466         public static implicit operator Decimal(ulong val) 
467         {
468             return new Decimal(val);
469         }
470
471         public static explicit operator Decimal(float val) 
472         {
473             return new Decimal(val);
474         }
475
476         public static explicit operator Decimal(double val)
477         {
478             return new Decimal(val);
479         }
480
481         public static explicit operator float(Decimal val)
482         {
483             return (float) (double) val;
484         }
485
486         public static explicit operator double(Decimal val)
487         {
488             return decimal2double(ref val);
489         }
490
491
492         public static bool operator !=(Decimal d1, Decimal d2) 
493         {
494             return !Equals(d1, d2);
495         }
496
497         public static bool operator ==(Decimal d1, Decimal d2) 
498         {
499             return Equals(d1, d2);
500         }
501
502         public static bool operator >(Decimal d1, Decimal d2) 
503         {
504             return decimalCompare(ref d1, ref d2) > 0;
505         }
506
507         public static bool operator >=(Decimal d1, Decimal d2) 
508         {
509             return decimalCompare(ref d1, ref d2) >= 0;
510         }
511
512         public static bool operator <(Decimal d1, Decimal d2) 
513         {
514             return decimalCompare(ref d1, ref d2) < 0;
515         }
516
517         public static bool operator <=(Decimal d1, Decimal d2) 
518         {
519             return decimalCompare(ref d1, ref d2) <= 0;
520         }
521
522         public static bool Equals(Decimal d1, Decimal d2) 
523         {
524             return decimalCompare(ref d1, ref d2) == 0;
525         }
526
527         public override bool Equals(object o) 
528         {
529             if (!(o is Decimal))
530                 return false;
531
532             return Equals((Decimal) o, this);
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             if (decimals < 0 || decimals > iMAX_SCALE) 
550             {
551                 throw new ArgumentOutOfRangeException(Locale.GetText ("decimals must be between 0 and 28"));
552             }
553
554             decimalRound(ref d, decimals);
555             return d;
556         }
557
558         public static Decimal Multiply(Decimal d1, Decimal d2) 
559         {
560             if (decimalMult(ref d1, ref d2) != 0) 
561             {
562                 throw new OverflowException();
563             }
564
565             return d1;
566         }
567
568         public static Decimal Divide(Decimal d1, Decimal d2) 
569         {
570             if (d1 == 0 && d2 != 0) return 0;
571
572             Decimal d3;
573             int rc = decimalDiv(out d3, ref d1, ref d2);
574
575             if (rc != 0)
576             {
577                 if (rc == DECIMAL_DIVIDE_BY_ZERO)
578                     throw new DivideByZeroException();
579                 else 
580                     throw new OverflowException();
581             }
582
583             return d3;
584         }
585
586         public static Decimal Remainder(Decimal d1, Decimal d2) 
587         {
588             Decimal d3;
589             int rc = decimalIntDiv(out d3, ref d1, ref d2);
590
591             if (rc != 0)
592             {
593                 if (rc == DECIMAL_DIVIDE_BY_ZERO)
594                     throw new DivideByZeroException();
595                 else 
596                     throw new OverflowException();
597             }
598
599             return d1 - d3 * d2;
600         }
601
602         public static int Compare(Decimal d1, Decimal d2) 
603         {
604             return decimalCompare(ref d1, ref d2);
605         }
606
607         public int CompareTo(object val)
608         {
609             if (val == null)
610                 return 1;
611             
612             if (!(val is Decimal))
613                 throw new ArgumentException (Locale.GetText ("Value is not a System.Decimal"));
614
615             Decimal d2 = (Decimal)val;
616             return decimalCompare(ref this, ref d2);
617         }
618
619         public static Decimal Parse(string s) 
620         {
621             return Parse(s, NumberStyles.Number, null);
622         }
623
624         public static Decimal Parse(string s, NumberStyles style) 
625         {
626             return Parse(s, style, null);
627         }
628
629         public static Decimal Parse(string s, IFormatProvider provider) 
630         {
631             return Parse(s, NumberStyles.Number, provider);
632         }
633
634         private static string stripStyles(string s, NumberStyles style, NumberFormatInfo nfi, 
635             out int decPos, out bool isNegative, out bool expFlag, out int exp)
636         {
637             string invalidChar = Locale.GetText ("Invalid character at position ");
638             string invalidExponent = Locale.GetText ("Invalid exponent");
639             isNegative = false;
640             expFlag = false;
641             exp = 0;
642             decPos = -1;
643
644             bool hasSign = false;
645             bool hasOpeningParentheses = false;
646             bool hasDecimalPoint = false;
647             bool allowedLeadingWhiteSpace = ((style & NumberStyles.AllowLeadingWhite) != 0);
648             bool allowedTrailingWhiteSpace = ((style & NumberStyles.AllowTrailingWhite) != 0);
649             bool allowedLeadingSign = ((style & NumberStyles.AllowLeadingSign) != 0);
650             bool allowedTrailingSign = ((style & NumberStyles.AllowTrailingSign) != 0);
651             bool allowedParentheses = ((style & NumberStyles.AllowParentheses) != 0);
652             bool allowedThousands = ((style & NumberStyles.AllowThousands) != 0);
653             bool allowedDecimalPoint = ((style & NumberStyles.AllowDecimalPoint) != 0);
654             bool allowedExponent = ((style & NumberStyles.AllowExponent) != 0);
655
656             /* get rid of currency symbol */
657             bool hasCurrency = false;
658             if ((style & NumberStyles.AllowCurrencySymbol) != 0)
659             {
660                 int index = s.IndexOf(nfi.CurrencySymbol);
661                 if (index >= 0) 
662                 {
663                     s = s.Remove(index, nfi.CurrencySymbol.Length);
664                     hasCurrency = true;
665                 }
666             }
667
668             string decimalSep = (hasCurrency) ? nfi.CurrencyDecimalSeparator : nfi.NumberDecimalSeparator;
669             string groupSep = (hasCurrency) ? nfi.CurrencyGroupSeparator : nfi.NumberGroupSeparator;
670
671             int pos = 0;
672             int len = s.Length;
673
674             StringBuilder sb = new StringBuilder(len);
675
676             // leading
677             while (pos < len) 
678             {
679                 char ch = s[pos];
680                 if (Char.IsDigit(ch)) 
681                 {
682                     break; // end of leading
683                 }
684                 else if (allowedLeadingWhiteSpace && Char.IsWhiteSpace(ch)) 
685                 {
686                     pos++;
687                 }
688                 else if (allowedParentheses && ch == '(' && !hasSign && !hasOpeningParentheses) 
689                 {
690                     hasOpeningParentheses = true;
691                     hasSign = true;
692                     isNegative = true;
693                     pos++;
694                 }
695                 else if (allowedLeadingSign && ch == nfi.NegativeSign[0] && !hasSign) 
696                 {
697                     int slen = nfi.NegativeSign.Length;
698                     if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos) 
699                     {
700                         hasSign = true;
701                         isNegative = true;
702                         pos += slen;
703                     }
704                 }
705                 else if (allowedLeadingSign && ch == nfi.PositiveSign[0] && !hasSign) 
706                 {
707                     int slen = nfi.PositiveSign.Length;
708                     if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos) 
709                     {
710                         hasSign = true;
711                         pos += slen;
712                     }
713                 }
714                 else if (allowedDecimalPoint && ch == decimalSep[0])
715                 {
716                     int slen = decimalSep.Length;
717                     if (slen != 1 && s.IndexOf(decimalSep, pos, slen) != pos) 
718                     {
719                         throw new FormatException(invalidChar + pos);
720                     }
721                     break;
722                 }
723                 else
724                 {
725                     throw new FormatException(invalidChar + pos);
726                 }
727             }
728
729             if (pos == len)
730                 throw new FormatException(Locale.GetText ("No digits found"));
731
732             // digits 
733             while (pos < len)
734             {
735                 char ch = s[pos];
736                 if (Char.IsDigit(ch)) 
737                 {
738                     sb.Append(ch);
739                     pos++;
740                 }
741                 else if (allowedThousands && ch == groupSep[0]) 
742                 {
743                     int slen = groupSep.Length;
744                     if (slen != 1 && s.IndexOf(groupSep, pos, slen) != pos) 
745                     {
746                         throw new FormatException(invalidChar + pos);
747                     }
748                     pos += slen;
749                 }
750                 else if (allowedDecimalPoint && ch == decimalSep[0] && !hasDecimalPoint)
751                 {
752                     int slen = decimalSep.Length;
753                     if (slen == 1 || s.IndexOf(decimalSep, pos, slen) == pos) 
754                     {
755                         decPos = sb.Length;
756                         hasDecimalPoint = true;
757                         pos += slen;
758                     }
759                 }
760                 else
761                 {
762                     break;
763                 }
764             }
765
766             // exponent
767             if (pos < len)
768             {
769                 char ch = s[pos];
770                 if (allowedExponent && Char.ToUpper(ch) == 'E')
771                 {
772                     expFlag = true;
773                     pos++; if (pos >= len) throw new FormatException(invalidExponent);
774                     ch = s[pos];
775                     bool isNegativeExp = false;
776                     if (ch == nfi.PositiveSign[0])
777                     {
778                         int slen = nfi.PositiveSign.Length;
779                         if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos) 
780                         {
781                             pos += slen;  if (pos >= len) throw new FormatException(invalidExponent);
782                         }
783                     }
784                     else if (ch == nfi.NegativeSign[0])
785                     {
786                         int slen = nfi.NegativeSign.Length;
787                         if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos) 
788                         {
789                             pos += slen; if (pos >= len) throw new FormatException(invalidExponent);
790                             isNegativeExp = true;
791                         }
792                     }
793                     ch = s[pos];
794                     if (!Char.IsDigit(ch)) throw new FormatException(invalidExponent);
795                     exp = ch - '0';
796                     pos++;
797                     while (pos < len && Char.IsDigit(s[pos])) 
798                     {
799                         exp *= 10;
800                         exp += s[pos] - '0';
801                         pos++;
802                     }
803                     if (isNegativeExp) exp *= -1;
804                 }
805             }
806
807             // trailing
808             while (pos < len)
809             {
810                 char ch = s[pos];
811                 if (allowedTrailingWhiteSpace && Char.IsWhiteSpace(ch)) 
812                 {
813                     pos++;
814                 }
815                 else if (allowedParentheses && ch == ')' && hasOpeningParentheses) 
816                 {
817                     hasOpeningParentheses = false;
818                     pos++;
819                 }
820                 else if (allowedTrailingSign && ch == nfi.NegativeSign[0] && !hasSign) 
821                 {
822                     int slen = nfi.NegativeSign.Length;
823                     if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos) 
824                     {
825                         hasSign = true;
826                         isNegative = true;
827                         pos += slen;
828                     }
829                 }
830                 else if (allowedTrailingSign && ch == nfi.PositiveSign[0] && !hasSign) 
831                 {
832                     int slen = nfi.PositiveSign.Length;
833                     if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos) 
834                     {
835                         hasSign = true;
836                         pos += slen;
837                     }
838                 }
839                 else
840                 {
841                     throw new FormatException(invalidChar + pos);
842                 }
843             }
844
845             if (hasOpeningParentheses) throw new FormatException (
846                     Locale.GetText ("Closing Parentheses not found"));
847             
848             if (!hasDecimalPoint) decPos = sb.Length;
849
850             return sb.ToString();
851         }
852
853         public static Decimal Parse(string s, NumberStyles style, IFormatProvider provider) 
854         {
855             NumberFormatInfo nfi = NumberFormatInfo.GetInstance(provider);
856
857             if (s == null) throw new ArgumentNullException (Locale.GetText ("string s"));
858
859             int iDecPos, exp;
860             bool isNegative, expFlag;
861             s = stripStyles(s, style, nfi, out iDecPos, out isNegative, out expFlag, out exp);
862
863             if (iDecPos < 0)
864                 throw new Exception (Locale.GetText ("Error in System.Decimal.Parse"));
865             uint decPos = (uint) iDecPos;
866
867             Decimal d;
868             int digits = s.Length;
869             int sign = (isNegative) ? 1 : 0;
870             if (string2decimal(out d, s, decPos, sign) != 0)
871             {
872                 throw new OverflowException();
873             }
874
875             if (expFlag)
876             {
877                 if (decimalSetExponent(ref d, exp) != 0)
878                     throw new OverflowException();
879             }
880
881             return d;
882         }
883
884         public TypeCode GetTypeCode ()
885         {
886             return TypeCode.Decimal;
887         }
888
889         public static byte ToByte (decimal value)
890         {
891                 return Convert.ToByte (value);
892         }
893
894         public static double ToDouble (decimal value)
895         {
896                 return Convert.ToDouble (value);
897         }
898
899         public static short ToInt16 (decimal value)
900         {
901                 return Convert.ToInt16 (value);
902         }
903
904         public static int ToInt32 (decimal value)
905         {
906                 return Convert.ToInt32 (value);
907         }
908         
909         public static long ToInt64 (decimal value)
910         {
911                 return Convert.ToInt64 (value);
912         }
913
914         public static long ToOACurrency (decimal value)
915         {
916                 return (long) (value * 10000);
917         }
918
919         [CLSCompliant(false)]
920         public static sbyte ToSByte (decimal value)
921         {
922                 return Convert.ToSByte (value);
923         }
924         
925         public static float ToSingle (decimal value)
926         {
927                 return Convert.ToSingle (value);
928         }
929
930         [CLSCompliant(false)]
931         public static ushort ToUInt16 (decimal value)
932         {
933                 return Convert.ToUInt16 (value);
934         }
935
936         [CLSCompliant(false)]
937         public static uint ToUInt32 (decimal value)
938         {
939                 return Convert.ToUInt32 (value);
940         }
941
942         [CLSCompliant(false)]
943         public static ulong ToUInt64 (decimal value)
944         {
945                 return Convert.ToUInt64 (value);
946         }
947                 
948         object IConvertible.ToType (Type conversionType, IFormatProvider provider)
949         {
950             return Convert.ToType (this, conversionType, provider);
951         }
952
953         bool IConvertible.ToBoolean (IFormatProvider provider)
954         {
955             return Convert.ToBoolean (this);
956         }
957
958         byte IConvertible.ToByte (IFormatProvider provider)
959         {
960             return Convert.ToByte (this);
961         }
962
963         char IConvertible.ToChar (IFormatProvider provider)
964         {
965             throw new InvalidCastException ();
966         }
967
968         [CLSCompliant (false)]
969         DateTime IConvertible.ToDateTime (IFormatProvider provider)
970         {
971             throw new InvalidCastException ();
972         }
973
974         decimal IConvertible.ToDecimal (IFormatProvider provider)
975         {
976             return this;
977         }
978
979         double IConvertible.ToDouble (IFormatProvider provider)
980         {
981             return Convert.ToDouble (this);
982         }
983
984         short IConvertible.ToInt16 (IFormatProvider provider)
985         {
986             return Convert.ToInt16 (this);
987         }
988
989         int IConvertible.ToInt32 (IFormatProvider provider)
990         {
991             return Convert.ToInt32 (this);
992         }
993
994         long IConvertible.ToInt64 (IFormatProvider provider)
995         {
996             return Convert.ToInt64 (this);
997         }
998
999         [CLSCompliant (false)]
1000         sbyte IConvertible.ToSByte (IFormatProvider provider)
1001         {
1002             return Convert.ToSByte (this);
1003         }
1004
1005         float IConvertible.ToSingle (IFormatProvider provider)
1006         {
1007             return Convert.ToSingle (this);
1008         }
1009
1010         [CLSCompliant (false)]
1011         ushort IConvertible.ToUInt16 (IFormatProvider provider)
1012         {
1013             return Convert.ToUInt16 (this);
1014         }
1015
1016         [CLSCompliant (false)]
1017         uint IConvertible.ToUInt32 (IFormatProvider provider)
1018         {
1019             return Convert.ToUInt32 (this);
1020         }
1021
1022         [CLSCompliant (false)]
1023         ulong IConvertible.ToUInt64 (IFormatProvider provider)
1024         {
1025             return Convert.ToUInt64 (this);
1026         }
1027
1028         public string ToString(string format, IFormatProvider provider) 
1029         {
1030             NumberFormatInfo nfi = NumberFormatInfo.GetInstance(provider);
1031             
1032             if (format == null) format = "G";   
1033                         
1034             return DecimalFormatter.NumberToString(format, nfi, this);
1035         }
1036
1037         public override string ToString() 
1038         {
1039             return ToString("G", null);
1040         }
1041
1042         public string ToString(string format) 
1043         {
1044             return ToString(format, null);
1045         }
1046
1047         public string ToString(IFormatProvider provider) 
1048         {
1049             return ToString("G", provider);
1050         }
1051
1052 #if !MSTEST
1053         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1054         private static extern int decimal2UInt64(ref Decimal val, 
1055             out ulong result);
1056
1057         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1058         private static extern int decimal2Int64(ref Decimal val, 
1059             out long result);
1060
1061         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1062         private static extern int double2decimal(out Decimal erg, 
1063             double val, int digits);
1064
1065         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1066         private static extern int decimalIncr(ref Decimal d1, ref Decimal d2);
1067
1068         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1069         internal static extern int decimal2string(ref Decimal val, 
1070             int digits, int decimals, char[] bufDigits, int bufSize, out int decPos, out int sign);
1071
1072         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1073         internal static extern int string2decimal(out Decimal val, String sDigits, uint decPos, int sign);
1074
1075         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1076         internal static extern int decimalSetExponent(ref Decimal val, int exp);
1077
1078         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1079         private static extern double decimal2double(ref Decimal val);
1080
1081         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1082         private static extern void decimalFloorAndTrunc(ref Decimal val, 
1083             int floorFlag);
1084         
1085         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1086         private static extern void decimalRound(ref Decimal val, int decimals);
1087
1088         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1089         private static extern int decimalMult(ref Decimal pd1, ref Decimal pd2);
1090         
1091         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1092         private static extern int decimalDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1093
1094         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1095         private static extern int decimalIntDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1096
1097         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1098         private static extern int decimalCompare(ref Decimal d1, ref Decimal d2);
1099 #else
1100         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1101         [DllImport("libdec", EntryPoint="decimal2UInt64")]
1102         private static extern int decimal2UInt64(ref Decimal val, 
1103             out ulong result);
1104
1105         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1106         [DllImport("libdec", EntryPoint="decimal2Int64")]
1107         private static extern int decimal2Int64(ref Decimal val, 
1108             out long result);
1109
1110         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1111         [DllImport("libdec", EntryPoint="double2decimal")]
1112         private static extern int double2decimal(out Decimal erg, 
1113             double val, int digits);
1114
1115         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1116         [DllImport("libdec", EntryPoint="decimalIncr")]
1117         private static extern int decimalIncr(ref Decimal d1, ref Decimal d2);
1118
1119         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1120         [DllImport("libdec", EntryPoint="decimal2string")]
1121         internal static extern int decimal2string(ref Decimal val, 
1122             int digits, int decimals,
1123             [MarshalAs(UnmanagedType.LPWStr)]StringBuilder bufDigits, 
1124             int bufSize, out int decPos, out int sign);
1125
1126         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1127         [DllImport("libdec", EntryPoint="string2decimal")]
1128         internal static extern int string2decimal(out Decimal val,
1129             [MarshalAs(UnmanagedType.LPWStr)]String sDigits,
1130             uint decPos, int sign);
1131
1132         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1133         [DllImport("libdec", EntryPoint="decimalSetExponent")]
1134         internal static extern int decimalSetExponent(ref Decimal val, int exp);
1135
1136         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1137         [DllImport("libdec", EntryPoint="decimal2double")]
1138         private static extern double decimal2double(ref Decimal val);
1139
1140         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1141         [DllImport("libdec", EntryPoint="decimalFloorAndTrunc")]
1142         private static extern void decimalFloorAndTrunc(ref Decimal val, 
1143             int floorFlag);
1144         
1145         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1146         [DllImport("libdec", EntryPoint="decimalRound")]
1147         private static extern void decimalRound(ref Decimal val, int decimals);
1148
1149         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1150         [DllImport("libdec", EntryPoint="decimalMult")]
1151         private static extern int decimalMult(ref Decimal pd1, ref Decimal pd2);
1152         
1153         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1154         [DllImport("libdec", EntryPoint="decimalDiv")]
1155         private static extern int decimalDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1156
1157         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1158         [DllImport("libdec", EntryPoint="decimalIntDiv")]
1159         private static extern int decimalIntDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1160
1161         //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1162         [DllImport("libdec", EntryPoint="decimalCompare")]
1163         private static extern int decimalCompare(ref Decimal d1, ref Decimal d2);
1164
1165 #endif
1166     }
1167 }
1168