Utility that converts from prettyPrint format back to double (e.g. 10M = 10 000 000)
authorMikhail Okunev <mokunev@fb.com>
Mon, 31 Mar 2014 18:51:55 +0000 (11:51 -0700)
committerSara Golemon <sgolemon@fb.com>
Fri, 4 Apr 2014 02:54:15 +0000 (19:54 -0700)
Summary: Utility is doing reverse of prettyPrint. This is a first sketch.

Test Plan:
1) We can reverse all tests from prettyPrint test and use for our function. For now I just reversed several of them
2) We can also test prettyPrint and prettyToDouble together by checking whether prettyToDouble(prettyPrint(X)) == X. This is implemented.

Reviewed By: marcelo.juchem@fb.com

FB internal diff: D1159879

folly/String.cpp
folly/String.h
folly/test/StringTest.cpp

index d8c25b55174906ad63035cf0430b4c43c16f6dc7..bf3fc38cde9fffb2167474f0a84a583d42c0a366 100644 (file)
@@ -180,6 +180,31 @@ const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
   { 0, 0 },
 };
 
+const PrettySuffix kPrettySISuffixes[] = {
+  { "Y", 1e24L },
+  { "Z", 1e21L },
+  { "E", 1e18L },
+  { "P", 1e15L },
+  { "T", 1e12L },
+  { "G", 1e9L },
+  { "M", 1e6L },
+  { "k", 1e3L },
+  { "h", 1e2L },
+  { "da", 1e1L },
+  { "d", 1e-1L },
+  { "c", 1e-2L },
+  { "m", 1e-3L },
+  { "u", 1e-6L },
+  { "n", 1e-9L },
+  { "p", 1e-12L },
+  { "f", 1e-15L },
+  { "a", 1e-18L },
+  { "z", 1e-21L },
+  { "y", 1e-24L },
+  { " ", 0 },
+  { 0, 0} 
+};
+
 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
   kPrettyTimeSuffixes,
   kPrettyBytesMetricSuffixes,
@@ -188,6 +213,7 @@ const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
   kPrettyUnitsMetricSuffixes,
   kPrettyUnitsBinarySuffixes,
   kPrettyUnitsBinaryIECSuffixes,
+  kPrettySISuffixes,
 };
 
 }  // namespace
@@ -218,6 +244,50 @@ std::string prettyPrint(double val, PrettyType type, bool addSpace) {
   return std::string(buf);
 }
 
+//TODO:
+//1) Benchmark & optimize
+double prettyToDouble(folly::StringPiece *const prettyString, 
+                      const PrettyType type) {
+  double value = folly::to<double>(prettyString);
+  while (prettyString->size() > 0 && std::isspace(prettyString->front())) {
+    prettyString->advance(1); //Skipping spaces between number and suffix
+  }
+  const PrettySuffix* suffixes = kPrettySuffixes[type];
+  int longestPrefixLen = -1;
+  int bestPrefixId = -1;
+  for (int j = 0 ; suffixes[j].suffix; ++j) {
+    if (suffixes[j].suffix[0] == ' '){//Checking for " " -> number rule.
+      if (longestPrefixLen == -1) {
+        longestPrefixLen = 0; //No characters to skip
+        bestPrefixId = j;
+      }
+    } else if (prettyString->startsWith(suffixes[j].suffix)) {
+      int suffixLen = strlen(suffixes[j].suffix);
+      //We are looking for a longest suffix matching prefix of the string
+      //after numeric value. We need this in case suffixes have common prefix.
+      if (suffixLen > longestPrefixLen) {
+        longestPrefixLen = suffixLen;
+        bestPrefixId = j;
+      }
+    }
+  }
+  if (bestPrefixId == -1) { //No valid suffix rule found
+    throw std::invalid_argument(folly::to<std::string>(
+            "Unable to parse suffix \"",
+            prettyString->toString(), "\""));
+  }
+  prettyString->advance(longestPrefixLen);
+  return suffixes[bestPrefixId].val ? value * suffixes[bestPrefixId].val : 
+                                      value;
+}
+
+double prettyToDouble(folly::StringPiece prettyString, const PrettyType type){
+  double result = prettyToDouble(&prettyString, type);
+  detail::enforceWhitespace(prettyString.data(), 
+                            prettyString.data() + prettyString.size());
+  return result;
+}
+
 std::string hexDump(const void* ptr, size_t size) {
   std::ostringstream os;
   hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
index b5dc2417c2850840fe6749e70c459c1b742de912..0dd8c1b3fc5ad16889564da35d27e08d84476c16 100644 (file)
@@ -268,7 +268,8 @@ bool unhexlify(const InputString& input, OutputString& output);
  *   PRETTY_UNITS_METRIC - k, M, G, etc (goes up by 10^3 = 1000 each time)
  *   PRETTY_UNITS_BINARY - k, M, G, etc (goes up by 2^10 = 1024 each time)
  *   PRETTY_UNITS_BINARY_IEC - Ki, Mi, Gi, etc
- *
+ *   PRETTY_SI           - full SI metric prefixes from yocto to Yotta
+ *                         http://en.wikipedia.org/wiki/Metric_prefix
  * @author Mark Rabkin <mrabkin@fb.com>
  */
 enum PrettyType {
@@ -284,11 +285,38 @@ enum PrettyType {
   PRETTY_UNITS_BINARY,
   PRETTY_UNITS_BINARY_IEC,
 
-  PRETTY_NUM_TYPES
+  PRETTY_SI,
+  PRETTY_NUM_TYPES,
 };
 
 std::string prettyPrint(double val, PrettyType, bool addSpace = true);
 
+/**
+ * This utility converts StringPiece in pretty format (look above) to double,
+ * with progress information. Alters the  StringPiece parameter
+ * to get rid of the already-parsed characters.
+ * Expects string in form <floating point number> {space}* [<suffix>]
+ * If string is not in correct format, utility finds longest valid prefix and
+ * if there at least one, returns double value based on that prefix and
+ * modifies string to what is left after parsing. Throws and std::range_error
+ * exception if there is no correct parse.
+ * Examples(for PRETTY_UNITS_METRIC):
+ * '10M' => 10 000 000
+ * '10 M' => 10 000 000
+ * '10' => 10
+ * '10 Mx' => 10 000 000, prettyString == "x"
+ * 'abc' => throws std::range_error
+ */
+double prettyToDouble(folly::StringPiece *const prettyString,
+                      const PrettyType type);
+
+/*
+ * Same as prettyToDouble(folly::StringPiece*, PrettyType), but
+ * expects whole string to be correctly parseable. Throws std::range_error
+ * otherwise
+ */
+double prettyToDouble(folly::StringPiece prettyString, const PrettyType type);
+
 /**
  * Write a hex dump of size bytes starting at ptr to out.
  *
index cb3bcb7a6a991870acbbef1162e66741a7ba65e2..bfad26e9b1ba2f0af110bf9a81cb2a78edcab03c 100644 (file)
@@ -312,115 +312,176 @@ double pow2(int exponent) {
 }
 
 }  // namespace
+struct PrettyTestCase{
+  std::string prettyString;
+  double realValue;
+  PrettyType prettyType;
+};
 
-TEST(PrettyPrint, Basic) {
-  // check time printing
-  EXPECT_EQ(string("8.53e+07 s "), prettyPrint(85.3e6, PRETTY_TIME));
-  EXPECT_EQ(string("85.3 s "), prettyPrint(85.3, PRETTY_TIME));
-  EXPECT_EQ(string("85.3 ms"), prettyPrint(85.3e-3, PRETTY_TIME));
-  EXPECT_EQ(string("85.3 us"), prettyPrint(85.3e-6, PRETTY_TIME));
-  EXPECT_EQ(string("85.3 ns"), prettyPrint(85.3e-9, PRETTY_TIME));
-  EXPECT_EQ(string("85.3 ps"), prettyPrint(85.3e-12, PRETTY_TIME));
-  EXPECT_EQ(string("8.53e-14 s "), prettyPrint(85.3e-15, PRETTY_TIME));
-
-  EXPECT_EQ(string("0 s "), prettyPrint(0, PRETTY_TIME));
-  EXPECT_EQ(string("1 s "), prettyPrint(1.0, PRETTY_TIME));
-  EXPECT_EQ(string("1 ms"), prettyPrint(1.0e-3, PRETTY_TIME));
-  EXPECT_EQ(string("1 us"), prettyPrint(1.0e-6, PRETTY_TIME));
-  EXPECT_EQ(string("1 ns"), prettyPrint(1.0e-9, PRETTY_TIME));
-  EXPECT_EQ(string("1 ps"), prettyPrint(1.0e-12, PRETTY_TIME));
+PrettyTestCase prettyTestCases[] =
+{
+  {string("8.53e+07 s "), 85.3e6,  PRETTY_TIME},
+  {string("8.53e+07 s "), 85.3e6,  PRETTY_TIME},
+  {string("85.3 ms"), 85.3e-3,  PRETTY_TIME},
+  {string("85.3 us"), 85.3e-6,  PRETTY_TIME},
+  {string("85.3 ns"), 85.3e-9,  PRETTY_TIME},
+  {string("85.3 ps"), 85.3e-12,  PRETTY_TIME},
+  {string("8.53e-14 s "), 85.3e-15,  PRETTY_TIME},
+
+  {string("0 s "), 0,  PRETTY_TIME},
+  {string("1 s "), 1.0,  PRETTY_TIME},
+  {string("1 ms"), 1.0e-3,  PRETTY_TIME},
+  {string("1 us"), 1.0e-6,  PRETTY_TIME},
+  {string("1 ns"), 1.0e-9,  PRETTY_TIME},
+  {string("1 ps"), 1.0e-12,  PRETTY_TIME},
 
   // check bytes printing
-  EXPECT_EQ(string("853 B "), prettyPrint(853., PRETTY_BYTES));
-  EXPECT_EQ(string("833 kB"), prettyPrint(853.e3, PRETTY_BYTES));
-  EXPECT_EQ(string("813.5 MB"), prettyPrint(853.e6, PRETTY_BYTES));
-  EXPECT_EQ(string("7.944 GB"), prettyPrint(8.53e9, PRETTY_BYTES));
-  EXPECT_EQ(string("794.4 GB"), prettyPrint(853.e9, PRETTY_BYTES));
-  EXPECT_EQ(string("775.8 TB"), prettyPrint(853.e12, PRETTY_BYTES));
-
-  EXPECT_EQ(string("0 B "), prettyPrint(0, PRETTY_BYTES));
-  EXPECT_EQ(string("1 B "), prettyPrint(pow2(0), PRETTY_BYTES));
-  EXPECT_EQ(string("1 kB"), prettyPrint(pow2(10), PRETTY_BYTES));
-  EXPECT_EQ(string("1 MB"), prettyPrint(pow2(20), PRETTY_BYTES));
-  EXPECT_EQ(string("1 GB"), prettyPrint(pow2(30), PRETTY_BYTES));
-  EXPECT_EQ(string("1 TB"), prettyPrint(pow2(40), PRETTY_BYTES));
-
-  EXPECT_EQ(string("853 B  "), prettyPrint(853., PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("833 KiB"), prettyPrint(853.e3, PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("813.5 MiB"), prettyPrint(853.e6, PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("7.944 GiB"), prettyPrint(8.53e9, PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("794.4 GiB"), prettyPrint(853.e9, PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("775.8 TiB"), prettyPrint(853.e12, PRETTY_BYTES_IEC));
-
-  EXPECT_EQ(string("0 B  "), prettyPrint(0, PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("1 B  "), prettyPrint(pow2(0), PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("1 KiB"), prettyPrint(pow2(10), PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("1 MiB"), prettyPrint(pow2(20), PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("1 GiB"), prettyPrint(pow2(30), PRETTY_BYTES_IEC));
-  EXPECT_EQ(string("1 TiB"), prettyPrint(pow2(40), PRETTY_BYTES_IEC));
+  {string("853 B "), 853.,  PRETTY_BYTES},
+  {string("833 kB"), 853.e3,  PRETTY_BYTES},
+  {string("813.5 MB"), 853.e6,  PRETTY_BYTES},
+  {string("7.944 GB"), 8.53e9,  PRETTY_BYTES},
+  {string("794.4 GB"), 853.e9,  PRETTY_BYTES},
+  {string("775.8 TB"), 853.e12,  PRETTY_BYTES},
+
+  {string("0 B "), 0,  PRETTY_BYTES},
+  {string("1 B "), pow2(0),  PRETTY_BYTES},
+  {string("1 kB"), pow2(10),  PRETTY_BYTES},
+  {string("1 MB"), pow2(20),  PRETTY_BYTES},
+  {string("1 GB"), pow2(30),  PRETTY_BYTES},
+  {string("1 TB"), pow2(40),  PRETTY_BYTES},
+
+  {string("853 B  "), 853.,  PRETTY_BYTES_IEC},
+  {string("833 KiB"), 853.e3,  PRETTY_BYTES_IEC},
+  {string("813.5 MiB"), 853.e6,  PRETTY_BYTES_IEC},
+  {string("7.944 GiB"), 8.53e9,  PRETTY_BYTES_IEC},
+  {string("794.4 GiB"), 853.e9,  PRETTY_BYTES_IEC},
+  {string("775.8 TiB"), 853.e12,  PRETTY_BYTES_IEC},
+
+  {string("0 B  "), 0,  PRETTY_BYTES_IEC},
+  {string("1 B  "), pow2(0),  PRETTY_BYTES_IEC},
+  {string("1 KiB"), pow2(10),  PRETTY_BYTES_IEC},
+  {string("1 MiB"), pow2(20),  PRETTY_BYTES_IEC},
+  {string("1 GiB"), pow2(30),  PRETTY_BYTES_IEC},
+  {string("1 TiB"), pow2(40),  PRETTY_BYTES_IEC},
 
   // check bytes metric printing
-  EXPECT_EQ(string("853 B "), prettyPrint(853., PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("853 kB"), prettyPrint(853.e3, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("853 MB"), prettyPrint(853.e6, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("8.53 GB"), prettyPrint(8.53e9, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("853 GB"), prettyPrint(853.e9, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("853 TB"), prettyPrint(853.e12, PRETTY_BYTES_METRIC));
+  {string("853 B "), 853.,  PRETTY_BYTES_METRIC},
+  {string("853 kB"), 853.e3,  PRETTY_BYTES_METRIC},
+  {string("853 MB"), 853.e6,  PRETTY_BYTES_METRIC},
+  {string("8.53 GB"), 8.53e9,  PRETTY_BYTES_METRIC},
+  {string("853 GB"), 853.e9,  PRETTY_BYTES_METRIC},
+  {string("853 TB"), 853.e12,  PRETTY_BYTES_METRIC},
 
-  EXPECT_EQ(string("0 B "), prettyPrint(0, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("1 B "), prettyPrint(1.0, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("1 kB"), prettyPrint(1.0e+3, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("1 MB"), prettyPrint(1.0e+6, PRETTY_BYTES_METRIC));
+  {string("0 B "), 0,  PRETTY_BYTES_METRIC},
+  {string("1 B "), 1.0,  PRETTY_BYTES_METRIC},
+  {string("1 kB"), 1.0e+3,  PRETTY_BYTES_METRIC},
+  {string("1 MB"), 1.0e+6,  PRETTY_BYTES_METRIC},
 
-  EXPECT_EQ(string("1 GB"), prettyPrint(1.0e+9, PRETTY_BYTES_METRIC));
-  EXPECT_EQ(string("1 TB"), prettyPrint(1.0e+12, PRETTY_BYTES_METRIC));
+  {string("1 GB"), 1.0e+9,  PRETTY_BYTES_METRIC},
+  {string("1 TB"), 1.0e+12,  PRETTY_BYTES_METRIC},
 
   // check metric-units (powers of 1000) printing
-  EXPECT_EQ(string("853  "), prettyPrint(853., PRETTY_UNITS_METRIC));
-  EXPECT_EQ(string("853 k"), prettyPrint(853.e3, PRETTY_UNITS_METRIC));
-  EXPECT_EQ(string("853 M"), prettyPrint(853.e6, PRETTY_UNITS_METRIC));
-  EXPECT_EQ(string("8.53 bil"), prettyPrint(8.53e9, PRETTY_UNITS_METRIC));
-  EXPECT_EQ(string("853 bil"), prettyPrint(853.e9, PRETTY_UNITS_METRIC));
-  EXPECT_EQ(string("853 tril"), prettyPrint(853.e12, PRETTY_UNITS_METRIC));
+  {string("853  "), 853.,  PRETTY_UNITS_METRIC},
+  {string("853 k"), 853.e3,  PRETTY_UNITS_METRIC},
+  {string("853 M"), 853.e6,  PRETTY_UNITS_METRIC},
+  {string("8.53 bil"), 8.53e9,  PRETTY_UNITS_METRIC},
+  {string("853 bil"), 853.e9,  PRETTY_UNITS_METRIC},
+  {string("853 tril"), 853.e12,  PRETTY_UNITS_METRIC},
 
   // check binary-units (powers of 1024) printing
-  EXPECT_EQ(string("0  "), prettyPrint(0, PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1  "), prettyPrint(pow2(0), PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1 k"), prettyPrint(pow2(10), PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1 M"), prettyPrint(pow2(20), PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1 G"), prettyPrint(pow2(30), PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1 T"), prettyPrint(pow2(40), PRETTY_UNITS_BINARY));
-
-  EXPECT_EQ(string("1023  "),
-      prettyPrint(pow2(10) - 1, PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1024 k"),
-      prettyPrint(pow2(20) - 1, PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1024 M"),
-      prettyPrint(pow2(30) - 1, PRETTY_UNITS_BINARY));
-  EXPECT_EQ(string("1024 G"),
-      prettyPrint(pow2(40) - 1, PRETTY_UNITS_BINARY));
-
-  EXPECT_EQ(string("0   "), prettyPrint(0, PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1   "), prettyPrint(pow2(0), PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1 Ki"), prettyPrint(pow2(10), PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1 Mi"), prettyPrint(pow2(20), PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1 Gi"), prettyPrint(pow2(30), PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1 Ti"), prettyPrint(pow2(40), PRETTY_UNITS_BINARY_IEC));
-
-  EXPECT_EQ(string("1023   "),
-      prettyPrint(pow2(10) - 1, PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1024 Ki"),
-      prettyPrint(pow2(20) - 1, PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1024 Mi"),
-      prettyPrint(pow2(30) - 1, PRETTY_UNITS_BINARY_IEC));
-  EXPECT_EQ(string("1024 Gi"),
-      prettyPrint(pow2(40) - 1, PRETTY_UNITS_BINARY_IEC));
+  {string("0  "), 0,  PRETTY_UNITS_BINARY},
+  {string("1  "), pow2(0),  PRETTY_UNITS_BINARY},
+  {string("1 k"), pow2(10),  PRETTY_UNITS_BINARY},
+  {string("1 M"), pow2(20),  PRETTY_UNITS_BINARY},
+  {string("1 G"), pow2(30),  PRETTY_UNITS_BINARY},
+  {string("1 T"), pow2(40),  PRETTY_UNITS_BINARY},
+
+  {string("1023  "), pow2(10) - 1,  PRETTY_UNITS_BINARY},
+  {string("1024 k"), pow2(20) - 1,  PRETTY_UNITS_BINARY},
+  {string("1024 M"), pow2(30) - 1,  PRETTY_UNITS_BINARY},
+  {string("1024 G"), pow2(40) - 1,  PRETTY_UNITS_BINARY},
+
+  {string("0   "), 0,  PRETTY_UNITS_BINARY_IEC},
+  {string("1   "), pow2(0),  PRETTY_UNITS_BINARY_IEC},
+  {string("1 Ki"), pow2(10),  PRETTY_UNITS_BINARY_IEC},
+  {string("1 Mi"), pow2(20),  PRETTY_UNITS_BINARY_IEC},
+  {string("1 Gi"), pow2(30),  PRETTY_UNITS_BINARY_IEC},
+  {string("1 Ti"), pow2(40),  PRETTY_UNITS_BINARY_IEC},
+
+  {string("1023   "), pow2(10) - 1,  PRETTY_UNITS_BINARY_IEC},
+  {string("1024 Ki"), pow2(20) - 1,  PRETTY_UNITS_BINARY_IEC},
+  {string("1024 Mi"), pow2(30) - 1,  PRETTY_UNITS_BINARY_IEC},
+  {string("1024 Gi"), pow2(40) - 1,  PRETTY_UNITS_BINARY_IEC},
+
+  //check border SI cases
+
+  {string("1 Y"), 1e24,  PRETTY_SI},
+  {string("10 Y"), 1e25,  PRETTY_SI},
+  {string("1 y"), 1e-24,  PRETTY_SI},
+  {string("10 y"), 1e-23,  PRETTY_SI},
 
   // check that negative values work
-  EXPECT_EQ(string("-85.3 s "), prettyPrint(-85.3, PRETTY_TIME));
-  EXPECT_EQ(string("-85.3 ms"), prettyPrint(-85.3e-3, PRETTY_TIME));
-  EXPECT_EQ(string("-85.3 us"), prettyPrint(-85.3e-6, PRETTY_TIME));
-  EXPECT_EQ(string("-85.3 ns"), prettyPrint(-85.3e-9, PRETTY_TIME));
+  {string("-85.3 s "), -85.3,  PRETTY_TIME},
+  {string("-85.3 ms"), -85.3e-3,  PRETTY_TIME},
+  {string("-85.3 us"), -85.3e-6,  PRETTY_TIME},
+  {string("-85.3 ns"), -85.3e-9,  PRETTY_TIME},
+  // end of test
+  {string("endoftest"), 0, PRETTY_NUM_TYPES}
+};
+
+TEST(PrettyPrint, Basic) {
+  for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
+    const PrettyTestCase& prettyTest = prettyTestCases[i];
+    EXPECT_EQ(prettyTest.prettyString,
+              prettyPrint(prettyTest.realValue, prettyTest.prettyType));
+  }
+}
+
+TEST(PrettyToDouble, Basic) {
+  // check manually created tests
+  for (int i = 0; prettyTestCases[i].prettyType != PRETTY_NUM_TYPES; ++i){
+    PrettyTestCase testCase = prettyTestCases[i];
+    PrettyType formatType = testCase.prettyType;
+    double x = testCase.realValue;
+    std::string testString = testCase.prettyString;
+    double recoveredX;
+    try{
+      recoveredX = prettyToDouble(testString, formatType);
+    } catch (std::range_error &ex){
+      EXPECT_TRUE(false);
+    }
+    double relativeError = fabs(x) < 1e-5 ? (x-recoveredX) :
+                                            (x - recoveredX) / x;
+    EXPECT_NEAR(0, relativeError, 1e-3);
+  }
+
+  // checks for compatibility with prettyPrint over the whole parameter space
+  for (int i = 0 ; i < PRETTY_NUM_TYPES; ++i){
+    PrettyType formatType = static_cast<PrettyType>(i);
+    for (double x = 1e-18; x < 1e40; x *= 1.9){
+      bool addSpace = static_cast<PrettyType> (i) == PRETTY_SI;
+      for (int it = 0; it < 2; ++it, addSpace = true){
+        double recoveredX;
+        try{
+          recoveredX = prettyToDouble(prettyPrint(x, formatType, addSpace),
+                                             formatType);
+        } catch (std::range_error &ex){
+          EXPECT_TRUE(false);
+        }
+        double relativeError = (x - recoveredX) / x;
+        EXPECT_NEAR(0, relativeError, 1e-3);
+      }
+    }
+  }
+
+  // check for incorrect values
+  EXPECT_THROW(prettyToDouble("10Mx", PRETTY_SI), std::range_error);
+  EXPECT_THROW(prettyToDouble("10 Mx", PRETTY_SI), std::range_error);
+  EXPECT_THROW(prettyToDouble("10 M x", PRETTY_SI), std::range_error);
+
+  StringPiece testString = "10Mx";
+  EXPECT_DOUBLE_EQ(prettyToDouble(&testString, PRETTY_UNITS_METRIC), 10e6);
+  EXPECT_EQ(testString, "x");
 }
 
 TEST(PrettyPrint, HexDump) {