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)
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:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
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.
37 using System
.Globalization
;
39 using System
.Runtime
.CompilerServices
;
40 using System
.Runtime
.ConstrainedExecution
;
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 public const decimal MinValue
= -79228162514264337593543950335m
;
58 public const decimal MaxValue
= 79228162514264337593543950335m
;
60 public const decimal MinusOne
= -1;
61 public const decimal One
= 1;
62 public const decimal Zero
= 0;
64 private static readonly Decimal MaxValueDiv10
= MaxValue
/ 10;
67 private const uint MAX_SCALE
= 28;
68 private const uint SIGN_FLAG
= 0x80000000;
69 private const int SCALE_SHIFT
= 16;
70 private const uint RESERVED_SS32_BITS
= 0x7F00FFFF;
72 // internal representation of decimal
78 public Decimal (int lo
, int mid
, int hi
, bool isNegative
, byte scale
)
83 this.mid
= (uint) mid
;
86 if (scale
> MAX_SCALE
)
87 throw new ArgumentOutOfRangeException (Locale
.GetText ("scale must be between 0 and 28"));
90 flags
<<= SCALE_SHIFT
;
91 if (isNegative
) flags
|= SIGN_FLAG
;
95 public Decimal (int value)
103 lo
= ((uint)~
value) + 1;
113 [CLSCompliant(false)]
114 public Decimal (uint value)
117 flags
= hi
= mid
= 0;
120 public Decimal (long value)
128 ulong u
= ((ulong)~
value) + 1;
130 mid
= (uint)(u
>> 32);
135 ulong u
= (ulong)value;
137 mid
= (uint)(u
>> 32);
142 [CLSCompliant(false)]
143 public Decimal (ulong value)
149 mid
= (uint)(value >> 32);
153 public Decimal (float value)
157 // We cant use the double2decimal method
158 // because it incorrectly turns the floating point
159 // value 1.23456789E-25F which should be:
160 // 0.0000000000000000000000001235
161 // into the incorrect:
162 // 0.0000000000000000000000001234
164 // The code currently parses the double value 0.6 as
167 // And we have a patch for that called (trim
168 if (double2decimal (out this, value, 7) != 0)
169 throw new OverflowException ();
171 if (value > (float)Decimal
.MaxValue
|| value < (float)Decimal
.MinValue
||
172 float.IsNaN (value) || float.IsNegativeInfinity (value) || float.IsPositiveInfinity (value)) {
173 throw new OverflowException (Locale
.GetText (
174 "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
177 // we must respect the precision (double2decimal doesn't)
178 Decimal d
= Decimal
.Parse (value.ToString (CultureInfo
.InvariantCulture
),
179 NumberStyles
.Float
, CultureInfo
.InvariantCulture
);
187 public Decimal (double value)
191 // We cant use the double2decimal method
192 // because it incorrectly turns the floating point
193 // value 1.23456789E-25F which should be:
194 // 0.0000000000000000000000001235
195 // into the incorrect:
196 // 0.0000000000000000000000001234
198 // The code currently parses the double value 0.6 as
201 // And we have a patch for that called (trim
202 if (double2decimal (out this, value, 15) != 0)
203 throw new OverflowException ();
205 if (value > (double)Decimal
.MaxValue
|| value < (double)Decimal
.MinValue
||
206 double.IsNaN (value) || double.IsNegativeInfinity (value) || double.IsPositiveInfinity (value)) {
207 throw new OverflowException (Locale
.GetText (
208 "Value {0} is greater than Decimal.MaxValue or less than Decimal.MinValue", value));
210 // we must respect the precision (double2decimal doesn't)
211 Decimal d
= Decimal
.Parse (value.ToString (CultureInfo
.InvariantCulture
),
212 NumberStyles
.Float
, CultureInfo
.InvariantCulture
);
220 public Decimal (int[] bits
)
224 throw new ArgumentNullException (Locale
.GetText ("Bits is a null reference"));
227 if (bits
.GetLength(0) != 4)
229 throw new ArgumentException (Locale
.GetText ("bits does not contain four values"));
234 mid
= (uint) bits
[1];
236 flags
= (uint) bits
[3];
237 byte scale
= (byte)(flags
>> SCALE_SHIFT
);
238 if (scale
> MAX_SCALE
|| (flags
& RESERVED_SS32_BITS
) != 0)
240 throw new ArgumentException (Locale
.GetText ("Invalid bits[3]"));
245 public static decimal FromOACurrency (long cy
)
247 return (decimal)cy
/ (decimal)10000;
250 public static int[] GetBits (Decimal d
)
254 return new int[] { (int)d.lo, (int)d.mid, (int)d.hi, (int)d.flags }
;
258 public static Decimal
Negate (Decimal d
)
260 d
.flags ^
= SIGN_FLAG
;
264 public static Decimal
Add (Decimal d1
, Decimal d2
)
266 if (decimalIncr (ref d1
, ref d2
) == 0)
269 throw new OverflowException (Locale
.GetText ("Overflow on adding decimal number"));
272 public static Decimal
Subtract (Decimal d1
, Decimal d2
)
274 d2
.flags ^
= SIGN_FLAG
;
275 int result
= decimalIncr (ref d1
, ref d2
);
279 throw new OverflowException (Locale
.GetText ("Overflow on subtracting decimal numbers ("+result
+")"));
282 public override int GetHashCode ()
284 return (int) (flags ^ hi ^ lo ^ mid
);
287 public static Decimal
operator + (Decimal d1
, Decimal d2
)
292 public static Decimal
operator -- (Decimal d
)
294 return Add(d
, MinusOne
);
297 public static Decimal
operator ++ (Decimal d
)
302 public static Decimal
operator - (Decimal d1
, Decimal d2
)
304 return Subtract (d1
, d2
);
307 public static Decimal
operator - (Decimal d
)
312 public static Decimal
operator + (Decimal d
)
317 public static Decimal
operator * (Decimal d1
, Decimal d2
)
319 return Multiply (d1
, d2
);
322 public static Decimal
operator / (Decimal d1
, Decimal d2
)
324 return Divide (d1
, d2
);
327 public static Decimal
operator % (Decimal d1
, Decimal d2
)
329 return Remainder (d1
, d2
);
332 private static ulong u64 (Decimal
value)
336 decimalFloorAndTrunc (ref value, 0);
337 if (decimal2UInt64 (ref value, out result
) != 0) {
338 throw new System
.OverflowException ();
343 private static long s64 (Decimal
value)
347 decimalFloorAndTrunc (ref value, 0);
348 if (decimal2Int64 (ref value, out result
) != 0) {
349 throw new System
.OverflowException ();
354 public static explicit operator byte (Decimal
value)
356 ulong result
= u64 (value);
357 return checked ((byte) result
);
360 [CLSCompliant (false)]
361 public static explicit operator sbyte (Decimal
value)
363 long result
= s64 (value);
364 return checked ((sbyte) result
);
367 public static explicit operator char (Decimal
value)
369 ulong result
= u64 (value);
370 return checked ((char) result
);
373 public static explicit operator short (Decimal
value)
375 long result
= s64 (value);
376 return checked ((short) result
);
379 [CLSCompliant (false)]
380 public static explicit operator ushort (Decimal
value)
382 ulong result
= u64 (value);
383 return checked ((ushort) result
);
386 public static explicit operator int (Decimal
value)
388 long result
= s64 (value);
389 return checked ((int) result
);
392 [CLSCompliant(false)]
393 public static explicit operator uint (Decimal
value)
395 ulong result
= u64 (value);
396 return checked ((uint) result
);
399 public static explicit operator long (Decimal
value)
404 [CLSCompliant(false)]
405 public static explicit operator ulong (Decimal
value)
410 public static implicit operator Decimal (byte value)
412 return new Decimal (value);
415 [CLSCompliant(false)]
416 public static implicit operator Decimal (sbyte value)
418 return new Decimal (value);
421 public static implicit operator Decimal (short value)
423 return new Decimal (value);
426 [CLSCompliant(false)]
427 public static implicit operator Decimal (ushort value)
429 return new Decimal (value);
432 public static implicit operator Decimal (char value)
434 return new Decimal (value);
437 public static implicit operator Decimal (int value)
439 return new Decimal (value);
442 [CLSCompliant(false)]
443 public static implicit operator Decimal (uint value)
445 return new Decimal (value);
448 public static implicit operator Decimal (long value)
450 return new Decimal (value);
453 [CLSCompliant(false)]
454 public static implicit operator Decimal (ulong value)
456 return new Decimal (value);
459 public static explicit operator Decimal (float value)
461 return new Decimal (value);
464 public static explicit operator Decimal (double value)
466 return new Decimal (value);
469 public static explicit operator float (Decimal
value)
471 return (float) (double) value;
474 public static explicit operator double (Decimal
value)
476 return decimal2double (ref value);
480 public static bool operator != (Decimal d1
, Decimal d2
)
482 return !Equals (d1
, d2
);
485 public static bool operator == (Decimal d1
, Decimal d2
)
487 return Equals (d1
, d2
);
490 public static bool operator > (Decimal d1
, Decimal d2
)
492 return Compare (d1
, d2
) > 0;
495 public static bool operator >= (Decimal d1
, Decimal d2
)
497 return Compare (d1
, d2
) >= 0;
500 public static bool operator < (Decimal d1
, Decimal d2
)
502 return Compare (d1
, d2
) < 0;
505 public static bool operator <= (Decimal d1
, Decimal d2
)
507 return Compare (d1
, d2
) <= 0;
510 public static bool Equals (Decimal d1
, Decimal d2
)
512 return Compare (d1
, d2
) == 0;
515 public override bool Equals (object value)
517 if (!(value is Decimal
))
520 return Equals ((Decimal
) value, this);
523 // avoid unmanaged call
524 private bool IsZero ()
526 return ((hi
== 0) && (lo
== 0) && (mid
== 0));
529 // avoid unmanaged call
530 private bool IsNegative ()
532 return ((flags
& 0x80000000) == 0x80000000);
535 public static Decimal
Floor (Decimal d
)
537 decimalFloorAndTrunc (ref d
, 1);
541 public static Decimal
Truncate (Decimal d
)
543 decimalFloorAndTrunc (ref d
, 0);
547 public static Decimal
Round (Decimal d
, int decimals
)
549 return Round (d
, decimals
, MidpointRounding
.ToEven
);
552 public static Decimal
Round (Decimal d
, int decimals
, MidpointRounding mode
)
554 if ((mode
!= MidpointRounding
.ToEven
) && (mode
!= MidpointRounding
.AwayFromZero
))
555 throw new ArgumentException ("The value '" + mode
+ "' is not valid for this usage of the type MidpointRounding.", "mode");
557 if (decimals
< 0 || decimals
> 28) {
558 throw new ArgumentOutOfRangeException ("decimals", "[0,28]");
561 bool negative
= d
.IsNegative ();
563 d
.flags ^
= SIGN_FLAG
;
565 // Moved from Math.cs because it's easier to fix the "sign"
566 // issue here :( as the logic is OK only for positive numbers
567 decimal p
= (decimal) Math
.Pow (10, decimals
);
568 decimal int_part
= Decimal
.Floor (d
);
569 decimal dec_part
= d
- int_part
;
570 dec_part
*= 10000000000000000000000000000M
;
571 dec_part
= Decimal
.Floor(dec_part
);
572 dec_part
/= (10000000000000000000000000000M
/ p
);
573 dec_part
= Math
.Round (dec_part
, mode
);
575 decimal result
= int_part
+ dec_part
;
577 // that fixes the precision/scale (which we must keep for output)
578 // (moved and adapted from System.Data.SqlTypes.SqlMoney)
579 long scaleDiff
= decimals
- ((result
.flags
& 0x7FFF0000) >> 16);
582 // note: here we always work with positive numbers
583 while (scaleDiff
> 0) {
584 if (result
> MaxValueDiv10
)
590 else if (scaleDiff
< 0) {
591 while (scaleDiff
< 0) {
596 result
.flags
= (uint)((decimals
- scaleDiff
) << SCALE_SHIFT
);
599 result
.flags ^
= SIGN_FLAG
;
603 public static Decimal
Round (Decimal d
)
605 return Math
.Round (d
);
608 public static Decimal
Round (Decimal d
, MidpointRounding mode
)
610 return Math
.Round (d
, mode
);
613 public static Decimal
Multiply (Decimal d1
, Decimal d2
)
615 if (d1
.IsZero () || d2
.IsZero ())
618 if (decimalMult (ref d1
, ref d2
) != 0)
619 throw new OverflowException ();
623 public static Decimal
Divide (Decimal d1
, Decimal d2
)
626 throw new DivideByZeroException ();
630 d1
.flags ^
= SIGN_FLAG
;
631 d1
.flags ^
= SIGN_FLAG
;
634 if (decimalDiv (out result
, ref d1
, ref d2
) != 0)
635 throw new OverflowException ();
640 public static Decimal
Remainder (Decimal d1
, Decimal d2
)
643 throw new DivideByZeroException ();
647 bool negative
= d1
.IsNegative ();
649 d1
.flags ^
= SIGN_FLAG
;
650 if (d2
.IsNegative ())
651 d2
.flags ^
= SIGN_FLAG
;
661 if (decimalDiv (out result
, ref d1
, ref d2
) != 0)
662 throw new OverflowException ();
663 result
= Decimal
.Truncate (result
);
665 // FIXME: not really performant here
666 result
= d1
- result
* d2
;
670 result
.flags ^
= SIGN_FLAG
;
674 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
675 public static int Compare (Decimal d1
, Decimal d2
)
677 return decimalCompare (ref d1
, ref d2
);
680 public int CompareTo (object value)
685 if (!(value is Decimal
))
686 throw new ArgumentException (Locale
.GetText ("Value is not a System.Decimal"));
688 return Compare (this, (Decimal
)value);
691 public int CompareTo (Decimal
value)
693 return Compare (this, value);
696 public bool Equals (Decimal
value)
698 return Equals (value, this);
701 public static Decimal
Ceiling (Decimal d
)
703 return Math
.Ceiling (d
);
706 public static Decimal
Parse (string s
)
708 return Parse (s
, NumberStyles
.Number
, null);
711 public static Decimal
Parse (string s
, NumberStyles style
)
713 return Parse (s
, style
, null);
716 public static Decimal
Parse (string s
, IFormatProvider provider
)
718 return Parse (s
, NumberStyles
.Number
, provider
);
721 static void ThrowAtPos (int pos
)
723 throw new FormatException (String
.Format (Locale
.GetText ("Invalid character at position {0}"), pos
));
726 static void ThrowInvalidExp ()
728 throw new FormatException (Locale
.GetText ("Invalid exponent"));
731 private static string stripStyles (string s
, NumberStyles style
, NumberFormatInfo nfi
,
732 out int decPos
, out bool isNegative
, out bool expFlag
, out int exp
, bool throwex
)
739 bool hasSign
= false;
740 bool hasOpeningParentheses
= false;
741 bool hasDecimalPoint
= false;
742 bool allowedLeadingWhiteSpace
= ((style
& NumberStyles
.AllowLeadingWhite
) != 0);
743 bool allowedTrailingWhiteSpace
= ((style
& NumberStyles
.AllowTrailingWhite
) != 0);
744 bool allowedLeadingSign
= ((style
& NumberStyles
.AllowLeadingSign
) != 0);
745 bool allowedTrailingSign
= ((style
& NumberStyles
.AllowTrailingSign
) != 0);
746 bool allowedParentheses
= ((style
& NumberStyles
.AllowParentheses
) != 0);
747 bool allowedThousands
= ((style
& NumberStyles
.AllowThousands
) != 0);
748 bool allowedDecimalPoint
= ((style
& NumberStyles
.AllowDecimalPoint
) != 0);
749 bool allowedExponent
= ((style
& NumberStyles
.AllowExponent
) != 0);
751 /* get rid of currency symbol */
752 bool hasCurrency
= false;
753 if ((style
& NumberStyles
.AllowCurrencySymbol
) != 0)
755 int index
= s
.IndexOf (nfi
.CurrencySymbol
);
758 s
= s
.Remove (index
, nfi
.CurrencySymbol
.Length
);
763 string decimalSep
= (hasCurrency
) ? nfi
.CurrencyDecimalSeparator
: nfi
.NumberDecimalSeparator
;
764 string groupSep
= (hasCurrency
) ? nfi
.CurrencyGroupSeparator
: nfi
.NumberGroupSeparator
;
769 StringBuilder sb
= new StringBuilder (len
);
775 if (Char
.IsDigit (ch
))
777 break; // end of leading
779 else if (allowedLeadingWhiteSpace
&& Char
.IsWhiteSpace (ch
))
783 else if (allowedParentheses
&& ch
== '(' && !hasSign
&& !hasOpeningParentheses
)
785 hasOpeningParentheses
= true;
790 else if (allowedLeadingSign
&& ch
== nfi
.NegativeSign
[0] && !hasSign
)
792 int slen
= nfi
.NegativeSign
.Length
;
793 if (slen
== 1 || s
.IndexOf (nfi
.NegativeSign
, pos
, slen
) == pos
)
800 else if (allowedLeadingSign
&& ch
== nfi
.PositiveSign
[0] && !hasSign
)
802 int slen
= nfi
.PositiveSign
.Length
;
803 if (slen
== 1 || s
.IndexOf (nfi
.PositiveSign
, pos
, slen
) == pos
)
809 else if (allowedDecimalPoint
&& ch
== decimalSep
[0])
811 int slen
= decimalSep
.Length
;
812 if (slen
!= 1 && s
.IndexOf (decimalSep
, pos
, slen
) != pos
)
832 throw new FormatException (Locale
.GetText ("No digits found"));
841 if (Char
.IsDigit (ch
))
846 else if (allowedThousands
&& ch
== groupSep
[0] && ch
!= decimalSep
[0])
848 int slen
= groupSep
.Length
;
849 if (slen
!= 1 && s
.IndexOf(groupSep
, pos
, slen
) != pos
)
858 else if (allowedDecimalPoint
&& ch
== decimalSep
[0] && !hasDecimalPoint
)
860 int slen
= decimalSep
.Length
;
861 if (slen
== 1 || s
.IndexOf(decimalSep
, pos
, slen
) == pos
)
864 hasDecimalPoint
= true;
878 if (allowedExponent
&& Char
.ToUpperInvariant (ch
) == 'E')
889 bool isNegativeExp
= false;
890 if (ch
== nfi
.PositiveSign
[0])
892 int slen
= nfi
.PositiveSign
.Length
;
893 if (slen
== 1 || s
.IndexOf (nfi
.PositiveSign
, pos
, slen
) == pos
)
904 else if (ch
== nfi
.NegativeSign
[0])
906 int slen
= nfi
.NegativeSign
.Length
;
907 if (slen
== 1 || s
.IndexOf (nfi
.NegativeSign
, pos
, slen
) == pos
)
916 isNegativeExp
= true;
920 if (!Char
.IsDigit(ch
)) {
929 while (pos
< len
&& Char
.IsDigit (s
[pos
]))
935 if (isNegativeExp
) exp
*= -1;
943 if (allowedTrailingWhiteSpace
&& Char
.IsWhiteSpace (ch
))
947 else if (allowedParentheses
&& ch
== ')' && hasOpeningParentheses
)
949 hasOpeningParentheses
= false;
952 else if (allowedTrailingSign
&& ch
== nfi
.NegativeSign
[0] && !hasSign
)
954 int slen
= nfi
.NegativeSign
.Length
;
955 if (slen
== 1 || s
.IndexOf (nfi
.NegativeSign
, pos
, slen
) == pos
)
962 else if (allowedTrailingSign
&& ch
== nfi
.PositiveSign
[0] && !hasSign
)
964 int slen
= nfi
.PositiveSign
.Length
;
965 if (slen
== 1 || s
.IndexOf(nfi
.PositiveSign
, pos
, slen
) == pos
)
973 // trailing zero characters are allowed
975 while (++pos
< len
&& s
[pos
] == 0)
988 if (hasOpeningParentheses
) {
990 throw new FormatException (Locale
.GetText ("Closing Parentheses not found"));
995 if (!hasDecimalPoint
)
998 return sb
.ToString ();
1001 public static Decimal
Parse (string s
, NumberStyles style
, IFormatProvider provider
)
1004 throw new ArgumentNullException ("s");
1006 if ((style
& NumberStyles
.AllowHexSpecifier
) != 0)
1007 throw new ArgumentException ("Decimal.TryParse does not accept AllowHexSpecifier", "style");
1010 PerformParse (s
, style
, provider
, out result
, true);
1014 public static bool TryParse (string s
, out Decimal result
)
1020 return PerformParse (s
, NumberStyles
.Number
, null, out result
, false);
1023 public static bool TryParse (string s
, NumberStyles style
, IFormatProvider provider
, out decimal result
)
1025 if (s
== null || (style
& NumberStyles
.AllowHexSpecifier
) != 0){
1030 return PerformParse (s
, style
, provider
, out result
, false);
1033 static bool PerformParse (string s
, NumberStyles style
, IFormatProvider provider
, out Decimal res
, bool throwex
)
1035 NumberFormatInfo nfi
= NumberFormatInfo
.GetInstance (provider
);
1038 bool isNegative
, expFlag
;
1039 s
= stripStyles(s
, style
, nfi
, out iDecPos
, out isNegative
, out expFlag
, out exp
, throwex
);
1047 throw new Exception (Locale
.GetText ("Error in System.Decimal.Parse"));
1052 // first we remove leading 0
1055 while ((i
< iDecPos
) && (s
[i
] == '0'))
1057 if ((i
> 1) && (len
> 1)) {
1058 s
= s
.Substring (i
, len
- i
);
1062 // first 0. may not be here but is part of the maximum length
1063 int max
= ((iDecPos
== 0) ? 27 : 28);
1065 if (len
>= max
+ 1) {
1066 // number lower than MaxValue (base-less) can have better precision
1067 if (String
.Compare (s
, 0, "79228162514264337593543950335", 0, max
+ 1,
1068 false, CultureInfo
.InvariantCulture
) <= 0) {
1073 // then we trunc the string
1074 if ((len
> max
) && (iDecPos
< len
)) {
1075 int round
= (s
[max
] - '0');
1076 s
= s
.Substring (0, max
);
1078 bool addone
= false;
1082 else if (round
== 5) {
1087 // banker rounding applies :(
1088 int previous
= (s
[max
- 1] - '0');
1089 addone
= ((previous
& 0x01) == 0x01);
1093 char[] array
= s
.ToCharArray ();
1096 int b
= (array
[p
] - '0');
1097 if (array
[p
] != '9') {
1098 array
[p
] = (char)(b
+ '1');
1105 if ((p
== -1) && (array
[0] == '0')) {
1107 s
= "1".PadRight (iDecPos
, '0');
1110 s
= new String (array
);
1115 // always work in positive (rounding issues)
1116 if (string2decimal (out result
, s
, (uint)iDecPos
, 0) != 0){
1118 throw new OverflowException ();
1124 if (decimalSetExponent (ref result
, exp
) != 0){
1126 throw new OverflowException ();
1133 result
.flags ^
= SIGN_FLAG
;
1139 public TypeCode
GetTypeCode ()
1141 return TypeCode
.Decimal
;
1144 public static byte ToByte (decimal value)
1146 if (value > Byte
.MaxValue
|| value < Byte
.MinValue
)
1147 throw new OverflowException (Locale
.GetText (
1148 "Value is greater than Byte.MaxValue or less than Byte.MinValue"));
1150 // return truncated value
1151 return (byte)(Decimal
.Truncate (value));
1154 public static double ToDouble (decimal d
)
1156 return Convert
.ToDouble (d
);
1159 public static short ToInt16 (decimal value)
1161 if (value > Int16
.MaxValue
|| value < Int16
.MinValue
)
1162 throw new OverflowException (Locale
.GetText (
1163 "Value is greater than Int16.MaxValue or less than Int16.MinValue"));
1165 // return truncated value
1166 return (Int16
)(Decimal
.Truncate (value));
1169 public static int ToInt32 (decimal d
)
1171 if (d
> Int32
.MaxValue
|| d
< Int32
.MinValue
)
1172 throw new OverflowException (Locale
.GetText (
1173 "Value is greater than Int32.MaxValue or less than Int32.MinValue"));
1175 // return truncated value
1176 return (Int32
)(Decimal
.Truncate (d
));
1179 public static long ToInt64 (decimal d
)
1181 if (d
> Int64
.MaxValue
|| d
< Int64
.MinValue
)
1182 throw new OverflowException (Locale
.GetText (
1183 "Value is greater than Int64.MaxValue or less than Int64.MinValue"));
1185 // return truncated value
1186 return (Int64
)(Decimal
.Truncate (d
));
1189 public static long ToOACurrency (decimal value)
1191 return (long) (value * 10000);
1194 [CLSCompliant(false)]
1195 public static sbyte ToSByte (decimal value)
1197 if (value > SByte
.MaxValue
|| value < SByte
.MinValue
)
1198 throw new OverflowException (Locale
.GetText (
1199 "Value is greater than SByte.MaxValue or less than SByte.MinValue"));
1201 // return truncated value
1202 return (SByte
)(Decimal
.Truncate (value));
1205 public static float ToSingle (decimal d
)
1207 return Convert
.ToSingle (d
);
1210 [CLSCompliant(false)]
1211 public static ushort ToUInt16 (decimal value)
1213 if (value > UInt16
.MaxValue
|| value < UInt16
.MinValue
)
1214 throw new OverflowException (Locale
.GetText (
1215 "Value is greater than UInt16.MaxValue or less than UInt16.MinValue"));
1217 // return truncated value
1218 return (UInt16
)(Decimal
.Truncate (value));
1221 [CLSCompliant(false)]
1222 public static uint ToUInt32 (decimal d
)
1224 if (d
> UInt32
.MaxValue
|| d
< UInt32
.MinValue
)
1225 throw new OverflowException (Locale
.GetText (
1226 "Value is greater than UInt32.MaxValue or less than UInt32.MinValue"));
1228 // return truncated value
1229 return (UInt32
)(Decimal
.Truncate (d
));
1232 [CLSCompliant(false)]
1233 public static ulong ToUInt64 (decimal d
)
1235 if (d
> UInt64
.MaxValue
|| d
< UInt64
.MinValue
)
1236 throw new OverflowException (Locale
.GetText (
1237 "Value is greater than UInt64.MaxValue or less than UInt64.MinValue"));
1239 // return truncated value
1240 return (UInt64
)(Decimal
.Truncate (d
));
1243 object IConvertible
.ToType (Type targetType
, IFormatProvider provider
)
1245 if (targetType
== null)
1246 throw new ArgumentNullException ("targetType");
1247 return Convert
.ToType (this, targetType
, provider
, false);
1250 bool IConvertible
.ToBoolean (IFormatProvider provider
)
1252 return Convert
.ToBoolean (this);
1255 byte IConvertible
.ToByte (IFormatProvider provider
)
1257 return Convert
.ToByte (this);
1260 char IConvertible
.ToChar (IFormatProvider provider
)
1262 throw new InvalidCastException ();
1265 DateTime IConvertible
.ToDateTime (IFormatProvider provider
)
1267 throw new InvalidCastException ();
1270 decimal IConvertible
.ToDecimal (IFormatProvider provider
)
1275 double IConvertible
.ToDouble (IFormatProvider provider
)
1277 return Convert
.ToDouble (this);
1280 short IConvertible
.ToInt16 (IFormatProvider provider
)
1282 return Convert
.ToInt16 (this);
1285 int IConvertible
.ToInt32 (IFormatProvider provider
)
1287 return Convert
.ToInt32 (this);
1290 long IConvertible
.ToInt64 (IFormatProvider provider
)
1292 return Convert
.ToInt64 (this);
1295 sbyte IConvertible
.ToSByte (IFormatProvider provider
)
1297 return Convert
.ToSByte (this);
1300 float IConvertible
.ToSingle (IFormatProvider provider
)
1302 return Convert
.ToSingle (this);
1305 ushort IConvertible
.ToUInt16 (IFormatProvider provider
)
1307 return Convert
.ToUInt16 (this);
1310 uint IConvertible
.ToUInt32 (IFormatProvider provider
)
1312 return Convert
.ToUInt32 (this);
1315 ulong IConvertible
.ToUInt64 (IFormatProvider provider
)
1317 return Convert
.ToUInt64 (this);
1320 public string ToString (string format
, IFormatProvider provider
)
1322 return NumberFormatter
.NumberToString (format
, this, provider
);
1325 public override string ToString ()
1327 return ToString ("G", null);
1330 public string ToString (string format
)
1332 return ToString (format
, null);
1335 public string ToString (IFormatProvider provider
)
1337 return ToString ("G", provider
);
1341 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1342 private static extern int decimal2UInt64 (ref Decimal val
, out ulong result
);
1344 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1345 private static extern int decimal2Int64 (ref Decimal val
, out long result
);
1347 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1348 private static extern int double2decimal (out Decimal erg
, double val
, int digits
);
1350 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1351 private static extern int decimalIncr (ref Decimal d1
, ref Decimal d2
);
1353 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1354 internal static extern int decimal2string (ref Decimal val
,
1355 int digits
, int decimals
, char[] bufDigits
, int bufSize
, out int decPos
, out int sign
);
1357 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1358 internal static extern int string2decimal (out Decimal val
, String sDigits
, uint decPos
, int sign
);
1360 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1361 internal static extern int decimalSetExponent (ref Decimal val
, int exp
);
1363 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1364 private static extern double decimal2double (ref Decimal val
);
1366 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1367 private static extern void decimalFloorAndTrunc (ref Decimal val
, int floorFlag
);
1369 // [MethodImplAttribute(MethodImplOptions.InternalCall)]
1370 // private static extern void decimalRound (ref Decimal val, int decimals);
1372 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1373 private static extern int decimalMult (ref Decimal pd1
, ref Decimal pd2
);
1375 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1376 private static extern int decimalDiv (out Decimal pc
, ref Decimal pa
, ref Decimal pb
);
1378 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1379 private static extern int decimalIntDiv (out Decimal pc
, ref Decimal pa
, ref Decimal pb
);
1381 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1382 private static extern int decimalCompare (ref Decimal d1
, ref Decimal d2
);
1384 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1385 [DllImport("libdec", EntryPoint
="decimal2UInt64")]
1386 private static extern int decimal2UInt64 (ref Decimal val
, out ulong result
);
1388 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1389 [DllImport("libdec", EntryPoint
="decimal2Int64")]
1390 private static extern int decimal2Int64 (ref Decimal val
, out long result
);
1392 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1393 [DllImport("libdec", EntryPoint
="double2decimal")]
1394 private static extern int double2decimal (out Decimal erg
, double val
, int digits
);
1396 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1397 [DllImport("libdec", EntryPoint
="decimalIncr")]
1398 private static extern int decimalIncr (ref Decimal d1
, ref Decimal d2
);
1400 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1401 [DllImport("libdec", EntryPoint
="decimal2string")]
1402 internal static extern int decimal2string (ref Decimal val
,
1403 int digits
, int decimals
,
1404 [MarshalAs(UnmanagedType
.LPWStr
)]StringBuilder bufDigits
,
1405 int bufSize
, out int decPos
, out int sign
);
1407 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1408 [DllImport("libdec", EntryPoint
="string2decimal")]
1409 internal static extern int string2decimal (out Decimal val
,
1410 [MarshalAs(UnmanagedType
.LPWStr
)]String sDigits
,
1411 uint decPos
, int sign
);
1413 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1414 [DllImport("libdec", EntryPoint
="decimalSetExponent")]
1415 internal static extern int decimalSetExponent (ref Decimal val
, int exp
);
1417 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1418 [DllImport("libdec", EntryPoint
="decimal2double")]
1419 private static extern double decimal2double (ref Decimal val
);
1421 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1422 [DllImport("libdec", EntryPoint
="decimalFloorAndTrunc")]
1423 private static extern void decimalFloorAndTrunc (ref Decimal val
, int floorFlag
);
1425 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1426 [DllImport("libdec", EntryPoint
="decimalRound")]
1427 private static extern void decimalRound (ref Decimal val
, int decimals
);
1429 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1430 [DllImport("libdec", EntryPoint
="decimalMult")]
1431 private static extern int decimalMult (ref Decimal pd1
, ref Decimal pd2
);
1433 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1434 [DllImport("libdec", EntryPoint
="decimalDiv")]
1435 private static extern int decimalDiv (out Decimal pc
, ref Decimal pa
, ref Decimal pb
);
1437 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1438 [DllImport("libdec", EntryPoint
="decimalIntDiv")]
1439 private static extern int decimalIntDiv (out Decimal pc
, ref Decimal pa
, ref Decimal pb
);
1441 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1442 [DllImport("libdec", EntryPoint
="decimalCompare")]
1443 private static extern int decimalCompare (ref Decimal d1
, ref Decimal d2
);