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()); }
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())); }
/// <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); } } } }