(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / corlib / System / Decimal.cs
blobf96d78b7173df2d4103de2cd7e9fd1c9ec2a6af9
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
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.
36 using System;
37 using System.Globalization;
38 using System.Text;
39 using System.Runtime.CompilerServices;
40 #if MSTEST
41 using System.Runtime.InteropServices;
42 #endif
45 namespace System
47 /// <summary>
48 /// Represents a floating-point decimal data type with up to 29 significant
49 /// digits, suitable for financial and commercial calculations
50 /// </summary>
51 [Serializable]
52 public struct Decimal: IFormattable, IConvertible,
53 #if NET_2_0
54 IComparable, IComparable<Decimal>
55 #else
56 IComparable
57 #endif
59 // LAMESPEC: the attributes aren't mentioned, but show up in CorCompare
60 // Unfortunately, corcompare starts throwing security exceptions when
61 // these attributes are present...
63 [DecimalConstantAttribute(0, 1, unchecked((uint)-1), unchecked((uint)-1), unchecked((uint)-1))]
64 public static readonly Decimal MinValue = new Decimal(-1, -1, -1, true, 0);
65 [DecimalConstantAttribute(0, 0, unchecked((uint)-1), unchecked((uint)-1), unchecked((uint)-1))]
66 public static readonly Decimal MaxValue = new Decimal(-1, -1, -1, false, 0);
67 [DecimalConstantAttribute(0, 1, 0, 0, 1)]
68 public static readonly Decimal MinusOne = new Decimal(1, 0, 0, true, 0);
69 [DecimalConstantAttribute(0, 0, 0, 0, 1)]
70 public static readonly Decimal One = new Decimal(1, 0, 0, false, 0);
71 [DecimalConstantAttribute(0, 0, 0, 0, 0)]
72 public static readonly Decimal Zero = new Decimal(0, 0, 0, false, 0);
74 private static readonly Decimal MaxValueDiv10 = MaxValue / 10;
76 // maximal decimal value as double
77 private static readonly double dDecMaxValue = 7.922816251426433759354395033e28;
78 // epsilon decimal value as double
79 private static readonly double dDecEpsilon = 0.5e-28; // == 0.5 * 1 / 10^28
81 // some constants
82 private const int DECIMAL_DIVIDE_BY_ZERO = 5;
83 private const uint MAX_SCALE = 28;
84 private const int iMAX_SCALE = 28;
85 private const uint SIGN_FLAG = 0x80000000;
86 private const uint SCALE_MASK = 0x00FF0000;
87 private const int SCALE_SHIFT = 16;
88 private const uint RESERVED_SS32_BITS = 0x7F00FFFF;
90 // internal representation of decimal
91 private uint ss32;
92 private uint hi32;
93 private uint lo32;
94 private uint mid32;
96 public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
98 unchecked
100 lo32 = (uint) lo;
101 mid32 = (uint) mid;
102 hi32 = (uint) hi;
104 if (scale > MAX_SCALE)
106 throw new ArgumentOutOfRangeException (Locale.GetText ("scale must be between 0 and 28"));
109 ss32 = scale;
110 ss32 <<= SCALE_SHIFT;
111 if (isNegative) ss32 |= SIGN_FLAG;
115 public Decimal(int val)
117 unchecked
119 hi32 = mid32 = 0;
120 if (val < 0)
122 ss32 = SIGN_FLAG;
123 lo32 = ((uint)~val) + 1;
125 else
127 ss32 = 0;
128 lo32 = (uint) val;
133 [CLSCompliant(false)]
134 public Decimal(uint val)
136 lo32 = val;
137 ss32 = hi32 = mid32 = 0;
140 public Decimal(long val)
142 unchecked
144 hi32 = 0;
145 if (val < 0)
147 ss32 = SIGN_FLAG;
148 ulong u = ((ulong)~val) + 1;
149 lo32 = (uint)u;
150 mid32 = (uint)(u >> 32);
152 else
154 ss32 = 0;
155 ulong u = (ulong)val;
156 lo32 = (uint)u;
157 mid32 = (uint)(u >> 32);
162 [CLSCompliant(false)]
163 public Decimal(ulong uval)
165 unchecked
167 ss32 = hi32 = 0;
168 lo32 = (uint)uval;
169 mid32 = (uint)(uval >> 32);
173 public Decimal (float val)
175 if (val > (float)Decimal.MaxValue || val < (float)Decimal.MinValue) {
176 throw new OverflowException (Locale.GetText (
177 "Value is greater than Decimal.MaxValue or less than Decimal.MinValue"));
179 // we must respect the precision (double2decimal doesn't)
180 Decimal d = Decimal.Parse (val.ToString (CultureInfo.InvariantCulture),
181 NumberStyles.Float, CultureInfo.InvariantCulture);
182 ss32 = d.ss32;
183 hi32 = d.hi32;
184 lo32 = d.lo32;
185 mid32 = d.mid32;
188 public Decimal (double val)
190 if (val > (double)Decimal.MaxValue || val < (double)Decimal.MinValue) {
191 throw new OverflowException (Locale.GetText (
192 "Value is greater than Decimal.MaxValue or less than Decimal.MinValue"));
194 // we must respect the precision (double2decimal doesn't)
195 Decimal d = Decimal.Parse (val.ToString (CultureInfo.InvariantCulture),
196 NumberStyles.Float, CultureInfo.InvariantCulture);
197 ss32 = d.ss32;
198 hi32 = d.hi32;
199 lo32 = d.lo32;
200 mid32 = d.mid32;
203 public Decimal(int[] bits)
205 if (bits == null)
207 throw new ArgumentNullException(Locale.GetText ("Bits is a null reference"));
210 if (bits.GetLength(0) != 4)
212 throw new ArgumentException(Locale.GetText ("bits does not contain four values"));
215 unchecked {
216 lo32 = (uint) bits[0];
217 mid32 = (uint) bits[1];
218 hi32 = (uint) bits[2];
219 ss32 = (uint) bits[3];
220 byte scale = (byte)(ss32 >> SCALE_SHIFT);
221 if (scale > MAX_SCALE || (ss32 & RESERVED_SS32_BITS) != 0)
223 throw new ArgumentException(Locale.GetText ("Invalid bits[3]"));
228 public static decimal FromOACurrency(long cy)
230 return (decimal)cy / (decimal)10000;
233 public static int[] GetBits(Decimal d)
235 unchecked
237 return new int[] { (int)d.lo32, (int)d.mid32, (int)d.hi32,
238 (int)d.ss32 };
242 public static Decimal Negate(Decimal d)
244 d.ss32 ^= SIGN_FLAG;
245 return d;
249 public static Decimal Add(Decimal d1, Decimal d2)
251 if (decimalIncr(ref d1, ref d2) == 0)
252 return d1;
253 else
254 throw new OverflowException(Locale.GetText ("Overflow on adding decimal number"));
257 public static Decimal Subtract(Decimal d1, Decimal d2)
259 d2.ss32 ^= SIGN_FLAG;
260 int result = decimalIncr(ref d1, ref d2);
261 if (result == 0)
262 return d1;
263 else
264 throw new OverflowException(Locale.GetText ("Overflow on subtracting decimal numbers ("+result+")"));
267 public override int GetHashCode ()
269 return (int) (ss32 ^ hi32 ^ lo32 ^ mid32);
272 public static Decimal operator +(Decimal d1, Decimal d2)
274 return Add(d1, d2);
277 public static Decimal operator --(Decimal d)
279 return Add(d, MinusOne);
282 public static Decimal operator ++(Decimal d)
284 return Add(d, One);
287 public static Decimal operator -(Decimal d1, Decimal d2)
289 return Subtract(d1, d2);
292 public static Decimal operator -(Decimal d)
294 return Negate(d);
297 public static Decimal operator +(Decimal d)
299 return d;
302 public static Decimal operator *(Decimal d1, Decimal d2)
304 return Multiply(d1, d2);
307 public static Decimal operator /(Decimal d1, Decimal d2)
309 return Divide(d1, d2);
312 public static Decimal operator %(Decimal d1, Decimal d2)
314 return Remainder(d1, d2);
317 private static ulong u64 (Decimal value)
319 ulong result;
321 decimalFloorAndTrunc (ref value, 0);
322 if (decimal2UInt64 (ref value, out result) != 0) {
323 throw new System.OverflowException ();
325 return result;
328 private static long s64 (Decimal value)
330 long result;
332 decimalFloorAndTrunc (ref value, 0);
333 if (decimal2Int64 (ref value, out result) != 0) {
334 throw new System.OverflowException ();
336 return result;
339 public static explicit operator byte (Decimal val)
341 ulong result = u64 (val);
342 return checked ((byte) result);
345 [CLSCompliant (false)]
346 public static explicit operator sbyte (Decimal val)
348 long result = s64 (val);
349 return checked ((sbyte) result);
352 public static explicit operator char (Decimal val)
354 ulong result = u64 (val);
355 return checked ((char) result);
358 public static explicit operator short (Decimal val)
360 long result = s64 (val);
361 return checked ((short) result);
364 [CLSCompliant (false)]
365 public static explicit operator ushort (Decimal val)
367 ulong result = u64 (val);
368 return checked ((ushort) result);
371 public static explicit operator int (Decimal val)
373 long result = s64 (val);
374 return checked ((int) result);
377 [CLSCompliant(false)]
378 public static explicit operator uint (Decimal val)
380 ulong result = u64 (val);
381 return checked ((uint) result);
384 public static explicit operator long (Decimal val)
386 return s64 (val);
389 [CLSCompliant(false)]
390 public static explicit operator ulong (Decimal val)
392 return u64 (val);
395 public static implicit operator Decimal(byte val)
397 return new Decimal(val);
400 [CLSCompliant(false)]
401 public static implicit operator Decimal(sbyte val)
403 return new Decimal(val);
406 public static implicit operator Decimal(short val)
408 return new Decimal(val);
411 [CLSCompliant(false)]
412 public static implicit operator Decimal(ushort val)
414 return new Decimal(val);
417 public static implicit operator Decimal(char val)
419 return new Decimal(val);
422 public static implicit operator Decimal(int val)
424 return new Decimal(val);
427 [CLSCompliant(false)]
428 public static implicit operator Decimal(uint val)
430 return new Decimal(val);
433 public static implicit operator Decimal(long val)
435 return new Decimal(val);
438 [CLSCompliant(false)]
439 public static implicit operator Decimal(ulong val)
441 return new Decimal(val);
444 public static explicit operator Decimal(float val)
446 return new Decimal(val);
449 public static explicit operator Decimal(double val)
451 return new Decimal(val);
454 public static explicit operator float(Decimal val)
456 return (float) (double) val;
459 public static explicit operator double(Decimal val)
461 return decimal2double(ref val);
465 public static bool operator !=(Decimal d1, Decimal d2)
467 return !Equals(d1, d2);
470 public static bool operator ==(Decimal d1, Decimal d2)
472 return Equals(d1, d2);
475 public static bool operator >(Decimal d1, Decimal d2)
477 return decimalCompare(ref d1, ref d2) > 0;
480 public static bool operator >=(Decimal d1, Decimal d2)
482 return decimalCompare(ref d1, ref d2) >= 0;
485 public static bool operator <(Decimal d1, Decimal d2)
487 return decimalCompare(ref d1, ref d2) < 0;
490 public static bool operator <=(Decimal d1, Decimal d2)
492 return decimalCompare(ref d1, ref d2) <= 0;
495 public static bool Equals(Decimal d1, Decimal d2)
497 return decimalCompare(ref d1, ref d2) == 0;
500 public override bool Equals(object o)
502 if (!(o is Decimal))
503 return false;
505 return Equals((Decimal) o, this);
508 // avoid unmanaged call
509 private bool IsZero ()
511 return ((hi32 == 0) && (lo32 == 0) && (mid32 == 0));
514 // avoid unmanaged call
515 private bool IsNegative ()
517 return ((ss32 & 0x80000000) == 0x80000000);
520 public static Decimal Floor(Decimal d)
522 decimalFloorAndTrunc(ref d, 1);
523 return d;
526 public static Decimal Truncate(Decimal d)
528 decimalFloorAndTrunc(ref d, 0);
529 return d;
532 public static Decimal Round (Decimal d, int decimals)
534 if (decimals < 0 || decimals > 28) {
535 throw new ArgumentOutOfRangeException ("decimals", "[0,28]");
538 bool negative = d.IsNegative ();
539 if (negative)
540 d.ss32 ^= SIGN_FLAG;
542 // Moved from Math.cs because it's easier to fix the "sign"
543 // issue here :( as the logic is OK only for positive numbers
544 decimal p = (decimal) Math.Pow (10, decimals);
545 decimal int_part = Decimal.Floor (d);
546 decimal dec_part = d - int_part;
547 dec_part *= 10000000000000000000000000000M;
548 dec_part = Decimal.Floor(dec_part);
549 dec_part /= (10000000000000000000000000000M / p);
550 dec_part = Math.Round (dec_part);
551 dec_part /= p;
552 decimal result = int_part + dec_part;
554 // that fixes the precision/scale (which we must keep for output)
555 // (moved and adapted from System.Data.SqlTypes.SqlMoney)
556 long scaleDiff = decimals - ((result.ss32 & 0x7FFF0000) >> 16);
557 // integrify
558 if (scaleDiff > 0) {
559 // note: here we always work with positive numbers
560 while (scaleDiff > 0) {
561 if (result > MaxValueDiv10)
562 break;
563 result *= 10;
564 scaleDiff--;
567 else if (scaleDiff < 0) {
568 while (scaleDiff < 0) {
569 result /= 10;
570 scaleDiff++;
573 result.ss32 = (uint)((decimals - scaleDiff) << SCALE_SHIFT);
575 if (negative)
576 result.ss32 ^= SIGN_FLAG;
577 return result;
580 public static Decimal Multiply (Decimal d1, Decimal d2)
582 if (d1.IsZero () || d2.IsZero ())
583 return Decimal.Zero;
585 if (decimalMult (ref d1, ref d2) != 0)
586 throw new OverflowException ();
587 return d1;
590 public static Decimal Divide (Decimal d1, Decimal d2)
592 if (d2.IsZero ())
593 throw new DivideByZeroException ();
594 if (d2.IsZero ())
595 return Decimal.Zero;
596 if (d1 == d2)
597 return Decimal.One;
599 d1.ss32 ^= SIGN_FLAG;
600 if (d1 == d2)
601 return Decimal.MinusOne;
602 d1.ss32 ^= SIGN_FLAG;
604 Decimal result;
605 if (decimalDiv (out result, ref d1, ref d2) != 0)
606 throw new OverflowException ();
608 return result;
611 public static Decimal Remainder (Decimal d1, Decimal d2)
613 if (d2.IsZero ())
614 throw new DivideByZeroException ();
615 if (d1.IsZero ())
616 return Decimal.Zero;
618 bool negative = d1.IsNegative ();
619 if (negative)
620 d1.ss32 ^= SIGN_FLAG;
621 if (d2.IsNegative ())
622 d2.ss32 ^= SIGN_FLAG;
624 Decimal result;
625 if (d1 == d2) {
626 return Decimal.Zero;
628 else if (d2 > d1) {
629 result = d1;
631 else {
632 if (decimalIntDiv (out result, ref d1, ref d2) != 0)
633 throw new OverflowException ();
635 // FIXME: not really performant here
636 result = d1 - result * d2;
639 if (negative)
640 result.ss32 ^= SIGN_FLAG;
641 return result;
644 public static int Compare(Decimal d1, Decimal d2)
646 return decimalCompare(ref d1, ref d2);
649 public int CompareTo(object val)
651 if (val == null)
652 return 1;
654 if (!(val is Decimal))
655 throw new ArgumentException (Locale.GetText ("Value is not a System.Decimal"));
657 Decimal d2 = (Decimal)val;
658 return decimalCompare(ref this, ref d2);
661 #if NET_2_0
662 public int CompareTo(Decimal value)
664 return decimalCompare(ref this, ref value);
667 public bool Equals(Decimal value)
669 return Equals(value, this);
671 #endif
673 public static Decimal Parse(string s)
675 return Parse(s, NumberStyles.Number, null);
678 public static Decimal Parse(string s, NumberStyles style)
680 return Parse(s, style, null);
683 public static Decimal Parse(string s, IFormatProvider provider)
685 return Parse(s, NumberStyles.Number, provider);
688 private static string stripStyles(string s, NumberStyles style, NumberFormatInfo nfi,
689 out int decPos, out bool isNegative, out bool expFlag, out int exp)
691 string invalidChar = Locale.GetText ("Invalid character at position ");
692 string invalidExponent = Locale.GetText ("Invalid exponent");
693 isNegative = false;
694 expFlag = false;
695 exp = 0;
696 decPos = -1;
698 bool hasSign = false;
699 bool hasOpeningParentheses = false;
700 bool hasDecimalPoint = false;
701 bool allowedLeadingWhiteSpace = ((style & NumberStyles.AllowLeadingWhite) != 0);
702 bool allowedTrailingWhiteSpace = ((style & NumberStyles.AllowTrailingWhite) != 0);
703 bool allowedLeadingSign = ((style & NumberStyles.AllowLeadingSign) != 0);
704 bool allowedTrailingSign = ((style & NumberStyles.AllowTrailingSign) != 0);
705 bool allowedParentheses = ((style & NumberStyles.AllowParentheses) != 0);
706 bool allowedThousands = ((style & NumberStyles.AllowThousands) != 0);
707 bool allowedDecimalPoint = ((style & NumberStyles.AllowDecimalPoint) != 0);
708 bool allowedExponent = ((style & NumberStyles.AllowExponent) != 0);
710 /* get rid of currency symbol */
711 bool hasCurrency = false;
712 if ((style & NumberStyles.AllowCurrencySymbol) != 0)
714 int index = s.IndexOf(nfi.CurrencySymbol);
715 if (index >= 0)
717 s = s.Remove(index, nfi.CurrencySymbol.Length);
718 hasCurrency = true;
722 string decimalSep = (hasCurrency) ? nfi.CurrencyDecimalSeparator : nfi.NumberDecimalSeparator;
723 string groupSep = (hasCurrency) ? nfi.CurrencyGroupSeparator : nfi.NumberGroupSeparator;
725 int pos = 0;
726 int len = s.Length;
728 StringBuilder sb = new StringBuilder(len);
730 // leading
731 while (pos < len)
733 char ch = s[pos];
734 if (Char.IsDigit(ch))
736 break; // end of leading
738 else if (allowedLeadingWhiteSpace && Char.IsWhiteSpace(ch))
740 pos++;
742 else if (allowedParentheses && ch == '(' && !hasSign && !hasOpeningParentheses)
744 hasOpeningParentheses = true;
745 hasSign = true;
746 isNegative = true;
747 pos++;
749 else if (allowedLeadingSign && ch == nfi.NegativeSign[0] && !hasSign)
751 int slen = nfi.NegativeSign.Length;
752 if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos)
754 hasSign = true;
755 isNegative = true;
756 pos += slen;
759 else if (allowedLeadingSign && ch == nfi.PositiveSign[0] && !hasSign)
761 int slen = nfi.PositiveSign.Length;
762 if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos)
764 hasSign = true;
765 pos += slen;
768 else if (allowedDecimalPoint && ch == decimalSep[0])
770 int slen = decimalSep.Length;
771 if (slen != 1 && s.IndexOf(decimalSep, pos, slen) != pos)
773 throw new FormatException(invalidChar + pos);
775 break;
777 else
779 throw new FormatException(invalidChar + pos);
783 if (pos == len)
784 throw new FormatException(Locale.GetText ("No digits found"));
786 // digits
787 while (pos < len)
789 char ch = s[pos];
790 if (Char.IsDigit(ch))
792 sb.Append(ch);
793 pos++;
795 else if (allowedThousands && ch == groupSep[0])
797 int slen = groupSep.Length;
798 if (slen != 1 && s.IndexOf(groupSep, pos, slen) != pos)
800 throw new FormatException(invalidChar + pos);
802 pos += slen;
804 else if (allowedDecimalPoint && ch == decimalSep[0] && !hasDecimalPoint)
806 int slen = decimalSep.Length;
807 if (slen == 1 || s.IndexOf(decimalSep, pos, slen) == pos)
809 decPos = sb.Length;
810 hasDecimalPoint = true;
811 pos += slen;
814 else
816 break;
820 // exponent
821 if (pos < len)
823 char ch = s[pos];
824 if (allowedExponent && Char.ToUpperInvariant (ch) == 'E')
826 expFlag = true;
827 pos++; if (pos >= len) throw new FormatException(invalidExponent);
828 ch = s[pos];
829 bool isNegativeExp = false;
830 if (ch == nfi.PositiveSign[0])
832 int slen = nfi.PositiveSign.Length;
833 if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos)
835 pos += slen; if (pos >= len) throw new FormatException(invalidExponent);
838 else if (ch == nfi.NegativeSign[0])
840 int slen = nfi.NegativeSign.Length;
841 if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos)
843 pos += slen; if (pos >= len) throw new FormatException(invalidExponent);
844 isNegativeExp = true;
847 ch = s[pos];
848 if (!Char.IsDigit(ch)) throw new FormatException(invalidExponent);
849 exp = ch - '0';
850 pos++;
851 while (pos < len && Char.IsDigit(s[pos]))
853 exp *= 10;
854 exp += s[pos] - '0';
855 pos++;
857 if (isNegativeExp) exp *= -1;
861 // trailing
862 while (pos < len)
864 char ch = s[pos];
865 if (allowedTrailingWhiteSpace && Char.IsWhiteSpace(ch))
867 pos++;
869 else if (allowedParentheses && ch == ')' && hasOpeningParentheses)
871 hasOpeningParentheses = false;
872 pos++;
874 else if (allowedTrailingSign && ch == nfi.NegativeSign[0] && !hasSign)
876 int slen = nfi.NegativeSign.Length;
877 if (slen == 1 || s.IndexOf(nfi.NegativeSign, pos, slen) == pos)
879 hasSign = true;
880 isNegative = true;
881 pos += slen;
884 else if (allowedTrailingSign && ch == nfi.PositiveSign[0] && !hasSign)
886 int slen = nfi.PositiveSign.Length;
887 if (slen == 1 || s.IndexOf(nfi.PositiveSign, pos, slen) == pos)
889 hasSign = true;
890 pos += slen;
893 else
895 throw new FormatException(invalidChar + pos);
899 if (hasOpeningParentheses) throw new FormatException (
900 Locale.GetText ("Closing Parentheses not found"));
902 if (!hasDecimalPoint) decPos = sb.Length;
904 return sb.ToString();
907 public static Decimal Parse (string s, NumberStyles style, IFormatProvider provider)
909 if (s == null)
910 throw new ArgumentNullException ("s");
912 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
914 int iDecPos, exp;
915 bool isNegative, expFlag;
916 s = stripStyles(s, style, nfi, out iDecPos, out isNegative, out expFlag, out exp);
918 if (iDecPos < 0)
919 throw new Exception (Locale.GetText ("Error in System.Decimal.Parse"));
921 // first we remove leading 0
922 int len = s.Length;
923 int i = 0;
924 while ((i < iDecPos) && (s [i] == '0'))
925 i++;
926 if ((i > 1) && (len > 1)) {
927 s = s.Substring (i, len - i);
928 iDecPos -= i;
931 // first 0. may not be here but is part of the maximum length
932 int max = ((iDecPos == 0) ? 27 : 28);
933 len = s.Length;
934 if (len >= max + 1) {
935 // number lower than MaxValue (base-less) can have better precision
936 if (String.Compare (s, 0, "79228162514264337593543950335", 0, max + 1,
937 false, CultureInfo.InvariantCulture) <= 0) {
938 max++;
942 // then we trunc the string
943 if ((len > max) && (iDecPos < len)) {
944 int round = (s [max] - '0');
945 s = s.Substring (0, max);
947 bool addone = false;
948 if (round > 5) {
949 addone = true;
951 else if (round == 5) {
952 if (isNegative) {
953 addone = true;
955 else {
956 // banker rounding applies :(
957 int previous = (s [max - 1] - '0');
958 addone = ((previous & 0x01) == 0x01);
961 if (addone) {
962 char[] array = s.ToCharArray ();
963 int p = max - 1;
964 while (p >= 0) {
965 int b = (array [p] - '0');
966 if (array [p] != '9') {
967 array [p] = (char)(b + '1');
968 break;
970 else {
971 array [p--] = '0';
974 if ((p == -1) && (array [0] == '0')) {
975 iDecPos++;
976 s = "1".PadRight (iDecPos, '0');
978 else
979 s = new String (array);
983 Decimal result;
984 // always work in positive (rounding issues)
985 if (string2decimal (out result, s, (uint)iDecPos, 0) != 0)
986 throw new OverflowException ();
988 if (expFlag) {
989 if (decimalSetExponent (ref result, exp) != 0)
990 throw new OverflowException ();
993 if (isNegative)
994 result.ss32 ^= SIGN_FLAG;
995 return result;
998 public TypeCode GetTypeCode ()
1000 return TypeCode.Decimal;
1003 public static byte ToByte (decimal value)
1005 if (value > Byte.MaxValue || value < Byte.MinValue)
1006 throw new OverflowException (Locale.GetText (
1007 "Value is greater than Byte.MaxValue or less than Byte.MinValue"));
1009 // return truncated value
1010 return (byte)(Decimal.Truncate (value));
1013 public static double ToDouble (decimal value)
1015 return Convert.ToDouble (value);
1018 public static short ToInt16 (decimal value)
1020 if (value > Int16.MaxValue || value < Int16.MinValue)
1021 throw new OverflowException (Locale.GetText (
1022 "Value is greater than Int16.MaxValue or less than Int16.MinValue"));
1024 // return truncated value
1025 return (Int16)(Decimal.Truncate (value));
1028 public static int ToInt32 (decimal value)
1030 if (value > Int32.MaxValue || value < Int32.MinValue)
1031 throw new OverflowException (Locale.GetText (
1032 "Value is greater than Int32.MaxValue or less than Int32.MinValue"));
1034 // return truncated value
1035 return (Int32)(Decimal.Truncate (value));
1038 public static long ToInt64 (decimal value)
1040 if (value > Int64.MaxValue || value < Int64.MinValue)
1041 throw new OverflowException (Locale.GetText (
1042 "Value is greater than Int64.MaxValue or less than Int64.MinValue"));
1044 // return truncated value
1045 return (Int64)(Decimal.Truncate (value));
1048 public static long ToOACurrency (decimal value)
1050 return (long) (value * 10000);
1053 [CLSCompliant(false)]
1054 public static sbyte ToSByte (decimal value)
1056 if (value > SByte.MaxValue || value < SByte.MinValue)
1057 throw new OverflowException (Locale.GetText (
1058 "Value is greater than SByte.MaxValue or less than SByte.MinValue"));
1060 // return truncated value
1061 return (SByte)(Decimal.Truncate (value));
1064 public static float ToSingle (decimal value)
1066 return Convert.ToSingle (value);
1069 [CLSCompliant(false)]
1070 public static ushort ToUInt16 (decimal value)
1072 if (value > UInt16.MaxValue || value < UInt16.MinValue)
1073 throw new OverflowException (Locale.GetText (
1074 "Value is greater than UInt16.MaxValue or less than UInt16.MinValue"));
1076 // return truncated value
1077 return (UInt16)(Decimal.Truncate (value));
1080 [CLSCompliant(false)]
1081 public static uint ToUInt32 (decimal value)
1083 if (value > UInt32.MaxValue || value < UInt32.MinValue)
1084 throw new OverflowException (Locale.GetText (
1085 "Value is greater than UInt32.MaxValue or less than UInt32.MinValue"));
1087 // return truncated value
1088 return (UInt32)(Decimal.Truncate (value));
1091 [CLSCompliant(false)]
1092 public static ulong ToUInt64 (decimal value)
1094 if (value > UInt64.MaxValue || value < UInt64.MinValue)
1095 throw new OverflowException (Locale.GetText (
1096 "Value is greater than UInt64.MaxValue or less than UInt64.MinValue"));
1098 // return truncated value
1099 return (UInt64)(Decimal.Truncate (value));
1102 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
1104 return Convert.ToType (this, conversionType, provider);
1107 bool IConvertible.ToBoolean (IFormatProvider provider)
1109 return Convert.ToBoolean (this);
1112 byte IConvertible.ToByte (IFormatProvider provider)
1114 return Convert.ToByte (this);
1117 char IConvertible.ToChar (IFormatProvider provider)
1119 throw new InvalidCastException ();
1122 DateTime IConvertible.ToDateTime (IFormatProvider provider)
1124 throw new InvalidCastException ();
1127 decimal IConvertible.ToDecimal (IFormatProvider provider)
1129 return this;
1132 double IConvertible.ToDouble (IFormatProvider provider)
1134 return Convert.ToDouble (this);
1137 short IConvertible.ToInt16 (IFormatProvider provider)
1139 return Convert.ToInt16 (this);
1142 int IConvertible.ToInt32 (IFormatProvider provider)
1144 return Convert.ToInt32 (this);
1147 long IConvertible.ToInt64 (IFormatProvider provider)
1149 return Convert.ToInt64 (this);
1152 sbyte IConvertible.ToSByte (IFormatProvider provider)
1154 return Convert.ToSByte (this);
1157 float IConvertible.ToSingle (IFormatProvider provider)
1159 return Convert.ToSingle (this);
1162 ushort IConvertible.ToUInt16 (IFormatProvider provider)
1164 return Convert.ToUInt16 (this);
1167 uint IConvertible.ToUInt32 (IFormatProvider provider)
1169 return Convert.ToUInt32 (this);
1172 ulong IConvertible.ToUInt64 (IFormatProvider provider)
1174 return Convert.ToUInt64 (this);
1177 public string ToString (string format, IFormatProvider provider)
1179 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
1181 // use "G" for null or empty string
1182 if ((format == null) || (format.Length == 0))
1183 format = "G";
1185 return DecimalFormatter.NumberToString (format, nfi, this);
1188 public override string ToString()
1190 return ToString("G", null);
1193 public string ToString(string format)
1195 return ToString(format, null);
1198 public string ToString(IFormatProvider provider)
1200 return ToString("G", provider);
1203 #if !MSTEST
1204 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1205 private static extern int decimal2UInt64(ref Decimal val,
1206 out ulong result);
1208 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1209 private static extern int decimal2Int64(ref Decimal val,
1210 out long result);
1212 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1213 private static extern int double2decimal(out Decimal erg,
1214 double val, int digits);
1216 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1217 private static extern int decimalIncr(ref Decimal d1, ref Decimal d2);
1219 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1220 internal static extern int decimal2string(ref Decimal val,
1221 int digits, int decimals, char[] bufDigits, int bufSize, out int decPos, out int sign);
1223 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1224 internal static extern int string2decimal(out Decimal val, String sDigits, uint decPos, int sign);
1226 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1227 internal static extern int decimalSetExponent(ref Decimal val, int exp);
1229 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1230 private static extern double decimal2double(ref Decimal val);
1232 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1233 private static extern void decimalFloorAndTrunc(ref Decimal val,
1234 int floorFlag);
1236 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1237 private static extern void decimalRound(ref Decimal val, int decimals);
1239 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1240 private static extern int decimalMult(ref Decimal pd1, ref Decimal pd2);
1242 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1243 private static extern int decimalDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1246 private static extern int decimalIntDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1248 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1249 private static extern int decimalCompare(ref Decimal d1, ref Decimal d2);
1250 #else
1251 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1252 [DllImport("libdec", EntryPoint="decimal2UInt64")]
1253 private static extern int decimal2UInt64(ref Decimal val,
1254 out ulong result);
1256 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1257 [DllImport("libdec", EntryPoint="decimal2Int64")]
1258 private static extern int decimal2Int64(ref Decimal val,
1259 out long result);
1261 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1262 [DllImport("libdec", EntryPoint="double2decimal")]
1263 private static extern int double2decimal(out Decimal erg,
1264 double val, int digits);
1266 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1267 [DllImport("libdec", EntryPoint="decimalIncr")]
1268 private static extern int decimalIncr(ref Decimal d1, ref Decimal d2);
1270 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1271 [DllImport("libdec", EntryPoint="decimal2string")]
1272 internal static extern int decimal2string(ref Decimal val,
1273 int digits, int decimals,
1274 [MarshalAs(UnmanagedType.LPWStr)]StringBuilder bufDigits,
1275 int bufSize, out int decPos, out int sign);
1277 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1278 [DllImport("libdec", EntryPoint="string2decimal")]
1279 internal static extern int string2decimal(out Decimal val,
1280 [MarshalAs(UnmanagedType.LPWStr)]String sDigits,
1281 uint decPos, int sign);
1283 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1284 [DllImport("libdec", EntryPoint="decimalSetExponent")]
1285 internal static extern int decimalSetExponent(ref Decimal val, int exp);
1287 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1288 [DllImport("libdec", EntryPoint="decimal2double")]
1289 private static extern double decimal2double(ref Decimal val);
1291 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1292 [DllImport("libdec", EntryPoint="decimalFloorAndTrunc")]
1293 private static extern void decimalFloorAndTrunc(ref Decimal val,
1294 int floorFlag);
1296 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1297 [DllImport("libdec", EntryPoint="decimalRound")]
1298 private static extern void decimalRound(ref Decimal val, int decimals);
1300 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1301 [DllImport("libdec", EntryPoint="decimalMult")]
1302 private static extern int decimalMult(ref Decimal pd1, ref Decimal pd2);
1304 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1305 [DllImport("libdec", EntryPoint="decimalDiv")]
1306 private static extern int decimalDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1308 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1309 [DllImport("libdec", EntryPoint="decimalIntDiv")]
1310 private static extern int decimalIntDiv(out Decimal pc, ref Decimal pa, ref Decimal pb);
1312 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1313 [DllImport("libdec", EntryPoint="decimalCompare")]
1314 private static extern int decimalCompare(ref Decimal d1, ref Decimal d2);
1316 #endif