Fixing the float/double parsing logic to handle exponents that are too large/small...
authorTanner Gooding <tagoo@outlook.com>
Wed, 6 Mar 2019 12:27:57 +0000 (04:27 -0800)
committerGitHub <noreply@github.com>
Wed, 6 Mar 2019 12:27:57 +0000 (04:27 -0800)
* Fixing the float/double parsing logic to handle exponents that are too large/small

* Fixing the debug assert to use >= and <=

* Fixing the max exponents to be +1 to match what scale uses.

src/System.Private.CoreLib/shared/System/Number.NumberToFloatingPointBits.cs
src/System.Private.CoreLib/shared/System/Number.Parsing.cs

index 5474a60..37609f1 100644 (file)
@@ -333,6 +333,9 @@ namespace System
         {
             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
index 5a58171..89ae0a9 100644 (file)
@@ -32,6 +32,15 @@ namespace System
         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;
+
+        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[]
         {
@@ -1964,18 +1973,44 @@ namespace System
         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;
         }
     }