diff --git a/NEWS.md b/NEWS.md index da1978fb..ce018557 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # readr 0.2.2.9000 +* Parse doubles with `boost::spirit::qi::long_double` to work around a bug in the + spirit library when parsing large numbers (#412, @jimhester). + * Supports reading into long vectors (#309, @jimhester). * `default_locale()` now sets the default locale in `readr.default_locale` rather than regenerating it for each call. (#416, @jimhester). diff --git a/src/QiParsers.h b/src/QiParsers.h index ce919364..961a81c6 100644 --- a/src/QiParsers.h +++ b/src/QiParsers.h @@ -19,10 +19,10 @@ inline bool parseDouble(const char decimalMark, Iterator& first, Iterator& last, if (decimalMark == '.') { return boost::spirit::qi::parse(first, last, - boost::spirit::qi::double_, res); + boost::spirit::qi::long_double, res); } else if (decimalMark == ',') { return boost::spirit::qi::parse(first, last, - boost::spirit::qi::real_parser(), res); + boost::spirit::qi::real_parser(), res); } else { return false; } diff --git a/tests/testthat/test-parsing-numeric.R b/tests/testthat/test-parsing-numeric.R index b0dc9129..85b77bc0 100644 --- a/tests/testthat/test-parsing-numeric.R +++ b/tests/testthat/test-parsing-numeric.R @@ -31,7 +31,7 @@ test_that("lone - or decimal marks are not numbers", { test_that("Numbers with trailing characters are parsed as characters", { expect_equal(collector_guess("13T"), "character") - expect_equal(collector_guess(collector_guess(c("13T","13T","10N"))), "character") + expect_equal(collector_guess(collector_guess(c("13T", "13T", "10N"))), "character") }) # Leading zeros ----------------------------------------------------------- @@ -83,3 +83,15 @@ test_that("negative numbers return negative values", { expect_equal(parse_number("-100,000.00"), -100000) }) + +# Large numbers ------------------------------------------------------------- + +test_that("large numbers are parsed properly", { + expect_equal(parse_double("100000000000000000000"), 1e20) + + expect_equal(parse_double("1267650600228229401496703205376"), 1.267650600228229401496703205376e+30) + + expect_equal(parse_double("100000000000000000000", locale = es_MX), 1e20) + + expect_equal(parse_double("1267650600228229401496703205376", locale = es_MX), 1.267650600228229401496703205376e+30) +})