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
;
41 using System
.Runtime
.InteropServices
;
48 /// Represents a floating-point decimal data type with up to 29 significant
49 /// digits, suitable for financial and commercial calculations
52 public struct Decimal
: IFormattable
, IConvertible
,
54 IComparable
, IComparable
<Decimal
>
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
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
96 public Decimal(int lo
, int mid
, int hi
, bool isNegative
, byte scale
)
104 if (scale
> MAX_SCALE
)
106 throw new ArgumentOutOfRangeException (Locale
.GetText ("scale must be between 0 and 28"));
110 ss32
<<= SCALE_SHIFT
;
111 if (isNegative
) ss32
|= SIGN_FLAG
;
115 public Decimal(int val
)
123 lo32
= ((uint)~val
) + 1;
133 [CLSCompliant(false)]
134 public Decimal(uint val
)
137 ss32
= hi32
= mid32
= 0;
140 public Decimal(long val
)
148 ulong u
= ((ulong)~val
) + 1;
150 mid32
= (uint)(u
>> 32);
155 ulong u
= (ulong)val
;
157 mid32
= (uint)(u
>> 32);
162 [CLSCompliant(false)]
163 public Decimal(ulong 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
);
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
);
203 public Decimal(int[] bits
)
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"));
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
)
237 return new int[] { (int)d
.lo32
, (int)d
.mid32
, (int)d
.hi32
,
242 public static Decimal
Negate(Decimal d
)
249 public static Decimal
Add(Decimal d1
, Decimal d2
)
251 if (decimalIncr(ref d1
, ref d2
) == 0)
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
);
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
)
277 public static Decimal
operator --(Decimal d
)
279 return Add(d
, MinusOne
);
282 public static Decimal
operator ++(Decimal d
)
287 public static Decimal
operator -(Decimal d1
, Decimal d2
)
289 return Subtract(d1
, d2
);
292 public static Decimal
operator -(Decimal d
)
297 public static Decimal
operator +(Decimal 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)
321 decimalFloorAndTrunc (ref value, 0);
322 if (decimal2UInt64 (ref value, out result
) != 0) {
323 throw new System
.OverflowException ();
328 private static long s64 (Decimal
value)
332 decimalFloorAndTrunc (ref value, 0);
333 if (decimal2Int64 (ref value, out result
) != 0) {
334 throw new System
.OverflowException ();
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
)
389 [CLSCompliant(false)]
390 public static explicit operator ulong (Decimal 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
)
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);
526 public static Decimal
Truncate(Decimal d
)
528 decimalFloorAndTrunc(ref d
, 0);
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 ();
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
);
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);
559 // note: here we always work with positive numbers
560 while (scaleDiff
> 0) {
561 if (result
> MaxValueDiv10
)
567 else if (scaleDiff
< 0) {
568 while (scaleDiff
< 0) {
573 result
.ss32
= (uint)((decimals
- scaleDiff
) << SCALE_SHIFT
);
576 result
.ss32 ^
= SIGN_FLAG
;
580 public static Decimal
Multiply (Decimal d1
, Decimal d2
)
582 if (d1
.IsZero () || d2
.IsZero ())
585 if (decimalMult (ref d1
, ref d2
) != 0)
586 throw new OverflowException ();
590 public static Decimal
Divide (Decimal d1
, Decimal d2
)
593 throw new DivideByZeroException ();
599 d1
.ss32 ^
= SIGN_FLAG
;
601 return Decimal
.MinusOne
;
602 d1
.ss32 ^
= SIGN_FLAG
;
605 if (decimalDiv (out result
, ref d1
, ref d2
) != 0)
606 throw new OverflowException ();
611 public static Decimal
Remainder (Decimal d1
, Decimal d2
)
614 throw new DivideByZeroException ();
618 bool negative
= d1
.IsNegative ();
620 d1
.ss32 ^
= SIGN_FLAG
;
621 if (d2
.IsNegative ())
622 d2
.ss32 ^
= SIGN_FLAG
;
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
;
640 result
.ss32 ^
= SIGN_FLAG
;
644 public static int Compare(Decimal d1
, Decimal d2
)
646 return decimalCompare(ref d1
, ref d2
);
649 public int CompareTo(object val
)
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
);
662 public int CompareTo(Decimal
value)
664 return decimalCompare(ref this, ref value);
667 public bool Equals(Decimal
value)
669 return Equals(value, this);
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");
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
);
717 s
= s
.Remove(index
, nfi
.CurrencySymbol
.Length
);
722 string decimalSep
= (hasCurrency
) ? nfi
.CurrencyDecimalSeparator
: nfi
.NumberDecimalSeparator
;
723 string groupSep
= (hasCurrency
) ? nfi
.CurrencyGroupSeparator
: nfi
.NumberGroupSeparator
;
728 StringBuilder sb
= new StringBuilder(len
);
734 if (Char
.IsDigit(ch
))
736 break; // end of leading
738 else if (allowedLeadingWhiteSpace
&& Char
.IsWhiteSpace(ch
))
742 else if (allowedParentheses
&& ch
== '(' && !hasSign
&& !hasOpeningParentheses
)
744 hasOpeningParentheses
= true;
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
)
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
)
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
);
779 throw new FormatException(invalidChar
+ pos
);
784 throw new FormatException(Locale
.GetText ("No digits found"));
790 if (Char
.IsDigit(ch
))
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
);
804 else if (allowedDecimalPoint
&& ch
== decimalSep
[0] && !hasDecimalPoint
)
806 int slen
= decimalSep
.Length
;
807 if (slen
== 1 || s
.IndexOf(decimalSep
, pos
, slen
) == pos
)
810 hasDecimalPoint
= true;
824 if (allowedExponent
&& Char
.ToUpperInvariant (ch
) == 'E')
827 pos
++; if (pos
>= len
) throw new FormatException(invalidExponent
);
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;
848 if (!Char
.IsDigit(ch
)) throw new FormatException(invalidExponent
);
851 while (pos
< len
&& Char
.IsDigit(s
[pos
]))
857 if (isNegativeExp
) exp
*= -1;
865 if (allowedTrailingWhiteSpace
&& Char
.IsWhiteSpace(ch
))
869 else if (allowedParentheses
&& ch
== ')' && hasOpeningParentheses
)
871 hasOpeningParentheses
= false;
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
)
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
)
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
)
910 throw new ArgumentNullException ("s");
912 NumberFormatInfo nfi
= NumberFormatInfo
.GetInstance (provider
);
915 bool isNegative
, expFlag
;
916 s
= stripStyles(s
, style
, nfi
, out iDecPos
, out isNegative
, out expFlag
, out exp
);
919 throw new Exception (Locale
.GetText ("Error in System.Decimal.Parse"));
921 // first we remove leading 0
924 while ((i
< iDecPos
) && (s
[i
] == '0'))
926 if ((i
> 1) && (len
> 1)) {
927 s
= s
.Substring (i
, len
- i
);
931 // first 0. may not be here but is part of the maximum length
932 int max
= ((iDecPos
== 0) ? 27 : 28);
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) {
942 // then we trunc the string
943 if ((len
> max
) && (iDecPos
< len
)) {
944 int round
= (s
[max
] - '0');
945 s
= s
.Substring (0, max
);
951 else if (round
== 5) {
956 // banker rounding applies :(
957 int previous
= (s
[max
- 1] - '0');
958 addone
= ((previous
& 0x01) == 0x01);
962 char[] array
= s
.ToCharArray ();
965 int b
= (array
[p
] - '0');
966 if (array
[p
] != '9') {
967 array
[p
] = (char)(b
+ '1');
974 if ((p
== -1) && (array
[0] == '0')) {
976 s
= "1".PadRight (iDecPos
, '0');
979 s
= new String (array
);
984 // always work in positive (rounding issues)
985 if (string2decimal (out result
, s
, (uint)iDecPos
, 0) != 0)
986 throw new OverflowException ();
989 if (decimalSetExponent (ref result
, exp
) != 0)
990 throw new OverflowException ();
994 result
.ss32 ^
= SIGN_FLAG
;
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
)
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))
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
);
1204 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1205 private static extern int decimal2UInt64(ref Decimal val
,
1208 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
1209 private static extern int decimal2Int64(ref Decimal val
,
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
,
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
);
1251 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1252 [DllImport("libdec", EntryPoint
="decimal2UInt64")]
1253 private static extern int decimal2UInt64(ref Decimal val
,
1256 //![MethodImplAttribute(MethodImplOptions.InternalCall)]
1257 [DllImport("libdec", EntryPoint
="decimal2Int64")]
1258 private static extern int decimal2Int64(ref Decimal val
,
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
,
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
);