diff --git a/Src/Newtonsoft.Json.Tests/Utilities/ConvertUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/ConvertUtilsTests.cs index 87bbca34..37e4b0b3 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/ConvertUtilsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/ConvertUtilsTests.cs @@ -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); diff --git a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs index 69461856..6790c5e6 100644 --- a/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/ConvertUtils.cs @@ -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))