Commit f429f348 authored by Soren Lassen's avatar Soren Lassen Committed by Andrii Grynenko

Better estimateSpaceNeeded(double)

Test Plan: fbconfig -r folly/test && fbmake runtests

Reviewed By: mpawlowski@fb.com

Subscribers: njormrod

FB internal diff: D1604761

Blame Revision: D1420588
parent 550b907b
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <folly/Range.h> #include <folly/Range.h>
#include <boost/implicit_cast.hpp> #include <boost/implicit_cast.hpp>
#include <algorithm>
#include <type_traits> #include <type_traits>
#include <limits> #include <limits>
#include <string> #include <string>
...@@ -544,6 +545,11 @@ estimateSpaceNeeded(Src value) { ...@@ -544,6 +545,11 @@ estimateSpaceNeeded(Src value) {
* Conversions from floating-point types to string types. * Conversions from floating-point types to string types.
******************************************************************************/ ******************************************************************************/
namespace detail {
constexpr int kConvMaxDecimalInShortestLow = -6;
constexpr int kConvMaxDecimalInShortestHigh = 21;
} // folly::detail
/** Wrapper around DoubleToStringConverter **/ /** Wrapper around DoubleToStringConverter **/
template <class Tgt, class Src> template <class Tgt, class Src>
typename std::enable_if< typename std::enable_if<
...@@ -558,8 +564,8 @@ toAppend( ...@@ -558,8 +564,8 @@ toAppend(
DoubleToStringConverter DoubleToStringConverter
conv(DoubleToStringConverter::NO_FLAGS, conv(DoubleToStringConverter::NO_FLAGS,
"infinity", "NaN", 'E', "infinity", "NaN", 'E',
-6, // decimal in shortest low detail::kConvMaxDecimalInShortestLow,
21, // decimal in shortest high detail::kConvMaxDecimalInShortestHigh,
6, // max leading padding zeros 6, // max leading padding zeros
1); // max trailing padding zeros 1); // max trailing padding zeros
char buffer[256]; char buffer[256];
...@@ -594,29 +600,31 @@ toAppend(Src value, Tgt * result) { ...@@ -594,29 +600,31 @@ toAppend(Src value, Tgt * result) {
} }
/** /**
* Very primitive, lets say its our best effort * Upper bound of the length of the output from
* DoubleToStringConverter::ToShortest(double, StringBuilder*),
* as used in toAppend(double, string*).
*/ */
template <class Src> template <class Src>
typename std::enable_if< typename std::enable_if<
std::is_floating_point<Src>::value, size_t>::type std::is_floating_point<Src>::value, size_t>::type
estimateSpaceNeeded(Src value) { estimateSpaceNeeded(Src value) {
size_t sofar = 0; // kBase10MaximalLength is 17. We add 1 for decimal point,
if (value < 0) { // e.g. 10.0/9 is 17 digits and 18 characters, including the decimal point.
++sofar; constexpr int kMaxMantissaSpace =
value = -value; double_conversion::DoubleToStringConverter::kBase10MaximalLength + 1;
} // strlen("E-") + digits10(numeric_limits<double>::max_exponent10)
constexpr int kMaxExponentSpace = 2 + 3;
if (value < 1) { static const int kMaxPositiveSpace = std::max({
return sofar + 10; // lets assume 0 + '.' + 8 precision digits // E.g. 1.1111111111111111E-100.
} kMaxMantissaSpace + kMaxExponentSpace,
// E.g. 0.000001.1111111111111111, if kConvMaxDecimalInShortestLow is -6.
if (value < static_cast<double>(std::numeric_limits<uint64_t>::max())) { kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow,
sofar += digits10(static_cast<uint64_t>(value)); // If kConvMaxDecimalInShortestHigh is 21, then 1e21 is the smallest
} else { // number > 1 which ToShortest outputs in exponential notation,
return 64; // give up, it will be more than 23 anyway // so 21 is the longest non-exponential number > 1.
} detail::kConvMaxDecimalInShortestHigh
});
return sofar + 10; // integral part + '.' + 8 precision digits return kMaxPositiveSpace + (value < 0); // +1 for minus sign, if negative
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment