Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Fixing the float/double parsing logic to handle exponents that are too large/small #23043

Merged
merged 3 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ private static ulong NumberToFloatingPointBits(ref NumberBuffer number, in Float
{
Debug.Assert(number.GetDigitsPointer()[0] != '0');

Debug.Assert(number.Scale <= FloatingPointMaxExponent);
Debug.Assert(number.Scale >= FloatingPointMinExponent);

// The input is of the form 0.Mantissa x 10^Exponent, where 'Mantissa' are
// the decimal digits of the mantissa and 'Exponent' is the decimal exponent.
// We decompose the mantissa into two parts: an integer part and a fractional
Expand Down
43 changes: 39 additions & 4 deletions src/System.Private.CoreLib/shared/System/Number.Parsing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ internal partial class Number
private const int Int64Precision = 19;
private const int UInt64Precision = 20;

private const int DoubleMaxExponent = 309;
private const int DoubleMinExponent = -324;

private const int FloatingPointMaxExponent = DoubleMaxExponent;
private const int FloatingPointMinExponent = DoubleMinExponent;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need these rather than just using DoubleMax/MinExponent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes it easier to expand to support things like Binary128, if that ever happens.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.


private const int SingleMaxExponent = 39;
private const int SingleMinExponent = -45;

/// <summary>Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.</summary>
internal static ReadOnlySpan<byte> CharToHexLookup => new byte[]
{
Expand Down Expand Up @@ -1964,18 +1973,44 @@ private static Exception GetException(ParsingStatus status, TypeCode type)
internal static double NumberToDouble(ref NumberBuffer number)
{
number.CheckConsistency();
double result;

if (number.Scale > DoubleMaxExponent)
{
result = double.PositiveInfinity;
}
else if (number.Scale < DoubleMinExponent)
{
result = 0;
}
else
{
ulong bits = NumberToFloatingPointBits(ref number, in FloatingPointInfo.Double);
result = BitConverter.Int64BitsToDouble((long)(bits));
}

ulong bits = NumberToFloatingPointBits(ref number, in FloatingPointInfo.Double);
double result = BitConverter.Int64BitsToDouble((long)(bits));
return number.IsNegative ? -result : result;
}

internal static float NumberToSingle(ref NumberBuffer number)
{
number.CheckConsistency();
float result;

if (number.Scale > SingleMaxExponent)
{
result = float.PositiveInfinity;
}
else if (number.Scale < SingleMinExponent)
{
result = 0;
}
else
{
uint bits = (uint)(NumberToFloatingPointBits(ref number, in FloatingPointInfo.Single));
result = BitConverter.Int32BitsToSingle((int)(bits));
}

uint bits = (uint)(NumberToFloatingPointBits(ref number, in FloatingPointInfo.Single));
float result = BitConverter.Int32BitsToSingle((int)(bits));
return number.IsNegative ? -result : result;
}
}
Expand Down