The Labs \ Source Viewer \ SSCLI \ System \ Decimal

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System
  16. {
  17.    
  18.     using System;
  19.     using System.Globalization;
  20.     using System.Runtime.InteropServices;
  21.     using System.Runtime.CompilerServices;
  22.     using System.Runtime.ConstrainedExecution;
  23.    
  24.     // Implements the Decimal data type. The Decimal data type can
  25.     // represent values ranging from -79,228,162,514,264,337,593,543,950,335 to
  26.     // 79,228,162,514,264,337,593,543,950,335 with 28 significant digits. The
  27.     // Decimal data type is ideally suited to financial calculations that
  28.     // require a large number of significant digits and no round-off errors.
  29.     //
  30.     // The finite set of values of type Decimal are of the form m
  31.     // / 10e, where m is an integer such that
  32.     // -296 <; m <; 296, and e is an integer
  33.     // between 0 and 28 inclusive.
  34.     //
  35.     // Contrary to the float and double data types, decimal
  36.     // fractional numbers such as 0.1 can be represented exactly in the
  37.     // Decimal representation. In the float and double
  38.     // representations, such numbers are often infinite fractions, making those
  39.     // representations more prone to round-off errors.
  40.     //
  41.     // The Decimal class implements widening conversions from the
  42.     // ubyte, char, short, int, and long types
  43.     // to Decimal. These widening conversions never loose any information
  44.     // and never throw exceptions. The Decimal class also implements
  45.     // narrowing conversions from Decimal to ubyte, char,
  46.     // short, int, and long. These narrowing conversions round
  47.     // the Decimal value towards zero to the nearest integer, and then
  48.     // converts that integer to the destination type. An OverflowException
  49.     // is thrown if the result is not within the range of the destination type.
  50.     //
  51.     // The Decimal class provides a widening conversion from
  52.     // Currency to Decimal. This widening conversion never loses any
  53.     // information and never throws exceptions. The Currency class provides
  54.     // a narrowing conversion from Decimal to Currency. This
  55.     // narrowing conversion rounds the Decimal to four decimals and then
  56.     // converts that number to a Currency. An OverflowException
  57.     // is thrown if the result is not within the range of the Currency type.
  58.     //
  59.     // The Decimal class provides narrowing conversions to and from the
  60.     // float and double types. A conversion from Decimal to
  61.     // float or double may loose precision, but will not loose
  62.     // information about the overall magnitude of the numeric value, and will never
  63.     // throw an exception. A conversion from float or double to
  64.     // Decimal throws an OverflowException if the value is not within
  65.     // the range of the Decimal type.
  66.     [StructLayout(LayoutKind.Sequential)]
  67.     [Serializable()]
  68.     [System.Runtime.InteropServices.ComVisible(true)]
  69.     public struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal>
  70.     {
  71.         // Sign mask for the flags field. A value of zero in this bit indicates a
  72.         // positive Decimal value, and a value of one in this bit indicates a
  73.         // negative Decimal value.
  74.         //
  75.         // Look at OleAut's DECIMAL_NEG constant to check for negative values
  76.         // in native code.
  77.         private const int SignMask = unchecked((int)2147483648u);
  78.        
  79.         // Scale mask for the flags field. This byte in the flags field contains
  80.         // the power of 10 to divide the Decimal value by. The scale byte must
  81.         // contain a value between 0 and 28 inclusive.
  82.         private const int ScaleMask = 16711680;
  83.        
  84.         // Number of bits scale is shifted by.
  85.         private const int ScaleShift = 16;
  86.        
  87.         // The maximum power of 10 that a 32 bit integer can store
  88.         private const Int32 MaxInt32Scale = 9;
  89.        
  90.         // Fast access for 10^n where n is 0-9
  91.         private static UInt32[] Powers10 = new UInt32[] {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
  92.         };
  93.        
  94.         // Constant representing the Decimal value 0.
  95.         public const decimal Zero = 0m;
  96.        
  97.         // Constant representing the Decimal value 1.
  98.         public const decimal One = 1m;
  99.        
  100.         // Constant representing the Decimal value -1.
  101.         public const decimal MinusOne = -1m;
  102.        
  103.         // Constant representing the largest possible Decimal value. The value of
  104.         // this constant is 79,228,162,514,264,337,593,543,950,335.
  105.         public const decimal MaxValue = 79228162514264337593543950335m;
  106.        
  107.         // Constant representing the smallest possible Decimal value. The value of
  108.         // this constant is -79,228,162,514,264,337,593,543,950,335.
  109.         public const decimal MinValue = -79228162514264337593543950335m;
  110.        
  111.         // The lo, mid, hi, and flags fields contain the representation of the
  112.         // Decimal value. The lo, mid, and hi fields contain the 96-bit integer
  113.         // part of the Decimal. Bits 0-15 (the lower word) of the flags field are
  114.         // unused and must be zero; bits 16-23 contain must contain a value between
  115.         // 0 and 28, indicating the power of 10 to divide the 96-bit integer part
  116.         // by to produce the Decimal value; bits 24-30 are unused and must be zero;
  117.         // and finally bit 31 indicates the sign of the Decimal value, 0 meaning
  118.         // positive and 1 meaning negative.
  119.         //
  120.         // NOTE: Do not change the order in which these fields are declared. The
  121.         // native methods in this class rely on this particular order.
  122.         private int flags;
  123.         private int hi;
  124.         private int lo;
  125.         private int mid;
  126.        
  127.         // Constructs a zero Decimal.
  128.         //public Decimal() {
  129.         // lo = 0;
  130.         // mid = 0;
  131.         // hi = 0;
  132.         // flags = 0;
  133.         //}
  134.        
  135.         // Constructs a Decimal from an integer value.
  136.         //
  137.         public Decimal(int value)
  138.         {
  139.             if (value >= 0) {
  140.                 flags = 0;
  141.             }
  142.             else {
  143.                 flags = SignMask;
  144.                 value = -value;
  145.             }
  146.             lo = value;
  147.             mid = 0;
  148.             hi = 0;
  149.         }
  150.        
  151.         // Constructs a Decimal from an unsigned integer value.
  152.         //
  153.         [CLSCompliant(false)]
  154.         public Decimal(uint value)
  155.         {
  156.             flags = 0;
  157.             lo = (int)value;
  158.             mid = 0;
  159.             hi = 0;
  160.         }
  161.        
  162.         // Constructs a Decimal from a long value.
  163.         //
  164.         public Decimal(long value)
  165.         {
  166.             if (value >= 0) {
  167.                 flags = 0;
  168.             }
  169.             else {
  170.                 flags = SignMask;
  171.                 value = -value;
  172.             }
  173.             lo = (int)value;
  174.             mid = (int)(value >> 32);
  175.             hi = 0;
  176.         }
  177.        
  178.         // Constructs a Decimal from an unsigned long value.
  179.         //
  180.         [CLSCompliant(false)]
  181.         public Decimal(ulong value)
  182.         {
  183.             flags = 0;
  184.             lo = (int)value;
  185.             mid = (int)(value >> 32);
  186.             hi = 0;
  187.         }
  188.        
  189.         // Constructs a Decimal from a float value.
  190.         //
  191.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  192.         public extern Decimal(float value);
  193.        
  194.         // Constructs a Decimal from a double value.
  195.         //
  196.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  197.         public extern Decimal(double value);
  198.        
  199.         // Constructs a Decimal from a Currency value.
  200.         //
  201.         internal Decimal(Currency value)
  202.         {
  203.             decimal temp = Currency.ToDecimal(value);
  204.             this.lo = temp.lo;
  205.             this.mid = temp.mid;
  206.             this.hi = temp.hi;
  207.             this.flags = temp.flags;
  208.         }
  209.        
  210.         // Don't remove these 2 methods below. They are required by the fx when the are dealing with Currency in their
  211.         // databases
  212.         public static long ToOACurrency(decimal value)
  213.         {
  214.             return new Currency(value).ToOACurrency();
  215.         }
  216.        
  217.         public static decimal FromOACurrency(long cy)
  218.         {
  219.             return Currency.ToDecimal(Currency.FromOACurrency(cy));
  220.         }
  221.        
  222.        
  223.         // Constructs a Decimal from an integer array containing a binary
  224.         // representation. The bits argument must be a non-null integer
  225.         // array with four elements. bits[0], bits[1], and
  226.         // bits[2] contain the low, middle, and high 32 bits of the 96-bit
  227.         // integer part of the Decimal. bits[3] contains the scale factor
  228.         // and sign of the Decimal: bits 0-15 (the lower word) are unused and must
  229.         // be zero; bits 16-23 must contain a value between 0 and 28, indicating
  230.         // the power of 10 to divide the 96-bit integer part by to produce the
  231.         // Decimal value; bits 24-30 are unused and must be zero; and finally bit
  232.         // 31 indicates the sign of the Decimal value, 0 meaning positive and 1
  233.         // meaning negative.
  234.         //
  235.         // Note that there are several possible binary representations for the
  236.         // same numeric value. For example, the value 1 can be represented as {1,
  237.         // 0, 0, 0} (integer value 1 with a scale factor of 0) and equally well as
  238.         // {1000, 0, 0, 0x30000} (integer value 1000 with a scale factor of 3).
  239.         // The possible binary representations of a particular value are all
  240.         // equally valid, and all are numerically equivalent.
  241.         //
  242.         public Decimal(int[] bits)
  243.         {
  244.             if (bits == null)
  245.                 throw new ArgumentNullException("bits");
  246.             if (bits.Length == 4) {
  247.                 int f = bits[3];
  248.                 if ((f & ~(SignMask | ScaleMask)) == 0 && (f & ScaleMask) <= (28 << 16)) {
  249.                     lo = bits[0];
  250.                     mid = bits[1];
  251.                     hi = bits[2];
  252.                     flags = f;
  253.                     return;
  254.                 }
  255.             }
  256.             throw new ArgumentException(Environment.GetResourceString("Arg_DecBitCtor"));
  257.         }
  258.        
  259.         // Constructs a Decimal from its constituent parts.
  260.         //
  261.         public Decimal(int lo, int mid, int hi, bool isNegative, byte scale)
  262.         {
  263.             if (scale > 28)
  264.                 throw new ArgumentOutOfRangeException("scale", Environment.GetResourceString("ArgumentOutOfRange_DecimalScale"));
  265.             this.lo = lo;
  266.             this.mid = mid;
  267.             this.hi = hi;
  268.             this.flags = ((int)scale) << 16;
  269.             if (isNegative)
  270.                 this.flags |= SignMask;
  271.         }
  272.        
  273.         // Constructs a Decimal from its constituent parts.
  274.         private Decimal(int lo, int mid, int hi, int flags)
  275.         {
  276.             this.lo = lo;
  277.             this.mid = mid;
  278.             this.hi = hi;
  279.             this.flags = flags;
  280.         }
  281.        
  282.         // Returns the absolute value of the given Decimal. If d is
  283.         // positive, the result is d. If d is negative, the result
  284.         // is -d.
  285.         //
  286.         static internal decimal Abs(decimal d)
  287.         {
  288.             return new decimal(d.lo, d.mid, d.hi, d.flags & ~SignMask);
  289.         }
  290.        
  291.         // Adds two Decimal values.
  292.         //
  293.         public static decimal Add(decimal d1, decimal d2)
  294.         {
  295.             decimal result = new decimal();
  296.             FCallAdd(ref result, d1, d2);
  297.             return result;
  298.         }
  299.        
  300.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  301.         private static extern void FCallAdd(ref decimal result, decimal d1, decimal d2);
  302.        
  303.         // Rounds a Decimal to an integer value. The Decimal argument is rounded
  304.         // towards positive infinity.
  305.         public static decimal Ceiling(decimal d)
  306.         {
  307.             return (-(Decimal.Floor(-d)));
  308.         }
  309.        
  310.         // Compares two Decimal values, returning an integer that indicates their
  311.         // relationship.
  312.         //
  313.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  314.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  315.         public static extern int Compare(decimal d1, decimal d2);
  316.        
  317.         // Compares this object to another object, returning an integer that
  318.         // indicates the relationship.
  319.         // Returns a value less than zero if this object
  320.         // null is considered to be less than any instance.
  321.         // If object is not of type Decimal, this method throws an ArgumentException.
  322.         //
  323.         public int CompareTo(object value)
  324.         {
  325.             if (value == null)
  326.                 return 1;
  327.             if (!(value is decimal))
  328.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBeDecimal"));
  329.            
  330.             return Decimal.Compare(this, (decimal)value);
  331.         }
  332.        
  333.         public int CompareTo(decimal value)
  334.         {
  335.             return Decimal.Compare(this, value);
  336.         }
  337.        
  338.         // Divides two Decimal values.
  339.         //
  340.         public static decimal Divide(decimal d1, decimal d2)
  341.         {
  342.             decimal result = new decimal();
  343.             FCallDivide(ref result, d1, d2);
  344.             return result;
  345.         }
  346.        
  347.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  348.         private static extern void FCallDivide(ref decimal result, decimal d1, decimal d2);
  349.        
  350.         // Checks if this Decimal is equal to a given object. Returns true
  351.         // if the given object is a boxed Decimal and its value is equal to the
  352.         // value of this Decimal. Returns false otherwise.
  353.         //
  354.         public override bool Equals(object value)
  355.         {
  356.             if (value is decimal) {
  357.                 return Compare(this, (decimal)value) == 0;
  358.             }
  359.             return false;
  360.         }
  361.        
  362.         public bool Equals(decimal value)
  363.         {
  364.             return Compare(this, value) == 0;
  365.         }
  366.        
  367.         // Returns the hash code for this Decimal.
  368.         //
  369.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  370.         public override extern int GetHashCode();
  371.        
  372.         // Compares two Decimal values for equality. Returns true if the two
  373.         // Decimal values are equal, or false if they are not equal.
  374.         //
  375.         public static bool Equals(decimal d1, decimal d2)
  376.         {
  377.             return Compare(d1, d2) == 0;
  378.         }
  379.        
  380.         // Rounds a Decimal to an integer value. The Decimal argument is rounded
  381.         // towards negative infinity.
  382.         //
  383.         public static decimal Floor(decimal d)
  384.         {
  385.             decimal result = new decimal();
  386.             FCallFloor(ref result, d);
  387.             return result;
  388.         }
  389.        
  390.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  391.         private static extern void FCallFloor(ref decimal result, decimal d);
  392.        
  393.         // Converts this Decimal to a string. The resulting string consists of an
  394.         // optional minus sign ("-") followed to a sequence of digits ("0" - "9"),
  395.         // optionally followed by a decimal point (".") and another sequence of
  396.         // digits.
  397.         //
  398.         public override string ToString()
  399.         {
  400.             return Number.FormatDecimal(this, null, NumberFormatInfo.CurrentInfo);
  401.         }
  402.        
  403.         public string ToString(string format)
  404.         {
  405.             return Number.FormatDecimal(this, format, NumberFormatInfo.CurrentInfo);
  406.         }
  407.        
  408.         public string ToString(IFormatProvider provider)
  409.         {
  410.             return Number.FormatDecimal(this, null, NumberFormatInfo.GetInstance(provider));
  411.         }
  412.        
  413.         public string ToString(string format, IFormatProvider provider)
  414.         {
  415.             return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider));
  416.         }
  417.        
  418.        
  419.         // Converts a string to a Decimal. The string must consist of an optional
  420.         // minus sign ("-") followed by a sequence of digits ("0" - "9"). The
  421.         // sequence of digits may optionally contain a single decimal point (".")
  422.         // character. Leading and trailing whitespace characters are allowed.
  423.         // Parse also allows a currency symbol, a trailing negative sign, and
  424.         // parentheses in the number.
  425.         //
  426.         public static decimal Parse(string s)
  427.         {
  428.             return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo);
  429.         }
  430.        
  431.         public static decimal Parse(string s, NumberStyles style)
  432.         {
  433.             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  434.             return Number.ParseDecimal(s, style, NumberFormatInfo.CurrentInfo);
  435.         }
  436.        
  437.         public static decimal Parse(string s, IFormatProvider provider)
  438.         {
  439.             return Number.ParseDecimal(s, NumberStyles.Number, NumberFormatInfo.GetInstance(provider));
  440.         }
  441.        
  442.         public static decimal Parse(string s, NumberStyles style, IFormatProvider provider)
  443.         {
  444.             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  445.             return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider));
  446.         }
  447.        
  448.         public static bool TryParse(string s, out decimal result)
  449.         {
  450.             return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result);
  451.         }
  452.        
  453.         public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out decimal result)
  454.         {
  455.             NumberFormatInfo.ValidateParseStyleFloatingPoint(style);
  456.             return Number.TryParseDecimal(s, style, NumberFormatInfo.GetInstance(provider), out result);
  457.         }
  458.        
  459.         // Returns a binary representation of a Decimal. The return value is an
  460.         // integer array with four elements. Elements 0, 1, and 2 contain the low,
  461.         // middle, and high 32 bits of the 96-bit integer part of the Decimal.
  462.         // Element 3 contains the scale factor and sign of the Decimal: bits 0-15
  463.         // (the lower word) are unused; bits 16-23 contain a value between 0 and
  464.         // 28, indicating the power of 10 to divide the 96-bit integer part by to
  465.         // produce the Decimal value; bits 24-30 are unused; and finally bit 31
  466.         // indicates the sign of the Decimal value, 0 meaning positive and 1
  467.         // meaning negative.
  468.         //
  469.         public static int[] GetBits(decimal d)
  470.         {
  471.             return new int[] {d.lo, d.mid, d.hi, d.flags};
  472.         }
  473.        
  474.         static internal void GetBytes(decimal d, byte[] buffer)
  475.         {
  476.             BCLDebug.Assert((buffer != null && buffer.Length >= 16), "[GetBytes]buffer != null && buffer.Length >= 16");
  477.             buffer[0] = (byte)d.lo;
  478.             buffer[1] = (byte)(d.lo >> 8);
  479.             buffer[2] = (byte)(d.lo >> 16);
  480.             buffer[3] = (byte)(d.lo >> 24);
  481.            
  482.             buffer[4] = (byte)d.mid;
  483.             buffer[5] = (byte)(d.mid >> 8);
  484.             buffer[6] = (byte)(d.mid >> 16);
  485.             buffer[7] = (byte)(d.mid >> 24);
  486.            
  487.             buffer[8] = (byte)d.hi;
  488.             buffer[9] = (byte)(d.hi >> 8);
  489.             buffer[10] = (byte)(d.hi >> 16);
  490.             buffer[11] = (byte)(d.hi >> 24);
  491.            
  492.             buffer[12] = (byte)d.flags;
  493.             buffer[13] = (byte)(d.flags >> 8);
  494.             buffer[14] = (byte)(d.flags >> 16);
  495.             buffer[15] = (byte)(d.flags >> 24);
  496.         }
  497.        
  498.         static internal decimal ToDecimal(byte[] buffer)
  499.         {
  500.             int lo = ((int)buffer[0]) | ((int)buffer[1] << 8) | ((int)buffer[2] << 16) | ((int)buffer[3] << 24);
  501.             int mid = ((int)buffer[4]) | ((int)buffer[5] << 8) | ((int)buffer[6] << 16) | ((int)buffer[7] << 24);
  502.             int hi = ((int)buffer[8]) | ((int)buffer[9] << 8) | ((int)buffer[10] << 16) | ((int)buffer[11] << 24);
  503.             int flags = ((int)buffer[12]) | ((int)buffer[13] << 8) | ((int)buffer[14] << 16) | ((int)buffer[15] << 24);
  504.             return new decimal(lo, mid, hi, flags);
  505.         }
  506.        
  507.         // This method does a 'raw' and 'unchecked' addition of a UInt32 to a Decimal in place.
  508.         // 'raw' means that it operates on the internal 96-bit unsigned integer value and
  509.         // ingores the sign and scale. This means that it is not equivalent to just adding
  510.         // that number, as the sign and scale are effectively applied to the UInt32 value also.
  511.         // 'unchecked' means that it does not fail if you overflow the 96 bit value.
  512.         private static void InternalAddUInt32RawUnchecked(ref decimal value, UInt32 i)
  513.         {
  514.             UInt32 v;
  515.             UInt32 sum;
  516.             v = (UInt32)value.lo;
  517.             sum = v + i;
  518.             value.lo = (Int32)sum;
  519.             if (sum < v || sum < i) {
  520.                 v = (UInt32)value.mid;
  521.                 sum = v + 1;
  522.                 value.mid = (Int32)sum;
  523.                 if (sum < v || sum < 1) {
  524.                     value.hi = (Int32)((UInt32)value.hi + 1);
  525.                 }
  526.             }
  527.         }
  528.        
  529.         // This method does an in-place division of a decimal by a UInt32, returning the remainder.
  530.         // Although it does not operate on the sign or scale, this does not result in any
  531.         // caveat for the result. It is equivalent to dividing by that number.
  532.         private static UInt32 InternalDivRemUInt32(ref decimal value, UInt32 divisor)
  533.         {
  534.             UInt32 remainder = 0;
  535.             UInt64 n;
  536.             if (value.hi != 0) {
  537.                 n = ((UInt32)value.hi);
  538.                 value.hi = (Int32)((UInt32)(n / divisor));
  539.                 remainder = (UInt32)(n % divisor);
  540.             }
  541.             if (value.mid != 0 || remainder != 0) {
  542.                 n = ((UInt64)remainder << 32) | (UInt32)value.mid;
  543.                 value.mid = (Int32)((UInt32)(n / divisor));
  544.                 remainder = (UInt32)(n % divisor);
  545.             }
  546.             if (value.lo != 0 || remainder != 0) {
  547.                 n = ((UInt64)remainder << 32) | (UInt32)value.lo;
  548.                 value.lo = (Int32)((UInt32)(n / divisor));
  549.                 remainder = (UInt32)(n % divisor);
  550.             }
  551.             return remainder;
  552.         }
  553.        
  554.         // Does an in-place round the specified number of digits, rounding mid-point values
  555.         // away from zero
  556.         private static void InternalRoundFromZero(ref decimal d, int decimalCount)
  557.         {
  558.             Int32 scale = (d.flags & ScaleMask) >> ScaleShift;
  559.             Int32 scaleDifference = scale - decimalCount;
  560.             if (scaleDifference <= 0) {
  561.                 return;
  562.             }
  563.             // Divide the value by 10^scaleDifference
  564.             UInt32 lastRemainder;
  565.             UInt32 lastDivisor;
  566.             do {
  567.                 Int32 diffChunk = (scaleDifference > MaxInt32Scale) ? MaxInt32Scale : scaleDifference;
  568.                 lastDivisor = Powers10[diffChunk];
  569.                 lastRemainder = InternalDivRemUInt32(ref d, lastDivisor);
  570.                 scaleDifference -= diffChunk;
  571.             }
  572.             while (scaleDifference > 0);
  573.            
  574.             // Round away from zero at the mid point
  575.             if (lastRemainder >= (lastDivisor >> 1)) {
  576.                 InternalAddUInt32RawUnchecked(ref d, 1);
  577.             }
  578.            
  579.             // the scale becomes the desired decimal count
  580.             d.flags = ((decimalCount << ScaleShift) & ScaleMask) | (d.flags & SignMask);
  581.         }
  582.        
  583.         // Returns the larger of two Decimal values.
  584.         //
  585.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  586.         static internal decimal Max(decimal d1, decimal d2)
  587.         {
  588.             return Compare(d1, d2) >= 0 ? d1 : d2;
  589.         }
  590.        
  591.         // Returns the smaller of two Decimal values.
  592.         //
  593.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  594.         static internal decimal Min(decimal d1, decimal d2)
  595.         {
  596.             return Compare(d1, d2) < 0 ? d1 : d2;
  597.         }
  598.        
  599.         public static decimal Remainder(decimal d1, decimal d2)
  600.         {
  601.             // OleAut doesn't provide a VarDecMod.
  602.            
  603.             // In the operation x % y the sign of y does not matter. Result will have the sign of x.
  604.             d2.flags = (d2.flags & ~SignMask) | (d1.flags & SignMask);
  605.            
  606.            
  607.             // This piece of code is to work around the fact that Dividing a decimal with 28 digits number by decimal which causes
  608.             // causes the result to be 28 digits, can cause to be incorrectly rounded up.
  609.             // eg. Decimal.MaxValue / 2 * Decimal.MaxValue will overflow since the division by 2 was rounded instead of being truncked.
  610.             if (Abs(d1) < Abs(d2)) {
  611.                 return d1;
  612.             }
  613.             d1 -= d2;
  614.             if (d1 == 0) {
  615.                 d1.flags = (d1.flags & ~SignMask) | (d2.flags & SignMask);
  616.             }
  617.            
  618.             // Formula: d1 - (RoundTowardsZero(d1 / d2) * d2)
  619.             decimal dividedResult = Truncate(d1 / d2);
  620.             decimal multipliedResult = dividedResult * d2;
  621.             decimal result = d1 - multipliedResult;
  622.             // See if the result has crossed 0
  623.             if ((d1.flags & SignMask) != (result.flags & SignMask)) {
  624.                 if (result == 0) {
  625.                     // A zero result just needs its sign corrected
  626.                     result.flags = (result.flags & ~SignMask) | (d1.flags & SignMask);
  627.                 }
  628.                 else {
  629.                     // If the division rounds up because it runs out of digits, the multiplied result can end up with a larger
  630.                     // absolute value and the result of the formula crosses 0. To correct it can add the divisor back.
  631.                     result += d2;
  632.                 }
  633.             }
  634.             return result;
  635.         }
  636.        
  637.         // Multiplies two Decimal values.
  638.         //
  639.         public static decimal Multiply(decimal d1, decimal d2)
  640.         {
  641.             decimal result = new decimal();
  642.             FCallMultiply(ref result, d1, d2);
  643.             return result;
  644.         }
  645.        
  646.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  647.         private static extern void FCallMultiply(ref decimal result, decimal d1, decimal d2);
  648.        
  649.         // Returns the negated value of the given Decimal. If d is non-zero,
  650.         // the result is -d. If d is zero, the result is zero.
  651.         //
  652.         public static decimal Negate(decimal d)
  653.         {
  654.             return new decimal(d.lo, d.mid, d.hi, d.flags ^ SignMask);
  655.         }
  656.        
  657.         // Rounds a Decimal value to a given number of decimal places. The value
  658.         // given by d is rounded to the number of decimal places given by
  659.         // decimals. The decimals argument must be an integer between
  660.         // 0 and 28 inclusive.
  661.         //
  662.         // By default a mid-point value is rounded to the nearest even number. If the mode is
  663.         // passed in, it can also round away from zero.
  664.        
  665.         public static decimal Round(decimal d)
  666.         {
  667.             return Round(d, 0);
  668.         }
  669.        
  670.         public static decimal Round(decimal d, int decimals)
  671.         {
  672.             decimal result = new decimal();
  673.             FCallRound(ref result, d, decimals);
  674.             return result;
  675.         }
  676.        
  677.         public static decimal Round(decimal d, MidpointRounding mode)
  678.         {
  679.             return Round(d, 0, mode);
  680.         }
  681.        
  682.         public static decimal Round(decimal d, int decimals, MidpointRounding mode)
  683.         {
  684.             if ((decimals < 0) || (decimals > 28))
  685.                 throw new ArgumentOutOfRangeException("decimals", Environment.GetResourceString("ArgumentOutOfRange_DecimalRound"));
  686.             if (mode < MidpointRounding.ToEven || mode > MidpointRounding.AwayFromZero) {
  687.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidEnumValue", mode, "MidpointRounding"), "mode");
  688.             }
  689.             decimal returnValue = d;
  690.             if (mode == MidpointRounding.ToEven) {
  691.                 FCallRound(ref returnValue, d, decimals);
  692.             }
  693.             else {
  694.                 InternalRoundFromZero(ref returnValue, decimals);
  695.             }
  696.             return returnValue;
  697.         }
  698.        
  699.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  700.         private static extern void FCallRound(ref decimal result, decimal d, int decimals);
  701.        
  702.         // Subtracts two Decimal values.
  703.         //
  704.         public static decimal Subtract(decimal d1, decimal d2)
  705.         {
  706.             decimal result = new decimal();
  707.             FCallSubtract(ref result, d1, d2);
  708.             return result;
  709.         }
  710.        
  711.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  712.         private static extern void FCallSubtract(ref decimal result, decimal d1, decimal d2);
  713.        
  714.         // Converts a Decimal to an unsigned byte. The Decimal value is rounded
  715.         // towards zero to the nearest integer value, and the result of this
  716.         // operation is returned as a byte.
  717.         //
  718.         public static byte ToByte(decimal value)
  719.         {
  720.             uint temp = ToUInt32(value);
  721.             if (temp < Byte.MinValue || temp > Byte.MaxValue)
  722.                 throw new OverflowException(Environment.GetResourceString("Overflow_Byte"));
  723.             return (byte)temp;
  724.            
  725.         }
  726.        
  727.         // Converts a Decimal to a signed byte. The Decimal value is rounded
  728.         // towards zero to the nearest integer value, and the result of this
  729.         // operation is returned as a byte.
  730.         //
  731.         [CLSCompliant(false)]
  732.         public static sbyte ToSByte(decimal value)
  733.         {
  734.             int temp = ToInt32(value);
  735.             if (temp < SByte.MinValue || temp > SByte.MaxValue)
  736.                 throw new OverflowException(Environment.GetResourceString("Overflow_SByte"));
  737.             return (sbyte)temp;
  738.         }
  739.        
  740.         // Converts a Decimal to a short. The Decimal value is
  741.         // rounded towards zero to the nearest integer value, and the result of
  742.         // this operation is returned as a short.
  743.         //
  744.         public static short ToInt16(decimal value)
  745.         {
  746.             int temp = ToInt32(value);
  747.             if (temp < Int16.MinValue || temp > Int16.MaxValue)
  748.                 throw new OverflowException(Environment.GetResourceString("Overflow_Int16"));
  749.             return (short)temp;
  750.         }
  751.        
  752.        
  753.         // Converts a Decimal to a Currency. Since a Currency
  754.         // has fewer significant digits than a Decimal, this operation may
  755.         // produce round-off errors.
  756.         //
  757.         static internal Currency ToCurrency(decimal d)
  758.         {
  759.             Currency result = new Currency();
  760.             FCallToCurrency(ref result, d);
  761.             return result;
  762.         }
  763.        
  764.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  765.         private static extern void FCallToCurrency(ref Currency result, decimal d);
  766.        
  767.         // Converts a Decimal to a double. Since a double has fewer significant
  768.         // digits than a Decimal, this operation may produce round-off errors.
  769.         //
  770.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  771.         public static extern double ToDouble(decimal d);
  772.        
  773.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  774.         static internal extern int FCallToInt32(decimal d);
  775.        
  776.         // Converts a Decimal to an integer. The Decimal value is rounded towards
  777.         // zero to the nearest integer value, and the result of this operation is
  778.         // returned as an integer.
  779.         //
  780.         public static int ToInt32(decimal d)
  781.         {
  782.             if ((d.flags & ScaleMask) != 0)
  783.                 d = Truncate(d);
  784.             if (d.hi == 0 && d.mid == 0) {
  785.                 int i = d.lo;
  786.                 if (d.flags >= 0) {
  787.                     if (i >= 0)
  788.                         return i;
  789.                 }
  790.                 else {
  791.                     i = -i;
  792.                     if (i <= 0)
  793.                         return i;
  794.                 }
  795.             }
  796.             throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
  797.         }
  798.        
  799.         // Converts a Decimal to a long. The Decimal value is rounded towards zero
  800.         // to the nearest integer value, and the result of this operation is
  801.         // returned as a long.
  802.         //
  803.         public static long ToInt64(decimal d)
  804.         {
  805.             if ((d.flags & ScaleMask) != 0)
  806.                 d = Truncate(d);
  807.             if (d.hi == 0) {
  808.                 long l = d.lo & 4294967295ul | (long)d.mid << 32;
  809.                 if (d.flags >= 0) {
  810.                     if (l >= 0)
  811.                         return l;
  812.                 }
  813.                 else {
  814.                     l = -l;
  815.                     if (l <= 0)
  816.                         return l;
  817.                 }
  818.             }
  819.             throw new OverflowException(Environment.GetResourceString("Overflow_Int64"));
  820.         }
  821.        
  822.         // Converts a Decimal to an ushort. The Decimal
  823.         // value is rounded towards zero to the nearest integer value, and the
  824.         // result of this operation is returned as an ushort.
  825.         //
  826.         [CLSCompliant(false)]
  827.         public static ushort ToUInt16(decimal value)
  828.         {
  829.             uint temp = ToUInt32(value);
  830.             if (temp < UInt16.MinValue || temp > UInt16.MaxValue)
  831.                 throw new OverflowException(Environment.GetResourceString("Overflow_UInt16"));
  832.             return (ushort)temp;
  833.         }
  834.        
  835.         // Converts a Decimal to an unsigned integer. The Decimal
  836.         // value is rounded towards zero to the nearest integer value, and the
  837.         // result of this operation is returned as an unsigned integer.
  838.         //
  839.         [CLSCompliant(false)]
  840.         public static uint ToUInt32(decimal d)
  841.         {
  842.             if ((d.flags & ScaleMask) != 0)
  843.                 d = Truncate(d);
  844.             if (d.hi == 0 && d.mid == 0) {
  845.                 uint i = (uint)d.lo;
  846.                 if (d.flags >= 0 || i == 0)
  847.                     return i;
  848.             }
  849.             throw new OverflowException(Environment.GetResourceString("Overflow_UInt32"));
  850.         }
  851.        
  852.         // Converts a Decimal to an unsigned long. The Decimal
  853.         // value is rounded towards zero to the nearest integer value, and the
  854.         // result of this operation is returned as a long.
  855.         //
  856.         [CLSCompliant(false)]
  857.         public static ulong ToUInt64(decimal d)
  858.         {
  859.             if ((d.flags & ScaleMask) != 0)
  860.                 d = Truncate(d);
  861.             if (d.hi == 0) {
  862.                 ulong l = ((ulong)(uint)d.lo) | ((ulong)(uint)d.mid << 32);
  863.                 if (d.flags >= 0 || l == 0)
  864.                     return l;
  865.             }
  866.             throw new OverflowException(Environment.GetResourceString("Overflow_UInt64"));
  867.         }
  868.        
  869.         // Converts a Decimal to a float. Since a float has fewer significant
  870.         // digits than a Decimal, this operation may produce round-off errors.
  871.         //
  872.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  873.         public static extern float ToSingle(decimal d);
  874.        
  875.         // Truncates a Decimal to an integer value. The Decimal argument is rounded
  876.         // towards zero to the nearest integer value, corresponding to removing all
  877.         // digits after the decimal point.
  878.         //
  879.         public static decimal Truncate(decimal d)
  880.         {
  881.             decimal result = new decimal();
  882.             FCallTruncate(ref result, d);
  883.             return result;
  884.         }
  885.        
  886.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  887.         private static extern void FCallTruncate(ref decimal result, decimal d);
  888.        
  889.        
  890.         public static implicit operator decimal(byte value)
  891.         {
  892.             return new decimal(value);
  893.         }
  894.        
  895.         [CLSCompliant(false)]
  896.         public static implicit operator decimal(sbyte value)
  897.         {
  898.             return new decimal(value);
  899.         }
  900.        
  901.         public static implicit operator decimal(short value)
  902.         {
  903.             return new decimal(value);
  904.         }
  905.        
  906.         [CLSCompliant(false)]
  907.         public static implicit operator decimal(ushort value)
  908.         {
  909.             return new decimal(value);
  910.         }
  911.        
  912.         public static implicit operator decimal(char value)
  913.         {
  914.             return new decimal(value);
  915.         }
  916.        
  917.         public static implicit operator decimal(int value)
  918.         {
  919.             return new decimal(value);
  920.         }
  921.        
  922.         [CLSCompliant(false)]
  923.         public static implicit operator decimal(uint value)
  924.         {
  925.             return new decimal(value);
  926.         }
  927.        
  928.         public static implicit operator decimal(long value)
  929.         {
  930.             return new decimal(value);
  931.         }
  932.        
  933.         [CLSCompliant(false)]
  934.         public static implicit operator decimal(ulong value)
  935.         {
  936.             return new decimal(value);
  937.         }
  938.        
  939.        
  940.         public static explicit operator decimal(float value)
  941.         {
  942.             return new decimal(value);
  943.         }
  944.        
  945.         public static explicit operator decimal(double value)
  946.         {
  947.             return new decimal(value);
  948.         }
  949.        
  950.         public static explicit operator byte(decimal value)
  951.         {
  952.             return ToByte(value);
  953.         }
  954.        
  955.         [CLSCompliant(false)]
  956.         public static explicit operator sbyte(decimal value)
  957.         {
  958.             return ToSByte(value);
  959.         }
  960.        
  961.         public static explicit operator char(decimal value)
  962.         {
  963.             return (char)ToUInt16(value);
  964.         }
  965.        
  966.         public static explicit operator short(decimal value)
  967.         {
  968.             return ToInt16(value);
  969.         }
  970.        
  971.         [CLSCompliant(false)]
  972.         public static explicit operator ushort(decimal value)
  973.         {
  974.             return ToUInt16(value);
  975.         }
  976.        
  977.         public static explicit operator int(decimal value)
  978.         {
  979.             return ToInt32(value);
  980.         }
  981.        
  982.         [CLSCompliant(false)]
  983.         public static explicit operator uint(decimal value)
  984.         {
  985.             return ToUInt32(value);
  986.         }
  987.        
  988.         public static explicit operator long(decimal value)
  989.         {
  990.             return ToInt64(value);
  991.         }
  992.        
  993.         [CLSCompliant(false)]
  994.         public static explicit operator ulong(decimal value)
  995.         {
  996.             return ToUInt64(value);
  997.         }
  998.        
  999.         public static explicit operator float(decimal value)
  1000.         {
  1001.             return ToSingle(value);
  1002.         }
  1003.        
  1004.         public static explicit operator double(decimal value)
  1005.         {
  1006.             return ToDouble(value);
  1007.         }
  1008.        
  1009.         public static decimal operator +(decimal d)
  1010.         {
  1011.             return d;
  1012.         }
  1013.        
  1014.         public static decimal operator -(decimal d)
  1015.         {
  1016.             return Negate(d);
  1017.         }
  1018.        
  1019.         public static decimal operator ++(decimal d)
  1020.         {
  1021.             return Add(d, One);
  1022.         }
  1023.        
  1024.         public static decimal operator --(decimal d)
  1025.         {
  1026.             return Subtract(d, One);
  1027.         }
  1028.        
  1029.         public static decimal operator +(decimal d1, decimal d2)
  1030.         {
  1031.             return Add(d1, d2);
  1032.         }
  1033.        
  1034.         public static decimal operator -(decimal d1, decimal d2)
  1035.         {
  1036.             return Subtract(d1, d2);
  1037.         }
  1038.        
  1039.         public static decimal operator *(decimal d1, decimal d2)
  1040.         {
  1041.             return Multiply(d1, d2);
  1042.         }
  1043.        
  1044.         public static decimal operator /(decimal d1, decimal d2)
  1045.         {
  1046.             return Divide(d1, d2);
  1047.         }
  1048.        
  1049.         public static decimal operator %(decimal d1, decimal d2)
  1050.         {
  1051.             return Remainder(d1, d2);
  1052.         }
  1053.        
  1054. /*private static bool operator equals(Decimal d1, Decimal d2) {
  1055.             return Compare(d1, d2) == 0;
  1056.         }
  1057.    
  1058.         private static int operator compare(Decimal d1, Decimal d2) {
  1059.             int c = Compare(d1, d2);
  1060.             if (c < 0) return -1;
  1061.             if (c > 0) return 1;
  1062.             return 0;
  1063.         }*/       
  1064.        
  1065.         public static bool operator ==(decimal d1, decimal d2)
  1066.         {
  1067.             return Compare(d1, d2) == 0;
  1068.         }
  1069.        
  1070.         public static bool operator !=(decimal d1, decimal d2)
  1071.         {
  1072.             return Compare(d1, d2) != 0;
  1073.         }
  1074.        
  1075.         public static bool operator <(decimal d1, decimal d2)
  1076.         {
  1077.             return Compare(d1, d2) < 0;
  1078.         }
  1079.        
  1080.         public static bool operator <=(decimal d1, decimal d2)
  1081.         {
  1082.             return Compare(d1, d2) <= 0;
  1083.         }
  1084.        
  1085.         public static bool operator >(decimal d1, decimal d2)
  1086.         {
  1087.             return Compare(d1, d2) > 0;
  1088.         }
  1089.        
  1090.         public static bool operator >=(decimal d1, decimal d2)
  1091.         {
  1092.             return Compare(d1, d2) >= 0;
  1093.         }
  1094.        
  1095.         //
  1096.         // IValue implementation
  1097.         //
  1098.        
  1099.         public TypeCode GetTypeCode()
  1100.         {
  1101.             return TypeCode.Decimal;
  1102.         }
  1103.        
  1104.         /// <internalonly/>
  1105.         bool IConvertible.ToBoolean(IFormatProvider provider)
  1106.         {
  1107.             return Convert.ToBoolean(this);
  1108.         }
  1109.        
  1110.        
  1111.         /// <internalonly/>
  1112.         char IConvertible.ToChar(IFormatProvider provider)
  1113.         {
  1114.             throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_FromTo"), "Decimal", "Char"));
  1115.         }
  1116.        
  1117.         /// <internalonly/>
  1118.         sbyte IConvertible.ToSByte(IFormatProvider provider)
  1119.         {
  1120.             return Convert.ToSByte(this);
  1121.         }
  1122.        
  1123.         /// <internalonly/>
  1124.         byte IConvertible.ToByte(IFormatProvider provider)
  1125.         {
  1126.             return Convert.ToByte(this);
  1127.         }
  1128.        
  1129.         /// <internalonly/>
  1130.         short IConvertible.ToInt16(IFormatProvider provider)
  1131.         {
  1132.             return Convert.ToInt16(this);
  1133.         }
  1134.        
  1135.         /// <internalonly/>
  1136.         ushort IConvertible.ToUInt16(IFormatProvider provider)
  1137.         {
  1138.             return Convert.ToUInt16(this);
  1139.         }
  1140.        
  1141.         /// <internalonly/>
  1142.         int IConvertible.ToInt32(IFormatProvider provider)
  1143.         {
  1144.             return Convert.ToInt32(this);
  1145.         }
  1146.        
  1147.         /// <internalonly/>
  1148.         uint IConvertible.ToUInt32(IFormatProvider provider)
  1149.         {
  1150.             return Convert.ToUInt32(this);
  1151.         }
  1152.        
  1153.         /// <internalonly/>
  1154.         long IConvertible.ToInt64(IFormatProvider provider)
  1155.         {
  1156.             return Convert.ToInt64(this);
  1157.         }
  1158.        
  1159.         /// <internalonly/>
  1160.         ulong IConvertible.ToUInt64(IFormatProvider provider)
  1161.         {
  1162.             return Convert.ToUInt64(this);
  1163.         }
  1164.        
  1165.         /// <internalonly/>
  1166.         float IConvertible.ToSingle(IFormatProvider provider)
  1167.         {
  1168.             return Convert.ToSingle(this);
  1169.         }
  1170.        
  1171.         /// <internalonly/>
  1172.         double IConvertible.ToDouble(IFormatProvider provider)
  1173.         {
  1174.             return Convert.ToDouble(this);
  1175.         }
  1176.        
  1177.         /// <internalonly/>
  1178.         decimal IConvertible.ToDecimal(IFormatProvider provider)
  1179.         {
  1180.             return this;
  1181.         }
  1182.        
  1183.         /// <internalonly/>
  1184.         DateTime IConvertible.ToDateTime(IFormatProvider provider)
  1185.         {
  1186.             throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_FromTo"), "Decimal", "DateTime"));
  1187.         }
  1188.        
  1189.         /// <internalonly/>
  1190.         object IConvertible.ToType(Type type, IFormatProvider provider)
  1191.         {
  1192.             return Convert.DefaultToType((IConvertible)this, type, provider);
  1193.         }
  1194.        
  1195.     }
  1196. }

Developer Fusion