Made mantissa be stored in a ulong instead of double to prevent accumulating numeric error.

Added case where if the negative exponent is less than 23 to divide from the positive exponents array to pass unit tests.
This commit is contained in:
TylerBrinkley
2016-08-29 11:19:21 -05:00
parent 1860418cfd
commit 5fd78b21f5
2 changed files with 80 additions and 65 deletions
@@ -61,7 +61,7 @@ namespace Newtonsoft.Json.Tests.Utilities
{
Assert.AreEqual(expectedValue.Value, d, "Input string: " + s);
Assert.AreEqual(expectedValue, d2, "DoubleTryParse result is not equal to double.Parse. Input string: " + s);
Assert.AreEqual(expectedValue.Value, d2, "DoubleTryParse result is not equal to double.Parse. Input string: " + s);
}
}
@@ -89,6 +89,8 @@ namespace Newtonsoft.Json.Tests.Utilities
AssertDoubleTryParse("1", ParseResult.Success, 1);
AssertDoubleTryParse("1.2", ParseResult.Success, 1.2);
AssertDoubleTryParse("1E-21", ParseResult.Success, 1E-21);
AssertDoubleTryParse("1E-22", ParseResult.Success, 1E-22);
AssertDoubleTryParse("1E-23", ParseResult.Success, 1E-23);
AssertDoubleTryParse("1E-25", ParseResult.Success, 1E-25);
AssertDoubleTryParse("1E-50", ParseResult.Success, 1E-50);
+77 -64
View File
@@ -998,10 +998,13 @@ namespace Newtonsoft.Json.Utilities
int numDecimalEnd = end;
int exponent = 0;
bool exponentNegative = false;
ulong mantissa = 0UL;
int mantissaDigits = 0;
int exponentFromMantissa = 0;
for (; i < end; i++)
{
char c = chars[i];
switch (chars[i])
switch (c)
{
case '.':
if (i == start)
@@ -1019,87 +1022,89 @@ namespace Newtonsoft.Json.Utilities
break;
case 'e':
case 'E':
if (i == start)
{
if (i == start)
{
return ParseResult.Invalid;
}
if (i == numDecimalStart)
{
// E follows decimal point
return ParseResult.Invalid;
}
i++;
if (i == end)
{
return ParseResult.Invalid;
}
return ParseResult.Invalid;
}
if (i == numDecimalStart)
{
// E follows decimal point
return ParseResult.Invalid;
}
i++;
if (i == end)
{
return ParseResult.Invalid;
}
if (numDecimalStart < end)
{
numDecimalEnd = i - 1;
}
if (numDecimalStart < end)
{
numDecimalEnd = i - 1;
}
c = chars[i];
switch (c)
{
case '-':
exponentNegative = true;
i++;
break;
case '+':
i++;
break;
}
// parse 3 digit
for (;i < end;i++)
{
c = chars[i];
switch (c)
if (c < '0' || c > '9')
{
case '-':
exponentNegative = true;
i++;
break;
case '+':
i++;
break;
return ParseResult.Invalid;
}
// parse 3 digit
for (;i < end;i++)
{
c = chars[i];
if (c < '0' || c > '9')
{
return ParseResult.Invalid;
}
exponent = (10 * exponent) + (c - '0');
}
exponent = (10 * exponent) + (c - '0');
}
if (exponentNegative)
if (exponentNegative)
{
exponent = -exponent;
}
else
{
if (exponent > MaxExponent)
{
exponent = -exponent;
}
else
{
if (exponent > MaxExponent)
{
return ParseResult.Overflow;
}
return ParseResult.Overflow;
}
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value = (10 * value) + (c - '0');
break;
default:
return ParseResult.Invalid;
if (c < '0' || c > '9')
{
return ParseResult.Invalid;
}
if (mantissaDigits < 19)
{
mantissa = (10 * mantissa) + (ulong)(c - '0');
++mantissaDigits;
}
else
{
++exponentFromMantissa;
}
break;
}
}
exponent += exponentFromMantissa;
// correct the decimal point
exponent -= (numDecimalEnd - numDecimalStart);
if (exponent > 0)
{
value *= DoubleExponents[exponent - 1];
value = mantissa * DoubleExponents[exponent - 1];
}
else if (exponent < 0)
{
@@ -1107,17 +1112,25 @@ namespace Newtonsoft.Json.Utilities
if (exponent > MaxExponent)
{
// handle very small numbers, e.g. 4.94065645841247E-324
value *= DoubleNegativeExponents[154 - 1];
value = mantissa * DoubleNegativeExponents[154 - 1];
exponent -= 154;
}
else
{
value = mantissa;
}
if (DoubleNegativeExponents.Length <= exponent - 1)
{
value = 0;
return ParseResult.Success;
}
value *= DoubleNegativeExponents[exponent - 1];
value = exponent < 23 ? value / DoubleExponents[exponent - 1] : value * DoubleNegativeExponents[exponent - 1];
}
else
{
value = mantissa;
}
if (double.IsPositiveInfinity(value))