4 // Represents a floating-point decimal data type with up to 29
5 // significant digits, suitable for financial and commercial calculations.
8 // Martin Weindel (martin.weindel@t-online.de)
9 // Marek Safar (marek.safar@gmail.com)
11 // (C) 2001 Martin Weindel
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Globalization;
38 using System.Runtime.CompilerServices;
39 using System.Runtime.ConstrainedExecution;
40 using System.Runtime.Serialization;
43 using System.Runtime.InteropServices;
50 /// Represents a floating-point decimal data type with up to 29 significant
51 /// digits, suitable for financial and commercial calculations
54 [System.Runtime.InteropServices.ComVisible (true)]
55 public struct Decimal: IFormattable, IConvertible, IComparable, IComparable<Decimal>, IEquatable <Decimal>
57 , IDeserializationCallback
60 public const decimal MinValue = -79228162514264337593543950335m;
61 public const decimal MaxValue = 79228162514264337593543950335m;
63 public const decimal MinusOne = -1;
64 public const decimal One = 1;
65 public const decimal Zero = 0;
67 private static readonly Decimal MaxValueDiv10 = MaxValue / 10;
70 private const uint MAX_SCALE = 28;
71 private const uint SIGN_FLAG = 0x80000000;
72 private const int SCALE_SHIFT = 16;
73 private const uint RESERVED_SS32_BITS = 0x7F00FFFF;
75 // internal representation of decimal
81 public Decimal (int lo, int mid, int hi, bool isNegative, byte scale)
86 this.mid = (uint) mid;
89 if (scale > MAX_SCALE)
90 throw new ArgumentOutOfRangeException (Locale.GetText ("scale must be between 0 and 28"));
93 flags <<= SCALE_SHIFT;
94 if (isNegative) flags |= SIGN_FLAG;
98 public Decimal (int value)
106 lo = ((uint)~value) + 1;
116 [CLSCompliant(false)]
117 public Decimal (uint value)
120 flags = hi = mid = 0;
123 public Decimal (long value)
131 ulong u = ((ulong)~value) + 1;
133 mid = (uint)(u >> 32);
138 ulong u = (ulong)value;
140 mid = (uint)(u >> 32);
145 [CLSCompliant(false)]
146 public Decimal (ulong value)
152 mid = (uint)(value >> 32);
156 public Decimal (float value)
160 // We cant use the double2decimal method
161 // because it incorrectly turns the floating point
162 // value 1.23456789E-25F which should be:
163 // 0.0000000000000000000000001235
164 // into the incorrect:
165 // 0.0000000000000000000000001234
167 // The code currently parses the double value 0.6 as
170 // And we have a patch for that called (trim
171 if (double2decimal (out this, value, 7) != 0)
172 throw new OverflowException ();
174 if (value > (float)Decimal.MaxValue || value < (float)Decimal.MinValue ||
175 float.IsNaN (value) || float.IsNegativeInfinity (value) || float.IsPositiveInfinity (value)) {
176 throw new OverflowException (Locale.GetText (
177 "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
180 // we must respect the precision (double2decimal doesn't)
181 Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
182 NumberStyles.Float, CultureInfo.InvariantCulture);
190 public Decimal (double value)
194 // We cant use the double2decimal method
195 // because it incorrectly turns the floating point
196 // value 1.23456789E-25F which should be:
197 // 0.0000000000000000000000001235
198 // into the incorrect:
199 // 0.0000000000000000000000001234
201 // The code currently parses the double value 0.6 as
204 // And we have a patch for that called (trim
205 if (double2decimal (out this, value, 15) != 0)
206 throw new OverflowException ();
208 if (value > (double)Decimal.MaxValue || value < (double)Decimal.MinValue ||
209 double.IsNaN (value) || double.IsNegativeInfinity (value) || double.IsPositiveInfinity (value)) {
210 throw new OverflowException (Locale.GetText (
211 "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
213 // we must respect the precision (double2decimal doesn't)
214 Decimal d = Decimal.Parse (value.ToString (CultureInfo.InvariantCulture),
215 NumberStyles.Float, CultureInfo.InvariantCulture);
223 public Decimal (int[] bits)
227 throw new ArgumentNullException (Locale.GetText ("bits is a null reference"));
230 if (bits.Length != 4)
232 throw new ArgumentException (Locale.GetText ("bits does not contain four values"));
237 mid = (uint) bits[1];
239 flags = (uint) bits[3];
240 byte scale = (byte)(flags >> SCALE_SHIFT);
241 if (scale > MAX_SCALE || (flags & RESERVED_SS32_BITS) != 0)
243 throw new ArgumentException (Locale.GetText ("Invalid bits[3]"));
248 public static decimal FromOACurrency (long cy)
250 return (decimal)cy / (decimal)10000;
253 public static int[] GetBits (Decimal d)
257 return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags };
261 public static Decimal Negate (Decimal d)
263 d.flags ^= SIGN_FLAG;
267 public static Decimal Add (Decimal d1, Decimal d2)
269 if (decimalIncr (ref d1, ref d2) == 0)
272 throw new OverflowException (Locale.GetText ("Overflow on adding decimal number"));
275 public static Decimal Subtract (Decimal d1, Decimal d2)
277 d2.flags ^= SIGN_FLAG;
278 int result = decimalIncr (ref d1, ref d2);
282 throw new OverflowException (Locale.GetText ("Overflow on subtracting decimal numbers ("+result+")"));
285 public override int GetHashCode ()
287 return (int) (flags ^ hi ^ lo ^ mid);
290 public static Decimal operator + (Decimal d1, Decimal d2)
295 public static Decimal operator -- (Decimal d)
297 return Add(d, MinusOne);
300 public static Decimal operator ++ (Decimal d)
305 public static Decimal operator - (Decimal d1, Decimal d2)
307 return Subtract (d1, d2);
310 public static Decimal operator - (Decimal d)
315 public static Decimal operator + (Decimal d)
320 public static Decimal operator * (Decimal d1, Decimal d2)
322 return Multiply (d1, d2);
325 public static Decimal operator / (Decimal d1, Decimal d2)
327 return Divide (d1, d2);
330 public static Decimal operator % (Decimal d1, Decimal d2)
332 return Remainder (d1, d2);
335 private static ulong u64 (Decimal value)
339 decimalFloorAndTrunc (ref value, 0);
340 if (decimal2UInt64 (ref value, out result) != 0) {
341 throw new System.OverflowException ();
346 private static long s64 (Decimal value)
350 decimalFloorAndTrunc (ref value, 0);
351 if (decimal2Int64 (ref value, out result) != 0) {
352 throw new System.OverflowException ();
357 public static explicit operator byte (Decimal value)
359 ulong result = u64 (value);
360 return checked ((byte) result);
363 [CLSCompliant (false)]
364 public static explicit operator sbyte (Decimal value)
366 long result = s64 (value);
367 return checked ((sbyte) result);
370 public static explicit operator char (Decimal value)
372 ulong result = u64 (value);
373 return checked ((char) result);
376 public static explicit operator short (Decimal value)
378 long result = s64 (value);
379 return checked ((short) result);
382 [CLSCompliant (false)]
383 public static explicit operator ushort (Decimal value)
385 ulong result = u64 (value);
386 return checked ((ushort) result);
389 public static explicit operator int (Decimal value)
391 long result = s64 (value);
392 return checked ((int) result);
395 [CLSCompliant(false)]
396 public static explicit operator uint (Decimal value)
398 ulong result = u64 (value);
399 return checked ((uint) result);
402 public static explicit operator long (Decimal value)
407 [CLSCompliant(false)]
408 public static explicit operator ulong (Decimal value)
413 public static implicit operator Decimal (byte value)
415 return new Decimal (value);
418 [CLSCompliant(false)]
419 public static implicit operator Decimal (sbyte value)
421 return new Decimal (value);
424 public static implicit operator Decimal (short value)
426 return new Decimal (value);
429 [CLSCompliant(false)]
430 public static implicit operator Decimal (ushort value)
432 return new Decimal (value);
435 public static implicit operator Decimal (char value)
437 return new Decimal (value);
440 public static implicit operator Decimal (int value)
442 return new Decimal (value);
445 [CLSCompliant(false)]
446 public static implicit operator Decimal (uint value)
448 return new Decimal (value);
451 public static implicit operator Decimal (long value)
453 return new Decimal (value);
456 [CLSCompliant(false)]
457 public static implicit operator Decimal (ulong value)
459 return new Decimal (value);
462 public static explicit operator Decimal (float value)
464 return new Decimal (value);
467 public static explicit operator Decimal (double value)
469 return new Decimal (value);
472 public static explicit operator float (Decimal value)
474 return (float) (double) value;
477 public static explicit operator double (Decimal value)
479 return decimal2double (ref value);
483 public static bool operator != (Decimal d1, Decimal d2)
485 return !Equals (d1, d2);
488 public static bool operator == (Decimal d1, Decimal d2)
490 return Equals (d1, d2);
493 public static bool operator > (Decimal d1, Decimal d2)
495 return Compare (d1, d2) > 0;
498 public static bool operator >= (Decimal d1, Decimal d2)
500 return Compare (d1, d2) >= 0;
503 public static bool operator < (Decimal d1, Decimal d2)
505 return Compare (d1, d2) < 0;
508 public static bool operator <= (Decimal d1, Decimal d2)
510 return Compare (d1, d2) <= 0;
513 public static bool Equals (Decimal d1, Decimal d2)
515 return Compare (d1, d2) == 0;
518 public override bool Equals (object value)
520 if (!(value is Decimal))
523 return Equals ((Decimal) value, this);
526 // avoid unmanaged call
527 private bool IsZero ()
529 return ((hi == 0) && (lo == 0) && (mid == 0));
532 // avoid unmanaged call
533 private bool IsNegative ()
535 return ((flags & 0x80000000) == 0x80000000);
538 public static Decimal Floor (Decimal d)
540 decimalFloorAndTrunc (ref d, 1);
544 public static Decimal Truncate (Decimal d)
546 decimalFloorAndTrunc (ref d, 0);
550 public static Decimal Round (Decimal d, int decimals)
552 return Round (d, decimals, MidpointRounding.ToEven);
555 public static Decimal Round (Decimal d, int decimals, MidpointRounding mode)
557 if ((mode != MidpointRounding.ToEven) && (mode != MidpointRounding.AwayFromZero))
558 throw new ArgumentException ("The value '" + mode + "' is not valid for this usage of the type MidpointRounding.", "mode");
560 if (decimals < 0 || decimals > 28) {
561 throw new ArgumentOutOfRangeException ("decimals", "[0,28]");
564 bool negative = d.IsNegative ();
566 d.flags ^= SIGN_FLAG;
568 // Moved from Math.cs because it's easier to fix the "sign"
569 // issue here :( as the logic is OK only for positive numbers
570 decimal p = (decimal) Math.Pow (10, decimals);
571 decimal int_part = Decimal.Floor (d);
572 decimal dec_part = d - int_part;
573 dec_part *= 10000000000000000000000000000M;
574 dec_part = Decimal.Floor(dec_part);
575 dec_part /= (10000000000000000000000000000M / p);
576 dec_part = Math.Round (dec_part, mode);
578 decimal result = int_part + dec_part;
580 // that fixes the precision/scale (which we must keep for output)
581 // (moved and adapted from System.Data.SqlTypes.SqlMoney)
582 long scaleDiff = decimals - ((result.flags & 0x7FFF0000) >> 16);
585 // note: here we always work with positive numbers
586 while (scaleDiff > 0) {
587 if (result > MaxValueDiv10)
593 else if (scaleDiff < 0) {
594 while (scaleDiff < 0) {
599 result.flags = (uint)((decimals - scaleDiff) << SCALE_SHIFT);
602 result.flags ^= SIGN_FLAG;
606 public static Decimal Round (Decimal d)
608 return Math.Round (d);
611 public static Decimal Round (Decimal d, MidpointRounding mode)
613 return Math.Round (d, mode);
616 public static Decimal Multiply (Decimal d1, Decimal d2)
618 if (d1.IsZero () || d2.IsZero ())
621 if (decimalMult (ref d1, ref d2) != 0)
622 throw new OverflowException ();
626 public static Decimal Divide (Decimal d1, Decimal d2)
629 throw new DivideByZeroException ();
633 d1.flags ^= SIGN_FLAG;
634 d1.flags ^= SIGN_FLAG;
637 if (decimalDiv (out result, ref d1, ref d2) != 0)
638 throw new OverflowException ();
643 public static Decimal Remainder (Decimal d1, Decimal d2)
646 throw new DivideByZeroException ();
650 bool negative = d1.IsNegative ();
652 d1.flags ^= SIGN_FLAG;
653 if (d2.IsNegative ())
654 d2.flags ^= SIGN_FLAG;
664 if (decimalDiv (out result, ref d1, ref d2) != 0)
665 throw new OverflowException ();
666 result = Decimal.Truncate (result);
668 // FIXME: not really performant here
669 result = d1 - result * d2;
673 result.flags ^= SIGN_FLAG;
677 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
678 public static int Compare (Decimal d1, Decimal d2)
680 return decimalCompare (ref d1, ref d2);
683 public int CompareTo (object value)
688 if (!(value is Decimal))
689 throw new ArgumentException (Locale.GetText ("Value is not a System.Decimal"));
691 return Compare (this, (Decimal)value);
694 public int CompareTo (Decimal value)
696 return Compare (this, value);
699 public bool Equals (Decimal value)
701 return Equals (value, this);
704 public static Decimal Ceiling (Decimal d)
706 return Math.Ceiling (d);
709 public static Decimal Parse (string s)
711 return Parse (s, NumberStyles.Number, null);
714 public static Decimal Parse (string s, NumberStyles style)
716 return Parse (s, style, null);
719 public static Decimal Parse (string s, IFormatProvider provider)
721 return Parse (s, NumberStyles.Number, provider);
724 static void ThrowAtPos (int pos)
726 throw new FormatException (String.Format (Locale.GetText ("Invalid character at position {0}"), pos));
729 static void ThrowInvalidExp ()
731 throw new FormatException (Locale.GetText ("Invalid exponent"));
734 private static string stripStyles (string s, NumberStyles style, NumberFormatInfo nfi,
735 out int decPos, out bool isNegative, out bool expFlag, out int exp, bool throwex)
742 bool hasSign = false;
743 bool hasOpeningParentheses = false;
744 bool hasDecimalPoint = false;
745 bool allowedLeadingWhiteSpace = ((style & NumberStyles.AllowLeadingWhite) != 0);
746 bool allowedTrailingWhiteSpace = ((style & NumberStyles.AllowTrailingWhite) != 0);
747 bool allowedLeadingSign = ((style & NumberStyles.AllowLeadingSign) != 0);
748 bool allowedTrailingSign = ((style & NumberStyles.AllowTrailingSign) != 0);
749 bool allowedParentheses = ((style & NumberStyles.AllowParentheses) != 0);
750 bool allowedThousands = ((style & NumberStyles.AllowThousands) != 0);
751 bool allowedDecimalPoint = ((style & NumberStyles.AllowDecimalPoint) != 0);
752 bool allowedExponent = ((style & NumberStyles.AllowExponent) != 0);
754 /* get rid of currency symbol */
755 bool hasCurrency = false;
756 if ((style & NumberStyles.AllowCurrencySymbol) != 0)
758 int index = s.IndexOfOrdinalUnchecked (nfi.CurrencySymbol);
761 s = s.Remove (index, nfi.CurrencySymbol.Length);
766 string decimalSep = (hasCurrency) ? nfi.CurrencyDecimalSeparator : nfi.NumberDecimalSeparator;
767 string groupSep = (hasCurrency) ? nfi.CurrencyGroupSeparator : nfi.NumberGroupSeparator;
768 string negativeSign = nfi.NegativeSign;
769 string positiveSign = nfi.PositiveSign;
771 // If we don't have a group separator defined, it has the same effect as if it wasn't allowed.
772 if (string.IsNullOrEmpty(groupSep)) allowedThousands = false;
777 StringBuilder sb = new StringBuilder (len);
783 if (Char.IsDigit (ch))
785 break; // end of leading
787 else if (allowedLeadingWhiteSpace && Char.IsWhiteSpace (ch))
791 else if (allowedParentheses && ch == '(' && !hasSign && !hasOpeningParentheses)
793 hasOpeningParentheses = true;
798 else if (allowedLeadingSign && !string.IsNullOrEmpty (negativeSign) && ch == negativeSign[0] && !hasSign)
800 int slen = negativeSign.Length;
801 if (slen == 1 || s.IndexOfOrdinalUnchecked (negativeSign, pos, slen) == pos)
808 else if (allowedLeadingSign && !string.IsNullOrEmpty (positiveSign) && ch == positiveSign[0] && !hasSign)
810 int slen = positiveSign.Length;
811 if (slen == 1 || s.IndexOfOrdinalUnchecked (positiveSign, pos, slen) == pos)
817 else if (allowedDecimalPoint && ch == decimalSep[0])
819 int slen = decimalSep.Length;
820 if (slen != 1 && s.IndexOfOrdinalUnchecked (decimalSep, pos, slen) != pos)
840 throw new FormatException (Locale.GetText ("No digits found"));
849 if (Char.IsDigit (ch))
854 else if (allowedThousands && ch == groupSep[0] && ch != decimalSep [0])
856 int slen = groupSep.Length;
857 if (slen != 1 && s.IndexOfOrdinalUnchecked(groupSep, pos, slen) != pos)
866 else if (allowedDecimalPoint && ch == decimalSep[0] && !hasDecimalPoint)
868 int slen = decimalSep.Length;
869 if (slen == 1 || s.IndexOfOrdinalUnchecked(decimalSep, pos, slen) == pos)
872 hasDecimalPoint = true;
886 if (allowedExponent && Char.ToUpperInvariant (ch) == 'E')
897 bool isNegativeExp = false;
898 if (!string.IsNullOrEmpty (positiveSign) && ch == positiveSign[0])
900 int slen = positiveSign.Length;
901 if (slen == 1 || s.IndexOfOrdinalUnchecked (positiveSign, pos, slen) == pos)
912 else if (!string.IsNullOrEmpty (negativeSign) && ch == negativeSign[0])
914 int slen = negativeSign.Length;
915 if (slen == 1 || s.IndexOfOrdinalUnchecked (negativeSign, pos, slen) == pos)
924 isNegativeExp = true;
928 if (!Char.IsDigit(ch)) {
937 while (pos < len && Char.IsDigit (s[pos]))
943 if (isNegativeExp) exp *= -1;
951 if (allowedTrailingWhiteSpace && Char.IsWhiteSpace (ch))
955 else if (allowedParentheses && ch == ')' && hasOpeningParentheses)
957 hasOpeningParentheses = false;
960 else if (allowedTrailingSign && !string.IsNullOrWhiteSpace (negativeSign) && ch == negativeSign[0] && !hasSign)
962 int slen = negativeSign.Length;
963 if (slen == 1 || s.IndexOfOrdinalUnchecked(negativeSign, pos, slen) == pos)
970 else if (allowedTrailingSign && !string.IsNullOrWhiteSpace (positiveSign) && ch == positiveSign[0] && !hasSign)
972 int slen = positiveSign.Length;
973 if (slen == 1 || s.IndexOfOrdinalUnchecked (positiveSign, pos, slen) == pos)
981 // trailing zero characters are allowed
983 while (++pos < len && s [pos] == 0)
996 if (hasOpeningParentheses) {
998 throw new FormatException (Locale.GetText ("Closing Parentheses not found"));
1003 if (!hasDecimalPoint)
1006 return sb.ToString ();
1009 public static Decimal Parse (string s, NumberStyles style, IFormatProvider provider)
1012 throw new ArgumentNullException ("s");
1014 if ((style & NumberStyles.AllowHexSpecifier) != 0)
1015 throw new ArgumentException ("Decimal.TryParse does not accept AllowHexSpecifier", "style");
1018 PerformParse (s, style, provider, out result, true);
1022 public static bool TryParse (string s, out Decimal result)
1028 return PerformParse (s, NumberStyles.Number, null, out result, false);
1031 public static bool TryParse (string s, NumberStyles style, IFormatProvider provider, out decimal result)
1033 if (s == null || (style & NumberStyles.AllowHexSpecifier) != 0){
1038 return PerformParse (s, style, provider, out result, false);
1041 static bool PerformParse (string s, NumberStyles style, IFormatProvider provider, out Decimal res, bool throwex)
1043 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (provider);
1046 bool isNegative, expFlag;
1047 s = stripStyles(s, style, nfi, out iDecPos, out isNegative, out expFlag, out exp, throwex);
1055 throw new Exception (Locale.GetText ("Error in System.Decimal.Parse"));
1060 // first we remove leading 0
1063 while ((i < iDecPos) && (s [i] == '0'))
1065 if ((i > 1) && (len > 1)) {
1066 s = s.Substring (i, len - i);
1070 // first 0. may not be here but is part of the maximum length
1071 int max = ((iDecPos == 0) ? 27 : 28);
1073 if (len >= max + 1) {
1074 // number lower than MaxValue (base-less) can have better precision
1075 if (String.CompareOrdinal (s, 0, "79228162514264337593543950335", 0, max + 1) <= 0) {
1080 // then we trunc the string
1081 if ((len > max) && (iDecPos < len)) {
1082 int round = (s [max] - '0');
1084 bool addone = false;
1087 } else if (round == 5) {
1091 // banker's rounding applies
1092 if (len > max + 1) {
1093 addone = s [max + 1] > '0';
1095 int previous = s [max - 1] - '0';
1096 addone = ((previous & 0x01) == 0x01);
1101 s = s.Substring (0, max);
1103 char[] array = s.ToCharArray ();
1106 int b = (array [p] - '0');
1107 if (array [p] != '9') {
1108 array [p] = (char)(b + '1');
1115 if ((p == -1) && (array [0] == '0')) {
1117 s = "1".PadRight (iDecPos, '0');
1120 s = new String (array);
1125 // always work in positive (rounding issues)
1126 if (string2decimal (out result, s, (uint)iDecPos, 0) != 0){
1128 throw new OverflowException ();
1134 if (decimalSetExponent (ref result, exp) != 0){
1136 throw new OverflowException ();
1143 result.flags ^= SIGN_FLAG;
1149 public TypeCode GetTypeCode ()
1151 return TypeCode.Decimal;
1154 public static byte ToByte (decimal value)
1156 if (value > Byte.MaxValue || value < Byte.MinValue)
1157 throw new OverflowException (Locale.GetText (
1158 "Value is greater than Byte.MaxValue or less than Byte.MinValue"));
1160 // return truncated value
1161 return (byte)(Decimal.Truncate (value));
1164 public static double ToDouble (decimal d)
1166 return Convert.ToDouble (d);
1169 public static short ToInt16 (decimal value)
1171 if (value > Int16.MaxValue || value < Int16.MinValue)
1172 throw new OverflowException (Locale.GetText (
1173 "Value is greater than Int16.MaxValue or less than Int16.MinValue"));
1175 // return truncated value
1176 return (Int16)(Decimal.Truncate (value));
1179 public static int ToInt32 (decimal d)
1181 if (d > Int32.MaxValue || d < Int32.MinValue)
1182 throw new OverflowException (Locale.GetText (
1183 "Value is greater than Int32.MaxValue or less than Int32.MinValue"));
1185 // return truncated value
1186 return (Int32)(Decimal.Truncate (d));
1189 public static long ToInt64 (decimal d)
1191 if (d > Int64.MaxValue || d < Int64.MinValue)
1192 throw new OverflowException (Locale.GetText (
1193 "Value is greater than Int64.MaxValue or less than Int64.MinValue"));
1195 // return truncated value
1196 return (Int64)(Decimal.Truncate (d));
1199 public static long ToOACurrency (decimal value)
1201 return (long) (value * 10000);
1204 [CLSCompliant(false)]
1205 public static sbyte ToSByte (decimal value)
1207 if (value > SByte.MaxValue || value < SByte.MinValue)
1208 throw new OverflowException (Locale.GetText (
1209 "Value is greater than SByte.MaxValue or less than SByte.MinValue"));
1211 // return truncated value
1212 return (SByte)(Decimal.Truncate (value));
1215 public static float ToSingle (decimal d)
1217 return Convert.ToSingle (d);
1220 [CLSCompliant(false)]
1221 public static ushort ToUInt16 (decimal value)
1223 if (value > UInt16.MaxValue || value < UInt16.MinValue)
1224 throw new OverflowException (Locale.GetText (
1225 "Value is greater than UInt16.MaxValue or less than UInt16.MinValue"));
1227 // return truncated value
1228 return (UInt16)(Decimal.Truncate (value));
1231 [CLSCompliant(false)]
1232 public static uint ToUInt32 (decimal d)
1234 if (d > UInt32.MaxValue || d < UInt32.MinValue)
1235 throw new OverflowException (Locale.GetText (
1236 "Value is greater than UInt32.MaxValue or less than UInt32.MinValue"));
1238 // return truncated value
1239 return (UInt32)(Decimal.Truncate (d));
1242 [CLSCompliant(false)]
1243 public static ulong ToUInt64 (decimal d)
1245 if (d > UInt64.MaxValue || d < UInt64.MinValue)
1246 throw new OverflowException (Locale.GetText (
1247 "Value is greater than UInt64.MaxValue or less than UInt64.MinValue"));
1249 // return truncated value
1250 return (UInt64)(Decimal.Truncate (d));
1253 object IConvertible.ToType (Type targetType, IFormatProvider provider)
1255 if (targetType == null)
1256 throw new ArgumentNullException ("targetType");
1257 return Convert.ToType (this, targetType, provider, false);
1260 bool IConvertible.ToBoolean (IFormatProvider provider)
1262 return Convert.ToBoolean (this);
1265 byte IConvertible.ToByte (IFormatProvider provider)
1267 return Convert.ToByte (this);
1270 char IConvertible.ToChar (IFormatProvider provider)
1272 throw new InvalidCastException ();
1275 DateTime IConvertible.ToDateTime (IFormatProvider provider)
1277 throw new InvalidCastException ();
1280 decimal IConvertible.ToDecimal (IFormatProvider provider)
1285 double IConvertible.ToDouble (IFormatProvider provider)
1287 return Convert.ToDouble (this);
1290 short IConvertible.ToInt16 (IFormatProvider provider)
1292 return Convert.ToInt16 (this);
1295 int IConvertible.ToInt32 (IFormatProvider provider)
1297 return Convert.ToInt32 (this);
1300 long IConvertible.ToInt64 (IFormatProvider provider)
1302 return Convert.ToInt64 (this);
1305 sbyte IConvertible.ToSByte (IFormatProvider provider)
1307 return Convert.ToSByte (this);
1310 float IConvertible.ToSingle (IFormatProvider provider)
1312 return Convert.ToSingle (this);
1315 ushort IConvertible.ToUInt16 (IFormatProvider provider)
1317 return Convert.ToUInt16 (this);
1320 uint IConvertible.ToUInt32 (IFormatProvider provider)
1322 return Convert.ToUInt32 (this);
1325 ulong IConvertible.ToUInt64 (IFormatProvider provider)
1327 return Convert.ToUInt64 (this);
1330 public string ToString (string format, IFormatProvider provider)
1332 return NumberFormatter.NumberToString (format, this, provider);
1335 public override string ToString ()
1337 return ToString ("G", null);
1340 public string ToString (string format)
1342 return ToString (format, null);
1345 public string ToString (IFormatProvider provider)
1347 return ToString ("G", provider);
1351 void IDeserializationCallback.OnDeserialization(object sender)
1357 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1358 private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
1360 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1361 private static extern int decimal2Int64 (ref Decimal val, out long result);
1363 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1364 private static extern int double2decimal (out Decimal erg, double val, int digits);
1366 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1367 private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
1369 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1370 internal static extern int string2decimal (out Decimal val, String sDigits, uint decPos, int sign);
1372 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1373 internal static extern int decimalSetExponent (ref Decimal val, int exp);
1375 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1376 private static extern double decimal2double (ref Decimal val);
1378 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1379 private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
1381 // [MethodImplAttribute(MethodImplOptions.InternalCall)]
1382 // private static extern void decimalRound (ref Decimal val, int decimals);
1384 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1385 private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
1387 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1388 private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1390 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1391 private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1393 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1394 private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);
1396 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1397 [DllImport("libdec", EntryPoint="decimal2UInt64")]
1398 private static extern int decimal2UInt64 (ref Decimal val, out ulong result);
1400 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1401 [DllImport("libdec", EntryPoint="decimal2Int64")]
1402 private static extern int decimal2Int64 (ref Decimal val, out long result);
1404 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1405 [DllImport("libdec", EntryPoint="double2decimal")]
1406 private static extern int double2decimal (out Decimal erg, double val, int digits);
1408 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1409 [DllImport("libdec", EntryPoint="decimalIncr")]
1410 private static extern int decimalIncr (ref Decimal d1, ref Decimal d2);
1412 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1413 [DllImport("libdec", EntryPoint="string2decimal")]
1414 internal static extern int string2decimal (out Decimal val,
1415 [MarshalAs(UnmanagedType.LPWStr)]String sDigits,
1416 uint decPos, int sign);
1418 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1419 [DllImport("libdec", EntryPoint="decimalSetExponent")]
1420 internal static extern int decimalSetExponent (ref Decimal val, int exp);
1422 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1423 [DllImport("libdec", EntryPoint="decimal2double")]
1424 private static extern double decimal2double (ref Decimal val);
1426 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1427 [DllImport("libdec", EntryPoint="decimalFloorAndTrunc")]
1428 private static extern void decimalFloorAndTrunc (ref Decimal val, int floorFlag);
1430 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1431 [DllImport("libdec", EntryPoint="decimalRound")]
1432 private static extern void decimalRound (ref Decimal val, int decimals);
1434 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1435 [DllImport("libdec", EntryPoint="decimalMult")]
1436 private static extern int decimalMult (ref Decimal pd1, ref Decimal pd2);
1438 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1439 [DllImport("libdec", EntryPoint="decimalDiv")]
1440 private static extern int decimalDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1442 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1443 [DllImport("libdec", EntryPoint="decimalIntDiv")]
1444 private static extern int decimalIntDiv (out Decimal pc, ref Decimal pa, ref Decimal pb);
1446 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1447 [DllImport("libdec", EntryPoint="decimalCompare")]
1448 private static extern int decimalCompare (ref Decimal d1, ref Decimal d2);