private static BoundNode RewriteConstant(BoundExpression node)
        {
            var syntax = node.Syntax;

            Debug.Assert(node != null);
            var constantValue = node.ConstantValue;
            Debug.Assert(constantValue != null);
            Debug.Assert(node.ConstantValue.IsDecimal);

            var decimalType = node.Type as NamedTypeSymbol;

            Debug.Assert(decimalType != null);
            Debug.Assert(decimalType.SpecialType == SpecialType.System_Decimal);

            var value = node.ConstantValue.DecimalValue;
            var parts = new DecimalParts(value);
            var scale = parts.Scale;

            var arguments = new ArrayBuilder<BoundExpression>();
            MethodSymbol ctor = null;
            var ctors = decimalType.InstanceConstructors;

            // check if we can call a simple constructor
            if (scale == 0 && !parts.IsNegative && value == 0m)
            {
                // new decimal();
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 0)
                    {
                        ctor = c;
                        break;
                    }
                }
            }
            else if (scale == 0 && int.MinValue <= value && value <= int.MaxValue)
            {
                //new decimal(int);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((int)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && uint.MinValue <= value && value <= uint.MaxValue)
            {
                //new decimal(uint);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((uint)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && long.MinValue <= value && value <= long.MaxValue)
            {
                //new decimal(long);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((long)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && ulong.MinValue <= value && value <= ulong.MaxValue)
            {
                //new decimal(ulong);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((ulong)value), ctor.Parameters[0].Type));
            }
            else
            {
                //new decimal(int low, int mid, int high, bool isNegative, byte scale);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 5)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Low), ctor.Parameters[0].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Mid), ctor.Parameters[1].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.High), ctor.Parameters[2].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.IsNegative), ctor.Parameters[3].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((byte)parts.Scale), ctor.Parameters[4].Type));
            }
            return new BoundObjectCreationExpression(
                node.Syntax,
                ctor,
                arguments.ToReadOnlyAndFree());
        }
Ejemplo n.º 2
0
        private static BoundNode RewriteConstant(BoundExpression node)
        {
            var syntax = node.Syntax;

            Debug.Assert(node != null);
            var constantValue = node.ConstantValue;

            Debug.Assert(constantValue != null);
            Debug.Assert(node.ConstantValue.IsDecimal);

            var decimalType = node.Type as NamedTypeSymbol;

            Debug.Assert(decimalType != null);
            Debug.Assert(decimalType.SpecialType == SpecialType.System_Decimal);

            var value = node.ConstantValue.DecimalValue;
            var parts = new DecimalParts(value);
            var scale = parts.Scale;

            var          arguments = new ArrayBuilder <BoundExpression>();
            MethodSymbol ctor      = null;
            var          ctors     = decimalType.InstanceConstructors;

            // check if we can call a simple constructor
            if (scale == 0 && !parts.IsNegative && value == 0m)
            {
                // new decimal();
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 0)
                    {
                        ctor = c;
                        break;
                    }
                }
            }
            else if (scale == 0 && int.MinValue <= value && value <= int.MaxValue)
            {
                //new decimal(int);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((int)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && uint.MinValue <= value && value <= uint.MaxValue)
            {
                //new decimal(uint);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((uint)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && long.MinValue <= value && value <= long.MaxValue)
            {
                //new decimal(long);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((long)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && ulong.MinValue <= value && value <= ulong.MaxValue)
            {
                //new decimal(ulong);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((ulong)value), ctor.Parameters[0].Type));
            }
            else
            {
                //new decimal(int low, int mid, int high, bool isNegative, byte scale);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 5)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Low), ctor.Parameters[0].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Mid), ctor.Parameters[1].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.High), ctor.Parameters[2].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.IsNegative), ctor.Parameters[3].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((byte)parts.Scale), ctor.Parameters[4].Type));
            }
            return(new BoundObjectCreationExpression(
                       node.Syntax,
                       ctor,
                       arguments.ToReadOnlyAndFree()));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns a random decimal between positive zero and the specified maximum.
        /// </summary>
        public decimal NextDecimal(decimal max)
        {
            if (max <= 1)
            {
                Guard.ArgumentInRange(max > 0, "Maximum must be greater than zero.", nameof(max));
                return(0);
            }

            unchecked
            {
                // Flooring sets the exponent (scale) to zero. This is necessary even if the number is already an
                // integer so that the low, mid and high parts of the mantissa get shifted by the appropriate power of
                // ten until they only contain the integral part of the number.
                // May as well set it back to the parameter so that the `result < max` lower down is doing less work.
                max = decimal.Floor(max);

                var parts = DecimalParts.FromValue(max);

                // If scale is not zero, that means that low, mid, and high are shifted to make room for digits from the
                // fractional part of the number. We relied on Decimal.Floor to prevent this.
                Guard.OperationValid(parts.Scale == 0, "Decimal.Floor returned a value whose scale was not 0.");

                while (true)
                {
                    // Fill all 96 bits with uniformly-distributed randomness except for the bits that must be zero in
                    // order to stay under the exclusive maximum.
                    int low, mid, high;

                    if (parts.High != 0)
                    {
                        var inclusiveMaximum = parts.High - 1;

                        low  = RawInt32();
                        mid  = RawInt32();
                        high = RawInt32() & (int)MaskToRemoveBitsGuaranteedToExceedMaximum(inclusiveMaximum);
                    }
                    else if (parts.Mid != 0)
                    {
                        var inclusiveMaximum = parts.Mid - 1;

                        low  = RawInt32();
                        mid  = RawInt32() & (int)MaskToRemoveBitsGuaranteedToExceedMaximum(inclusiveMaximum);
                        high = 0;
                    }
                    else
                    {
                        var inclusiveMaximum = parts.Low - 1;

                        low  = RawInt32() & (int)MaskToRemoveBitsGuaranteedToExceedMaximum(inclusiveMaximum);
                        mid  = 0;
                        high = 0;
                    }

                    var result = new decimal(low, mid, high, false, 0);

                    // By masking out the random bits which would put the result at or over the exclusive maximum, the
                    // chance of having to loop and try again is strictly less than 50% in the worst-case scenario. The
                    // best-case scenario is 0% chance, and an average is 25% chance per iteration.

                    // For the worst-case scenario of 50% chance per iteration, the total chance of having to iterate
                    // twice is < 25%. Three times, 12.5%. And so on.
                    // For the average scenario of 25% chance per iteration, the total chance of having to iterate twice
                    // is < 6.25%. Three times, 1.5625%. And so on.
                    if (result < max)
                    {
                        return(result);
                    }
                }
            }
        }