summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Decimal.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Decimal.cs')
-rw-r--r--src/mscorlib/src/System/Decimal.cs1244
1 files changed, 1244 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Decimal.cs b/src/mscorlib/src/System/Decimal.cs
new file mode 100644
index 0000000000..8a2c30ffa8
--- /dev/null
+++ b/src/mscorlib/src/System/Decimal.cs
@@ -0,0 +1,1244 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System {
+
+ using System;
+ using System.Globalization;
+ using System.Runtime.InteropServices;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.ConstrainedExecution;
+ using System.Runtime.Versioning;
+ using System.Runtime.Serialization;
+ using System.Diagnostics.Contracts;
+
+ // Implements the Decimal data type. The Decimal data type can
+ // represent values ranging from -79,228,162,514,264,337,593,543,950,335 to
+ // 79,228,162,514,264,337,593,543,950,335 with 28 significant digits. The
+ // Decimal data type is ideally suited to financial calculations that
+ // require a large number of significant digits and no round-off errors.
+ //
+ // The finite set of values of type Decimal are of the form m
+ // / 10e, where m is an integer such that
+ // -296 <; m <; 296, and e is an integer
+ // between 0 and 28 inclusive.
+ //
+ // Contrary to the float and double data types, decimal
+ // fractional numbers such as 0.1 can be represented exactly in the
+ // Decimal representation. In the float and double
+ // representations, such numbers are often infinite fractions, making those
+ // representations more prone to round-off errors.
+ //
+ // The Decimal class implements widening conversions from the
+ // ubyte, char, short, int, and long types
+ // to Decimal. These widening conversions never loose any information
+ // and never throw exceptions. The Decimal class also implements
+ // narrowing conversions from Decimal to ubyte, char,
+ // short, int, and long. These narrowing conversions round
+ // the Decimal value towards zero to the nearest integer, and then
+ // converts that integer to the destination type. An OverflowException
+ // is thrown if the result is not within the range of the destination type.
+ //
+ // The Decimal class provides a widening conversion from
+ // Currency to Decimal. This widening conversion never loses any
+ // information and never throws exceptions. The Currency class provides
+ // a narrowing conversion from Decimal to Currency. This
+ // narrowing conversion rounds the Decimal to four decimals and then
+ // converts that number to a Currency. An OverflowException
+ // is thrown if the result is not within the range of the Currency type.
+ //
+ // The Decimal class provides narrowing conversions to and from the
+ // float and double types. A conversion from Decimal to
+ // float or double may loose precision, but will not loose
+ // information about the overall magnitude of the numeric value, and will never
+ // throw an exception. A conversion from float or double to
+ // Decimal throws an OverflowException if the value is not within
+ // the range of the Decimal type.
+ [StructLayout(LayoutKind.Sequential)]
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.Versioning.NonVersionable] // This only applies to field layout
+ public struct Decimal : IFormattable, IComparable, IConvertible, IComparable<Decimal>, IEquatable<Decimal>, IDeserializationCallback
+ {
+
+ // Sign mask for the flags field. A value of zero in this bit indicates a
+ // positive Decimal value, and a value of one in this bit indicates a
+ // negative Decimal value.
+ //
+ // Look at OleAut's DECIMAL_NEG constant to check for negative values
+ // in native code.
+ private const int SignMask = unchecked((int)0x80000000);
+ private const byte DECIMAL_NEG = 0x80;
+ private const byte DECIMAL_ADD = 0x00;
+
+ // Scale mask for the flags field. This byte in the flags field contains
+ // the power of 10 to divide the Decimal value by. The scale byte must
+ // contain a value between 0 and 28 inclusive.
+ private const int ScaleMask = 0x00FF0000;
+
+ // Number of bits scale is shifted by.
+ private const int ScaleShift = 16;
+
+ // The maximum power of 10 that a 32 bit integer can store
+ private const Int32 MaxInt32Scale = 9;
+
+ // Fast access for 10^n where n is 0-9
+ private static UInt32[] Powers10 = new UInt32[] {
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000
+ };
+
+ // Constant representing the Decimal value 0.
+ public const Decimal Zero = 0m;
+
+ // Constant representing the Decimal value 1.
+ public const Decimal One = 1m;
+
+ // Constant representing the Decimal value -1.
+ public const Decimal MinusOne = -1m;
+
+ // Constant representing the largest possible Decimal value. The value of
+ // this constant is 79,228,162,514,264,337,593,543,950,335.
+ public const Decimal MaxValue = 79228162514264337593543950335m;
+
+ // Constant representing the smallest possible Decimal value. The value of
+ // this constant is -79,228,162,514,264,337,593,543,950,335.
+ public const Decimal MinValue = -79228162514264337593543950335m;
+
+
+ // Constant representing the negative number that is the closest possible
+ // Decimal value to -0m.
+ private const Decimal NearNegativeZero = -0.000000000000000000000000001m;
+
+ // Constant representing the positive number that is the closest possible
+ // Decimal value to +0m.
+ private const Decimal NearPositiveZero = +0.000000000000000000000000001m;
+
+ // The lo, mid, hi, and flags fields contain the representation of the
+ // Decimal value. The lo, mid, and hi fields contain the 96-bit integer
+ // part of the Decimal. Bits 0-15 (the lower word) of the flags field are
+ // unused and must be zero; bits 16-23 contain must contain a value between
+ // 0 and 28, indicating the power of 10 to divide the 96-bit integer part
+ // by to produce the Decimal value; bits 24-30 are unused and must be zero;
+ // and finally bit 31 indicates the sign of the Decimal value, 0 meaning
+ // positive and 1 meaning negative.
+ //
+ // NOTE: Do not change the order in which these fields are declared. The
+ // native methods in this class rely on this particular order.
+ private int flags;
+ private int hi;
+ private int lo;
+ private int mid;
+
+
+ // Constructs a zero Decimal.
+ //public Decimal() {
+ // lo = 0;
+ // mid = 0;
+ // hi = 0;
+ // flags = 0;
+ //}
+
+ // Constructs a Decimal from an integer value.
+ //
+ public Decimal(int value) {
+ // JIT today can't inline methods that contains "starg" opcode.
+ // For more details, see DevDiv Bugs 81184: x86 JIT CQ: Removing the inline striction of "starg".
+ int value_copy = value;
+ if (value_copy >= 0) {
+ flags = 0;
+ }
+ else {
+ flags = SignMask;
+ value_copy = -value_copy;
+ }
+ lo = value_copy;
+ mid = 0;
+ hi = 0;
+ }
+
+ // Constructs a Decimal from an unsigned integer value.
+ //
+ [CLSCompliant(false)]
+ public Decimal(uint value) {
+ flags = 0;
+ lo = (int) value;
+ mid = 0;
+ hi = 0;
+ }
+
+ // Constructs a Decimal from a long value.
+ //
+ public Decimal(long value) {
+ // JIT today can't inline methods that contains "starg" opcode.
+ // For more details, see DevDiv Bugs 81184: x86 JIT CQ: Removing the inline striction of "starg".
+ long value_copy = value;
+ if (value_copy >= 0) {
+ flags = 0;
+ }
+ else {
+ flags = SignMask;
+ value_copy = -value_copy;
+ }
+ lo = (int)value_copy;
+ mid = (int)(value_copy >> 32);
+ hi = 0;
+ }
+
+ // Constructs a Decimal from an unsigned long value.
+ //
+ [CLSCompliant(false)]
+ public Decimal(ulong value) {
+ flags = 0;
+ lo = (int)value;
+ mid = (int)(value >> 32);
+ hi = 0;
+ }
+
+ // Constructs a Decimal from a float value.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern Decimal(float value);
+
+ // Constructs a Decimal from a double value.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern Decimal(double value);
+
+ // Constructs a Decimal from a Currency value.
+ //
+ internal Decimal(Currency value) {
+ this = Currency.ToDecimal(value);
+ }
+
+ // Don't remove these 2 methods below. They are required by the fx when the are dealing with Currency in their
+ // databases
+ public static long ToOACurrency(Decimal value)
+ {
+ return new Currency(value).ToOACurrency();
+ }
+
+ public static Decimal FromOACurrency(long cy)
+ {
+ return Currency.ToDecimal(Currency.FromOACurrency(cy));
+ }
+
+
+ // Constructs a Decimal from an integer array containing a binary
+ // representation. The bits argument must be a non-null integer
+ // array with four elements. bits[0], bits[1], and
+ // bits[2] contain the low, middle, and high 32 bits of the 96-bit
+ // integer part of the Decimal. bits[3] contains the scale factor
+ // and sign of the Decimal: bits 0-15 (the lower word) are unused and must
+ // be zero; bits 16-23 must contain a value between 0 and 28, indicating
+ // the power of 10 to divide the 96-bit integer part by to produce the
+ // Decimal value; bits 24-30 are unused and must be zero; and finally bit
+ // 31 indicates the sign of the Decimal value, 0 meaning positive and 1
+ // meaning negative.
+ //
+ // Note that there are several possible binary representations for the
+ // same numeric value. For example, the value 1 can be represented as {1,
+ // 0, 0, 0} (integer value 1 with a scale factor of 0) and equally well as
+ // {1000, 0, 0, 0x30000} (integer value 1000 with a scale factor of 3).
+ // The possible binary representations of a particular value are all
+ // equally valid, and all are numerically equivalent.
+ //
+ public Decimal(int[] bits) {
+ this.lo = 0;
+ this.mid = 0;
+ this.hi = 0;
+ this.flags = 0;
+ SetBits(bits);
+ }
+
+ private void SetBits(int[] bits) {
+ if (bits==null)
+ throw new ArgumentNullException("bits");
+ Contract.EndContractBlock();
+ if (bits.Length == 4) {
+ int f = bits[3];
+ if ((f & ~(SignMask | ScaleMask)) == 0 && (f & ScaleMask) <= (28 << 16)) {
+ lo = bits[0];
+ mid = bits[1];
+ hi = bits[2];
+ flags = f;
+ return;
+ }
+ }
+ throw new ArgumentException(Environment.GetResourceString("Arg_DecBitCtor"));
+ }
+
+ // Constructs a Decimal from its constituent parts.
+ //
+ public Decimal(int lo, int mid, int hi, bool isNegative, byte scale) {
+ if (scale > 28)
+ throw new ArgumentOutOfRangeException("scale", Environment.GetResourceString("ArgumentOutOfRange_DecimalScale"));
+ Contract.EndContractBlock();
+ this.lo = lo;
+ this.mid = mid;
+ this.hi = hi;
+ this.flags = ((int)scale) << 16;
+ if (isNegative)
+ this.flags |= SignMask;
+ }
+
+ [OnSerializing]
+ void OnSerializing(StreamingContext ctx) {
+ // OnSerializing is called before serialization of an object
+ try {
+ SetBits( GetBits(this) );
+ } catch (ArgumentException e) {
+ throw new SerializationException(Environment.GetResourceString("Overflow_Decimal"), e);
+ }
+ }
+
+ void IDeserializationCallback.OnDeserialization(Object sender) {
+ // OnDeserialization is called after each instance of this class is deserialized.
+ // This callback method performs decimal validation after being deserialized.
+ try {
+ SetBits( GetBits(this) );
+ } catch (ArgumentException e) {
+ throw new SerializationException(Environment.GetResourceString("Overflow_Decimal"), e);
+ }
+ }
+
+ // Constructs a Decimal from its constituent parts.
+ private Decimal(int lo, int mid, int hi, int flags) {
+ if ((flags & ~(SignMask | ScaleMask)) == 0 && (flags & ScaleMask) <= (28 << 16)) {
+ this.lo = lo;
+ this.mid = mid;
+ this.hi = hi;
+ this.flags = flags;
+ return;
+ }
+ throw new ArgumentException(Environment.GetResourceString("Arg_DecBitCtor"));
+ }
+
+ // Returns the absolute value of the given Decimal. If d is
+ // positive, the result is d. If d is negative, the result
+ // is -d.
+ //
+ internal static Decimal Abs(Decimal d) {
+ return new Decimal(d.lo, d.mid, d.hi, d.flags & ~SignMask);
+ }
+
+ // Adds two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Add(Decimal d1, Decimal d2)
+ {
+ FCallAddSub (ref d1, ref d2, DECIMAL_ADD);
+ return d1;
+ }
+
+ // FCallAddSub adds or subtracts two decimal values. On return, d1 contains the result
+ // of the operation. Passing in DECIMAL_ADD or DECIMAL_NEG for bSign indicates
+ // addition or subtraction, respectively.
+ //
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallAddSub(ref Decimal d1, ref Decimal d2, byte bSign);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallAddSubOverflowed(ref Decimal d1, ref Decimal d2, byte bSign, ref bool overflowed);
+
+ // Rounds a Decimal to an integer value. The Decimal argument is rounded
+ // towards positive infinity.
+ public static Decimal Ceiling(Decimal d) {
+ return (-(Decimal.Floor(-d)));
+ }
+
+ // Compares two Decimal values, returning an integer that indicates their
+ // relationship.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ public static int Compare(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2);
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ private static extern int FCallCompare(ref Decimal d1, ref Decimal d2);
+
+ // Compares this object to another object, returning an integer that
+ // indicates the relationship.
+ // Returns a value less than zero if this object
+ // null is considered to be less than any instance.
+ // If object is not of type Decimal, this method throws an ArgumentException.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public int CompareTo(Object value)
+ {
+ if (value == null)
+ return 1;
+ if (!(value is Decimal))
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDecimal"));
+
+ Decimal other = (Decimal)value;
+ return FCallCompare(ref this, ref other);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public int CompareTo(Decimal value)
+ {
+ return FCallCompare(ref this, ref value);
+ }
+
+ // Divides two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Divide(Decimal d1, Decimal d2)
+ {
+ FCallDivide (ref d1, ref d2);
+ return d1;
+ }
+
+ // FCallDivide divides two decimal values. On return, d1 contains the result
+ // of the operation.
+ //
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallDivide(ref Decimal d1, ref Decimal d2);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallDivideOverflowed(ref Decimal d1, ref Decimal d2, ref bool overflowed);
+
+
+ // Checks if this Decimal is equal to a given object. Returns true
+ // if the given object is a boxed Decimal and its value is equal to the
+ // value of this Decimal. Returns false otherwise.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public override bool Equals(Object value) {
+ if (value is Decimal) {
+ Decimal other = (Decimal)value;
+ return FCallCompare(ref this, ref other) == 0;
+ }
+ return false;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public bool Equals(Decimal value)
+ {
+ return FCallCompare(ref this, ref value) == 0;
+ }
+
+ // Returns the hash code for this Decimal.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern override int GetHashCode();
+
+ // Compares two Decimal values for equality. Returns true if the two
+ // Decimal values are equal, or false if they are not equal.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool Equals(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) == 0;
+ }
+
+ // Rounds a Decimal to an integer value. The Decimal argument is rounded
+ // towards negative infinity.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Floor(Decimal d)
+ {
+ FCallFloor (ref d);
+ return d;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallFloor(ref Decimal d);
+
+ // Converts this Decimal to a string. The resulting string consists of an
+ // optional minus sign ("-") followed to a sequence of digits ("0" - "9"),
+ // optionally followed by a decimal point (".") and another sequence of
+ // digits.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public override String ToString() {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public String ToString(String format) {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return Number.FormatDecimal(this, format, NumberFormatInfo.CurrentInfo);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public String ToString(IFormatProvider provider) {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return Number.FormatDecimal(this, null, NumberFormatInfo.GetInstance(provider));
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public String ToString(String format, IFormatProvider provider) {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider));
+ }
+
+
+ // Converts a string to a Decimal. The string must consist of an optional
+ // minus sign ("-") followed by a sequence of digits ("0" - "9"). The
+ // sequence of digits may optionally contain a single decimal point (".")
+ // character. Leading and trailing whitespace characters are allowed.
+ // Parse also allows a currency symbol, a trailing negative sign, and
+ // parentheses in the number.
+ //
+ public static Decimal Parse(String s) {
+ return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo);
+ }
+
+ public static Decimal Parse(String s, NumberStyles style) {
+ NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
+ return Number.ParseDecimal(s, style, NumberFormatInfo.CurrentInfo);
+ }
+
+ public static Decimal Parse(String s, IFormatProvider provider) {
+ return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider));
+ }
+
+ public static Decimal Parse(String s, NumberStyles style, IFormatProvider provider) {
+ NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
+ return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
+ }
+
+ public static Boolean TryParse(String s, out Decimal result) {
+ return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result);
+ }
+
+ public static Boolean TryParse(String s, NumberStyles style, IFormatProvider provider, out Decimal result) {
+ NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
+ return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result);
+ }
+
+ // Returns a binary representation of a Decimal. The return value is an
+ // integer array with four elements. Elements 0, 1, and 2 contain the low,
+ // middle, and high 32 bits of the 96-bit integer part of the Decimal.
+ // Element 3 contains the scale factor and sign of the Decimal: bits 0-15
+ // (the lower word) are unused; bits 16-23 contain a value between 0 and
+ // 28, indicating the power of 10 to divide the 96-bit integer part by to
+ // produce the Decimal value; bits 24-30 are unused; and finally bit 31
+ // indicates the sign of the Decimal value, 0 meaning positive and 1
+ // meaning negative.
+ //
+ public static int[] GetBits(Decimal d) {
+ return new int[] {d.lo, d.mid, d.hi, d.flags};
+ }
+
+ internal static void GetBytes(Decimal d, byte [] buffer) {
+ Contract.Requires((buffer != null && buffer.Length >= 16), "[GetBytes]buffer != null && buffer.Length >= 16");
+ buffer[0] = (byte) d.lo;
+ buffer[1] = (byte) (d.lo >> 8);
+ buffer[2] = (byte) (d.lo >> 16);
+ buffer[3] = (byte) (d.lo >> 24);
+
+ buffer[4] = (byte) d.mid;
+ buffer[5] = (byte) (d.mid >> 8);
+ buffer[6] = (byte) (d.mid >> 16);
+ buffer[7] = (byte) (d.mid >> 24);
+
+ buffer[8] = (byte) d.hi;
+ buffer[9] = (byte) (d.hi >> 8);
+ buffer[10] = (byte) (d.hi >> 16);
+ buffer[11] = (byte) (d.hi >> 24);
+
+ buffer[12] = (byte) d.flags;
+ buffer[13] = (byte) (d.flags >> 8);
+ buffer[14] = (byte) (d.flags >> 16);
+ buffer[15] = (byte) (d.flags >> 24);
+ }
+
+ internal static decimal ToDecimal(byte [] buffer) {
+ Contract.Requires((buffer != null && buffer.Length >= 16), "[ToDecimal]buffer != null && buffer.Length >= 16");
+ int lo = ((int)buffer[0]) | ((int)buffer[1] << 8) | ((int)buffer[2] << 16) | ((int)buffer[3] << 24);
+ int mid = ((int)buffer[4]) | ((int)buffer[5] << 8) | ((int)buffer[6] << 16) | ((int)buffer[7] << 24);
+ int hi = ((int)buffer[8]) | ((int)buffer[9] << 8) | ((int)buffer[10] << 16) | ((int)buffer[11] << 24);
+ int flags = ((int)buffer[12]) | ((int)buffer[13] << 8) | ((int)buffer[14] << 16) | ((int)buffer[15] << 24);
+ return new Decimal(lo,mid,hi,flags);
+ }
+
+ // This method does a 'raw' and 'unchecked' addition of a UInt32 to a Decimal in place.
+ // 'raw' means that it operates on the internal 96-bit unsigned integer value and
+ // ingores the sign and scale. This means that it is not equivalent to just adding
+ // that number, as the sign and scale are effectively applied to the UInt32 value also.
+ // 'unchecked' means that it does not fail if you overflow the 96 bit value.
+ private static void InternalAddUInt32RawUnchecked(ref Decimal value, UInt32 i) {
+ UInt32 v;
+ UInt32 sum;
+ v = (UInt32)value.lo;
+ sum = v + i;
+ value.lo = (Int32)sum;
+ if (sum < v || sum < i) {
+ v = (UInt32)value.mid;
+ sum = v + 1;
+ value.mid = (Int32)sum;
+ if (sum < v || sum < 1) {
+ value.hi = (Int32) ((UInt32)value.hi + 1);
+ }
+ }
+ }
+
+ // This method does an in-place division of a decimal by a UInt32, returning the remainder.
+ // Although it does not operate on the sign or scale, this does not result in any
+ // caveat for the result. It is equivalent to dividing by that number.
+ private static UInt32 InternalDivRemUInt32(ref Decimal value, UInt32 divisor) {
+ UInt32 remainder = 0;
+ UInt64 n;
+ if (value.hi != 0) {
+ n = ((UInt32) value.hi);
+ value.hi = (Int32)((UInt32)(n / divisor));
+ remainder = (UInt32)(n % divisor);
+ }
+ if (value.mid != 0 || remainder != 0) {
+ n = ((UInt64)remainder << 32) | (UInt32) value.mid;
+ value.mid = (Int32)((UInt32)(n / divisor));
+ remainder = (UInt32)(n % divisor);
+ }
+ if (value.lo != 0 || remainder != 0) {
+ n = ((UInt64)remainder << 32) | (UInt32) value.lo;
+ value.lo = (Int32)((UInt32)(n / divisor));
+ remainder = (UInt32)(n % divisor);
+ }
+ return remainder;
+ }
+
+ // Does an in-place round the specified number of digits, rounding mid-point values
+ // away from zero
+ private static void InternalRoundFromZero(ref Decimal d, int decimalCount) {
+ Int32 scale = (d.flags & ScaleMask) >> ScaleShift;
+ Int32 scaleDifference = scale - decimalCount;
+ if (scaleDifference <= 0) {
+ return;
+ }
+ // Divide the value by 10^scaleDifference
+ UInt32 lastRemainder;
+ UInt32 lastDivisor;
+ do {
+ Int32 diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
+ lastDivisor = Powers10[diffChunk];
+ lastRemainder = InternalDivRemUInt32(ref d, lastDivisor);
+ scaleDifference -= diffChunk;
+ } while (scaleDifference > 0);
+
+ // Round away from zero at the mid point
+ if (lastRemainder >= (lastDivisor >> 1)) {
+ InternalAddUInt32RawUnchecked(ref d, 1);
+ }
+
+ // the scale becomes the desired decimal count
+ d.flags = ((decimalCount << ScaleShift) & ScaleMask) | (d.flags & SignMask);
+ }
+
+ // Returns the larger of two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ internal static Decimal Max(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) >= 0? d1: d2;
+ }
+
+ // Returns the smaller of two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ internal static Decimal Min(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) < 0? d1: d2;
+ }
+
+ public static Decimal Remainder(Decimal d1, Decimal d2) {
+ // OleAut doesn't provide a VarDecMod.
+
+ // In the operation x % y the sign of y does not matter. Result will have the sign of x.
+ d2.flags = (d2.flags & ~SignMask) | (d1.flags & SignMask);
+
+
+ // This piece of code is to work around the fact that Dividing a decimal with 28 digits number by decimal which causes
+ // causes the result to be 28 digits, can cause to be incorrectly rounded up.
+ // eg. Decimal.MaxValue / 2 * Decimal.MaxValue will overflow since the division by 2 was rounded instead of being truncked.
+ if (Abs(d1) < Abs(d2)) {
+ return d1;
+ }
+ d1 -= d2;
+
+ if (d1 == 0) {
+ // The sign of D1 will be wrong here. Fall through so that we still get a DivideByZeroException
+ d1.flags = (d1.flags & ~SignMask) | (d2.flags & SignMask);
+ }
+
+ // Formula: d1 - (RoundTowardsZero(d1 / d2) * d2)
+ Decimal dividedResult = Truncate(d1/d2);
+ Decimal multipliedResult = dividedResult * d2;
+ Decimal result = d1 - multipliedResult;
+ // See if the result has crossed 0
+ if ((d1.flags & SignMask) != (result.flags & SignMask)) {
+
+ if (NearNegativeZero <= result && result <= NearPositiveZero) {
+ // Certain Remainder operations on decimals with 28 significant digits round
+ // to [+-]0.000000000000000000000000001m instead of [+-]0m during the intermediate calculations.
+ // 'zero' results just need their sign corrected.
+ result.flags = (result.flags & ~SignMask) | (d1.flags & SignMask);
+ }
+ else {
+ // If the division rounds up because it runs out of digits, the multiplied result can end up with a larger
+ // absolute value and the result of the formula crosses 0. To correct it can add the divisor back.
+ result += d2;
+ }
+ }
+
+ return result;
+ }
+
+ // Multiplies two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Multiply(Decimal d1, Decimal d2)
+ {
+ FCallMultiply (ref d1, ref d2);
+ return d1;
+ }
+
+ // FCallMultiply multiples two decimal values. On return, d1 contains the result
+ // of the operation.
+ //
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallMultiply(ref Decimal d1, ref Decimal d2);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallMultiplyOverflowed(ref Decimal d1, ref Decimal d2, ref bool overflowed);
+
+ // Returns the negated value of the given Decimal. If d is non-zero,
+ // the result is -d. If d is zero, the result is zero.
+ //
+ public static Decimal Negate(Decimal d) {
+ return new Decimal(d.lo, d.mid, d.hi, d.flags ^ SignMask);
+ }
+
+ // Rounds a Decimal value to a given number of decimal places. The value
+ // given by d is rounded to the number of decimal places given by
+ // decimals. The decimals argument must be an integer between
+ // 0 and 28 inclusive.
+ //
+ // By default a mid-point value is rounded to the nearest even number. If the mode is
+ // passed in, it can also round away from zero.
+
+ public static Decimal Round(Decimal d) {
+ return Round(d, 0);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Round(Decimal d, int decimals)
+ {
+ FCallRound (ref d, decimals);
+ return d;
+ }
+
+ public static Decimal Round(Decimal d, MidpointRounding mode) {
+ return Round(d, 0, mode);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Round(Decimal d, int decimals, MidpointRounding mode) {
+ if ((decimals < 0) || (decimals > 28))
+ throw new ArgumentOutOfRangeException("decimals", Environment.GetResourceString("ArgumentOutOfRange_DecimalRound"));
+ if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", mode, "MidpointRounding"), "mode");
+ }
+ Contract.EndContractBlock();
+
+ if (mode == MidpointRounding.ToEven) {
+ FCallRound (ref d, decimals);
+ }
+ else {
+ InternalRoundFromZero(ref d, decimals);
+ }
+ return d;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallRound(ref Decimal d, int decimals);
+
+ // Subtracts two Decimal values.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Subtract(Decimal d1, Decimal d2)
+ {
+ FCallAddSub(ref d1, ref d2, DECIMAL_NEG);
+ return d1;
+ }
+
+ // Converts a Decimal to an unsigned byte. The Decimal value is rounded
+ // towards zero to the nearest integer value, and the result of this
+ // operation is returned as a byte.
+ //
+ public static byte ToByte(Decimal value) {
+ uint temp;
+ try {
+ temp = ToUInt32(value);
+ }
+ catch (OverflowException e) {
+ throw new OverflowException(Environment.GetResourceString("Overflow_Byte"), e);
+ }
+ if (temp < Byte.MinValue || temp > Byte.MaxValue) throw new OverflowException(Environment.GetResourceString("Overflow_Byte"));
+ return (byte)temp;
+
+ }
+
+ // Converts a Decimal to a signed byte. The Decimal value is rounded
+ // towards zero to the nearest integer value, and the result of this
+ // operation is returned as a byte.
+ //
+ [CLSCompliant(false)]
+ public static sbyte ToSByte(Decimal value) {
+ int temp;
+ try {
+ temp = ToInt32(value);
+ }
+ catch (OverflowException e) {
+ throw new OverflowException(Environment.GetResourceString("Overflow_SByte"), e);
+ }
+ if (temp < SByte.MinValue || temp > SByte.MaxValue) throw new OverflowException(Environment.GetResourceString("Overflow_SByte"));
+ return (sbyte)temp;
+ }
+
+ // Converts a Decimal to a short. The Decimal value is
+ // rounded towards zero to the nearest integer value, and the result of
+ // this operation is returned as a short.
+ //
+ public static short ToInt16(Decimal value) {
+ int temp;
+ try {
+ temp = ToInt32(value);
+ }
+ catch (OverflowException e) {
+ throw new OverflowException(Environment.GetResourceString("Overflow_Int16"), e);
+ }
+ if (temp < Int16.MinValue || temp > Int16.MaxValue) throw new OverflowException(Environment.GetResourceString("Overflow_Int16"));
+ return (short)temp;
+ }
+
+
+ // Converts a Decimal to a Currency. Since a Currency
+ // has fewer significant digits than a Decimal, this operation may
+ // produce round-off errors.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ internal static Currency ToCurrency(Decimal d)
+ {
+ Currency result = new Currency ();
+ FCallToCurrency (ref result, d);
+ return result;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallToCurrency(ref Currency result, Decimal d);
+
+ // Converts a Decimal to a double. Since a double has fewer significant
+ // digits than a Decimal, this operation may produce round-off errors.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern double ToDouble(Decimal d);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern int FCallToInt32(Decimal d);
+
+ // Converts a Decimal to an integer. The Decimal value is rounded towards
+ // zero to the nearest integer value, and the result of this operation is
+ // returned as an integer.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static int ToInt32(Decimal d) {
+ if ((d.flags & ScaleMask) != 0) FCallTruncate (ref d);
+ if (d.hi == 0 && d.mid == 0) {
+ int i = d.lo;
+ if (d.flags >= 0) {
+ if (i >= 0) return i;
+ }
+ else {
+ i = -i;
+ if (i <= 0) return i;
+ }
+ }
+ throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
+ }
+
+ // Converts a Decimal to a long. The Decimal value is rounded towards zero
+ // to the nearest integer value, and the result of this operation is
+ // returned as a long.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static long ToInt64(Decimal d) {
+ if ((d.flags & ScaleMask) != 0) FCallTruncate (ref d);
+ if (d.hi == 0) {
+ long l = d.lo & 0xFFFFFFFFL | (long)d.mid << 32;
+ if (d.flags >= 0) {
+ if (l >= 0) return l;
+ }
+ else {
+ l = -l;
+ if (l <= 0) return l;
+ }
+ }
+ throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
+ }
+
+ // Converts a Decimal to an ushort. The Decimal
+ // value is rounded towards zero to the nearest integer value, and the
+ // result of this operation is returned as an ushort.
+ //
+ [CLSCompliant(false)]
+ public static ushort ToUInt16(Decimal value) {
+ uint temp;
+ try {
+ temp = ToUInt32(value);
+ }
+ catch (OverflowException e) {
+ throw new OverflowException(Environment.GetResourceString("Overflow_UInt16"), e);
+ }
+ if (temp < UInt16.MinValue || temp > UInt16.MaxValue) throw new OverflowException(Environment.GetResourceString("Overflow_UInt16"));
+ return (ushort)temp;
+ }
+
+ // Converts a Decimal to an unsigned integer. The Decimal
+ // value is rounded towards zero to the nearest integer value, and the
+ // result of this operation is returned as an unsigned integer.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [CLSCompliant(false)]
+ public static uint ToUInt32(Decimal d) {
+ if ((d.flags & ScaleMask) != 0) FCallTruncate (ref d);
+ if (d.hi == 0 && d.mid == 0) {
+ uint i = (uint) d.lo;
+ if (d.flags >= 0 || i == 0)
+ return i;
+ }
+ throw new OverflowException(Environment.GetResourceString("Overflow_UInt32"));
+ }
+
+ // Converts a Decimal to an unsigned long. The Decimal
+ // value is rounded towards zero to the nearest integer value, and the
+ // result of this operation is returned as a long.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [CLSCompliant(false)]
+ public static ulong ToUInt64(Decimal d) {
+ if ((d.flags & ScaleMask) != 0) FCallTruncate (ref d);
+ if (d.hi == 0) {
+ ulong l = ((ulong)(uint)d.lo) | ((ulong)(uint)d.mid << 32);
+ if (d.flags >= 0 || l == 0)
+ return l;
+ }
+ throw new OverflowException(Environment.GetResourceString("Overflow_UInt64"));
+ }
+
+ // Converts a Decimal to a float. Since a float has fewer significant
+ // digits than a Decimal, this operation may produce round-off errors.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern float ToSingle(Decimal d);
+
+ // Truncates a Decimal to an integer value. The Decimal argument is rounded
+ // towards zero to the nearest integer value, corresponding to removing all
+ // digits after the decimal point.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal Truncate(Decimal d)
+ {
+ FCallTruncate (ref d);
+ return d;
+ }
+
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FCallTruncate(ref Decimal d);
+
+
+ public static implicit operator Decimal(byte value) {
+ return new Decimal(value);
+ }
+
+ [CLSCompliant(false)]
+ public static implicit operator Decimal(sbyte value) {
+ return new Decimal(value);
+ }
+
+ public static implicit operator Decimal(short value) {
+ return new Decimal(value);
+ }
+
+ [CLSCompliant(false)]
+ public static implicit operator Decimal(ushort value) {
+ return new Decimal(value);
+ }
+
+ public static implicit operator Decimal(char value) {
+ return new Decimal(value);
+ }
+
+ public static implicit operator Decimal(int value) {
+ return new Decimal(value);
+ }
+
+ [CLSCompliant(false)]
+ public static implicit operator Decimal(uint value) {
+ return new Decimal(value);
+ }
+
+ public static implicit operator Decimal(long value) {
+ return new Decimal(value);
+ }
+
+ [CLSCompliant(false)]
+ public static implicit operator Decimal(ulong value) {
+ return new Decimal(value);
+ }
+
+
+ public static explicit operator Decimal(float value) {
+ return new Decimal(value);
+ }
+
+ public static explicit operator Decimal(double value) {
+ return new Decimal(value);
+ }
+
+ public static explicit operator byte(Decimal value) {
+ return ToByte(value);
+ }
+
+ [CLSCompliant(false)]
+ public static explicit operator sbyte(Decimal value) {
+ return ToSByte(value);
+ }
+
+ public static explicit operator char(Decimal value) {
+ UInt16 temp;
+ try {
+ temp = ToUInt16(value);
+ }
+ catch (OverflowException e) {
+ throw new OverflowException(Environment.GetResourceString("Overflow_Char"), e);
+ }
+ return (char)temp;
+ }
+
+ public static explicit operator short(Decimal value) {
+ return ToInt16(value);
+ }
+
+ [CLSCompliant(false)]
+ public static explicit operator ushort(Decimal value) {
+ return ToUInt16(value);
+ }
+
+ public static explicit operator int(Decimal value) {
+ return ToInt32(value);
+ }
+
+ [CLSCompliant(false)]
+ public static explicit operator uint(Decimal value) {
+ return ToUInt32(value);
+ }
+
+ public static explicit operator long(Decimal value) {
+ return ToInt64(value);
+ }
+
+ [CLSCompliant(false)]
+ public static explicit operator ulong(Decimal value) {
+ return ToUInt64(value);
+ }
+
+ public static explicit operator float(Decimal value) {
+ return ToSingle(value);
+ }
+
+ public static explicit operator double(Decimal value) {
+ return ToDouble(value);
+ }
+
+ public static Decimal operator +(Decimal d) {
+ return d;
+ }
+
+ public static Decimal operator -(Decimal d) {
+ return Negate(d);
+ }
+
+ public static Decimal operator ++(Decimal d) {
+ return Add(d, One);
+ }
+
+ public static Decimal operator --(Decimal d) {
+ return Subtract(d, One);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal operator +(Decimal d1, Decimal d2) {
+ FCallAddSub(ref d1, ref d2, DECIMAL_ADD);
+ return d1;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal operator -(Decimal d1, Decimal d2) {
+ FCallAddSub(ref d1, ref d2, DECIMAL_NEG);
+ return d1;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal operator *(Decimal d1, Decimal d2) {
+ FCallMultiply (ref d1, ref d2);
+ return d1;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static Decimal operator /(Decimal d1, Decimal d2) {
+ FCallDivide (ref d1, ref d2);
+ return d1;
+ }
+
+ public static Decimal operator %(Decimal d1, Decimal d2) {
+ return Remainder(d1, d2);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator ==(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) == 0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator !=(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) != 0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator <(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) < 0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator <=(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) <= 0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator >(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) > 0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static bool operator >=(Decimal d1, Decimal d2) {
+ return FCallCompare(ref d1, ref d2) >= 0;
+ }
+
+ //
+ // IConvertible implementation
+ //
+
+ public TypeCode GetTypeCode() {
+ return TypeCode.Decimal;
+ }
+
+ /// <internalonly/>
+ bool IConvertible.ToBoolean(IFormatProvider provider) {
+ return Convert.ToBoolean(this);
+ }
+
+
+ /// <internalonly/>
+ char IConvertible.ToChar(IFormatProvider provider) {
+ throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "Decimal", "Char"));
+ }
+
+ /// <internalonly/>
+ sbyte IConvertible.ToSByte(IFormatProvider provider) {
+ return Convert.ToSByte(this);
+ }
+
+ /// <internalonly/>
+ byte IConvertible.ToByte(IFormatProvider provider) {
+ return Convert.ToByte(this);
+ }
+
+ /// <internalonly/>
+ short IConvertible.ToInt16(IFormatProvider provider) {
+ return Convert.ToInt16(this);
+ }
+
+ /// <internalonly/>
+ ushort IConvertible.ToUInt16(IFormatProvider provider) {
+ return Convert.ToUInt16(this);
+ }
+
+ /// <internalonly/>
+ int IConvertible.ToInt32(IFormatProvider provider) {
+ return Convert.ToInt32(this);
+ }
+
+ /// <internalonly/>
+ uint IConvertible.ToUInt32(IFormatProvider provider) {
+ return Convert.ToUInt32(this);
+ }
+
+ /// <internalonly/>
+ long IConvertible.ToInt64(IFormatProvider provider) {
+ return Convert.ToInt64(this);
+ }
+
+ /// <internalonly/>
+ ulong IConvertible.ToUInt64(IFormatProvider provider) {
+ return Convert.ToUInt64(this);
+ }
+
+ /// <internalonly/>
+ float IConvertible.ToSingle(IFormatProvider provider) {
+ return Convert.ToSingle(this);
+ }
+
+ /// <internalonly/>
+ double IConvertible.ToDouble(IFormatProvider provider) {
+ return Convert.ToDouble(this);
+ }
+
+ /// <internalonly/>
+ Decimal IConvertible.ToDecimal(IFormatProvider provider) {
+ return this;
+ }
+
+ /// <internalonly/>
+ DateTime IConvertible.ToDateTime(IFormatProvider provider) {
+ throw new InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo", "Decimal", "DateTime"));
+ }
+
+ /// <internalonly/>
+ Object IConvertible.ToType(Type type, IFormatProvider provider) {
+ return Convert.DefaultToType((IConvertible)this, type, provider);
+ }
+ }
+}