Пример #1
0
        private static void DecShiftLeft(ref MutableDecimal value)
        {
            uint c0 = (value.Low & 0x80000000) != 0 ? 1u : 0u;
            uint c1 = (value.Mid & 0x80000000) != 0 ? 1u : 0u;

            value.Low  = value.Low << 1;
            value.Mid  = (value.Mid << 1) | c0;
            value.High = (value.High << 1) | c1;
        }
Пример #2
0
        internal static void DecMul10(ref MutableDecimal value)
        {
            MutableDecimal d = value;

            DecShiftLeft(ref value);
            DecShiftLeft(ref value);
            DecAdd(ref value, d);
            DecShiftLeft(ref value);
        }
Пример #3
0
 internal static void DecAddInt32(ref MutableDecimal value, uint i)
 {
     if (D32AddCarry(ref value.Low, i))
     {
         if (D32AddCarry(ref value.Mid, 1))
         {
             D32AddCarry(ref value.High, 1);
         }
     }
 }
Пример #4
0
        private static void DecAdd(ref MutableDecimal value, MutableDecimal d)
        {
            if (D32AddCarry(ref value.Low, d.Low))
            {
                if (D32AddCarry(ref value.Mid, 1))
                {
                    D32AddCarry(ref value.High, 1);
                }
            }

            if (D32AddCarry(ref value.Mid, d.Mid))
            {
                D32AddCarry(ref value.High, 1);
            }

            D32AddCarry(ref value.High, d.High);
        }
Пример #5
0
        public static unsafe bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value)
        {
            MutableDecimal d = new MutableDecimal();

            byte *p = number.UnsafeDigits;
            int   e = number.Scale;

            if (*p == 0)
            {
                // To avoid risking an app-compat issue with pre 4.5 (where some app was illegally using Reflection to examine the internal scale bits), we'll only force
                // the scale to 0 if the scale was previously positive (previously, such cases were unparsable to a bug.)
                if (e > 0)
                {
                    e = 0;
                }
            }
            else
            {
                if (e > DECIMAL_PRECISION)
                {
                    return(false);
                }

                while (((e > 0) || ((*p != 0) && (e > -28))) &&
                       ((d.High < 0x19999999) || ((d.High == 0x19999999) &&
                                                  ((d.Mid < 0x99999999) || ((d.Mid == 0x99999999) &&
                                                                            ((d.Low < 0x99999999) || ((d.Low == 0x99999999) &&
                                                                                                      (*p <= '5'))))))))
                {
                    DecimalDecCalc.DecMul10(ref d);
                    if (*p != 0)
                    {
                        DecimalDecCalc.DecAddInt32(ref d, (uint)(*p++ - '0'));
                    }
                    e--;
                }

                if (*p++ >= '5')
                {
                    bool round = true;
                    if ((*(p - 1) == '5') && ((*(p - 2) % 2) == 0))
                    {
                        // Check if previous digit is even, only if the when we are unsure whether hows to do
                        // Banker's rounding. For digits > 5 we will be rounding up anyway.
                        int count = 20; // Look at the next 20 digits to check to round
                        while ((*p == '0') && (count != 0))
                        {
                            p++;
                            count--;
                        }
                        if ((*p == '\0') || (count == 0))
                        {
                            round = false;// Do nothing
                        }
                    }

                    if (round)
                    {
                        DecimalDecCalc.DecAddInt32(ref d, 1);
                        if ((d.High | d.Mid | d.Low) == 0)
                        {
                            // If we got here, the magnitude portion overflowed and wrapped back to 0 as the magnitude was already at the MaxValue point:
                            //
                            //     79,228,162,514,264,337,593,543,950,335e+X
                            //
                            // Manually force it to the correct result:
                            //
                            //      7,922,816,251,426,433,759,354,395,034e+(X+1)
                            //
                            // This code path can be reached by trying to parse the following as a Decimal:
                            //
                            //      0.792281625142643375935439503355e28
                            //

                            d.High = 0x19999999;
                            d.Mid  = 0x99999999;
                            d.Low  = 0x9999999A;
                            e++;
                        }
                    }
                }
            }

            if (e > 0)
            {
                return(false); // Rounding may have caused its own overflow. For example, parsing "0.792281625142643375935439503355e29" will get here.
            }
            if (e <= -DECIMAL_PRECISION)
            {
                // Parsing a large scale zero can give you more precision than fits in the decimal.
                // This should only happen for actual zeros or very small numbers that round to zero.
                d.High  = 0;
                d.Low   = 0;
                d.Mid   = 0;
                d.Scale = DECIMAL_PRECISION - 1;
            }
            else
            {
                d.Scale = -e;
            }
            d.IsNegative = number.IsNegative;

            value = Unsafe.As <MutableDecimal, decimal>(ref d);
            return(true);
        }
Пример #6
0
 // Performs the equivalent of:
 //
 //    uint modulo = value % 1e9;
 //    value = value / 1e9;
 //    return modulo;
 //
 internal static uint DecDivMod1E9(ref MutableDecimal value)
 {
     return(D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0, ref value.High), ref value.Mid), ref value.Low));
 }