NumericString.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //
  2. // NumericString.h
  3. //
  4. // $Id: //poco/1.4/Foundation/src/NumericString.cpp#1 $
  5. //
  6. // Library: Foundation
  7. // Package: Core
  8. // Module: NumericString
  9. //
  10. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #include "Poco/Bugcheck.h"
  16. // +++ double conversion +++
  17. #define UNREACHABLE poco_bugcheck
  18. #define UNIMPLEMENTED poco_bugcheck
  19. #include "diy-fp.cc"
  20. #include "cached-powers.cc"
  21. #include "bignum-dtoa.cc"
  22. #include "bignum.cc"
  23. #include "fast-dtoa.cc"
  24. #include "fixed-dtoa.cc"
  25. #include "strtod.cc"
  26. #include "double-conversion.cc"
  27. // --- double conversion ---
  28. #include "Poco/NumericString.h"
  29. poco_static_assert(POCO_MAX_FLT_STRING_LEN == double_conversion::kMaxSignificantDecimalDigits);
  30. #include "Poco/String.h"
  31. #include <memory>
  32. #include <cctype>
  33. namespace {
  34. void pad(std::string& str, int precision, int width, char prefix = ' ', char decSep = '.')
  35. /// Pads the string with prefix space and postfix 0.
  36. /// Alternative prefix (e.g. zero instead of space) can be supplied by caller.
  37. /// Used only internally.
  38. {
  39. // these cases should never happen, if they do, it's a library bug
  40. poco_assert_dbg (precision > 0);
  41. poco_assert_dbg (str.length());
  42. std::string::size_type decSepPos = str.find(decSep);
  43. if (decSepPos == std::string::npos)
  44. {
  45. str.append(1, '.');
  46. decSepPos = str.size() - 1;
  47. }
  48. std::string::size_type frac = str.length() - decSepPos - 1;
  49. std::string::size_type ePos = str.find_first_of("eE");
  50. std::auto_ptr<std::string> eStr;
  51. if (ePos != std::string::npos)
  52. {
  53. eStr.reset(new std::string(str.substr(ePos, std::string::npos)));
  54. frac -= eStr->length();
  55. str = str.substr(0, str.length() - eStr->length());
  56. }
  57. if (frac != precision)
  58. {
  59. if (frac < precision)
  60. str.append(precision - frac, '0');
  61. else if ((frac > precision) && (decSepPos != std::string::npos))
  62. str = str.substr(0, decSepPos + 1 + precision);
  63. }
  64. if (eStr.get()) str += *eStr;
  65. if (width && (str.length() < width)) str.insert(str.begin(), width - str.length(), prefix);
  66. }
  67. void insertThousandSep(std::string& str, char thSep, char decSep = '.')
  68. /// Inserts thousand separators.
  69. /// Used only internally.
  70. {
  71. poco_assert (decSep != thSep);
  72. if (str.size() == 0) return;
  73. std::string::size_type exPos = str.find('e');
  74. if (exPos == std::string::npos) exPos = str.find('E');
  75. std::string::size_type decPos = str.find(decSep);
  76. // there's no rinsert, using forward iterator to go backwards
  77. std::string::iterator it = str.end();
  78. if (exPos != std::string::npos) it -= str.size() - exPos;
  79. if (decPos != std::string::npos)
  80. {
  81. while (it != str.begin())
  82. {
  83. --it;
  84. if (*it == decSep) break;
  85. }
  86. }
  87. int thCount = 0;
  88. if (it == str.end()) --it;
  89. for (; it != str.begin();)
  90. {
  91. std::string::iterator pos = it;
  92. std::string::value_type chr = *it;
  93. std::string::value_type prevChr = *--it;
  94. if (!std::isdigit(chr)) continue;
  95. if (++thCount == 3 && std::isdigit(prevChr))
  96. it = str.insert(pos, thSep);
  97. if (thCount == 3) thCount = 0;
  98. }
  99. }
  100. } // namespace
  101. namespace Poco {
  102. void floatToStr(char* buffer, int bufferSize, float value, int lowDec, int highDec)
  103. {
  104. using namespace double_conversion;
  105. StringBuilder builder(buffer, bufferSize);
  106. int flags = DoubleToStringConverter::UNIQUE_ZERO |
  107. DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
  108. DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP, lowDec, highDec, 0, 0);
  109. dc.ToShortestSingle(value, &builder);
  110. builder.Finalize();
  111. }
  112. std::string& floatToStr(std::string& str, float value, int precision, int width, char thSep, char decSep)
  113. {
  114. if (!decSep) decSep = '.';
  115. if (precision == 0) value = std::floor(value);
  116. char buffer[POCO_MAX_FLT_STRING_LEN];
  117. floatToStr(buffer, POCO_MAX_FLT_STRING_LEN, value);
  118. str = buffer;
  119. if (decSep && (decSep != '.') && (str.find('.') != std::string::npos))
  120. replaceInPlace(str, '.', decSep);
  121. if (thSep) insertThousandSep(str, thSep, decSep);
  122. if (precision > 0 || width) pad(str, precision, width, ' ', decSep ? decSep : '.');
  123. return str;
  124. }
  125. void doubleToStr(char* buffer, int bufferSize, double value, int lowDec, int highDec)
  126. {
  127. using namespace double_conversion;
  128. StringBuilder builder(buffer, bufferSize);
  129. int flags = DoubleToStringConverter::UNIQUE_ZERO |
  130. DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
  131. DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP, lowDec, highDec, 0, 0);
  132. dc.ToShortest(value, &builder);
  133. builder.Finalize();
  134. }
  135. std::string& doubleToStr(std::string& str, double value, int precision, int width, char thSep, char decSep)
  136. {
  137. if (!decSep) decSep = '.';
  138. if (precision == 0) value = std::floor(value);
  139. char buffer[POCO_MAX_FLT_STRING_LEN];
  140. doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, value);
  141. str = buffer;
  142. if (decSep && (decSep != '.') && (str.find('.') != std::string::npos))
  143. replaceInPlace(str, '.', decSep);
  144. if (thSep) insertThousandSep(str, thSep, decSep);
  145. if (precision > 0 || width) pad(str, precision, width, ' ', decSep ? decSep : '.');
  146. return str;
  147. }
  148. float strToFloat(const char* str)
  149. {
  150. using namespace double_conversion;
  151. int processed;
  152. int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
  153. StringToDoubleConverter::ALLOW_TRAILING_SPACES;
  154. StringToDoubleConverter converter(flags, 0.0, Single::NaN(), POCO_FLT_INF, POCO_FLT_NAN);
  155. float result = converter.StringToFloat(str, static_cast<int>(strlen(str)), &processed);
  156. return result;
  157. }
  158. double strToDouble(const char* str)
  159. {
  160. using namespace double_conversion;
  161. int processed;
  162. int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
  163. StringToDoubleConverter::ALLOW_TRAILING_SPACES;
  164. StringToDoubleConverter converter(flags, 0.0, Double::NaN(), POCO_FLT_INF, POCO_FLT_NAN);
  165. double result = converter.StringToDouble(str, static_cast<int>(strlen(str)), &processed);
  166. return result;
  167. }
  168. bool strToFloat(const std::string& str, float& result, char decSep, char thSep)
  169. {
  170. using namespace double_conversion;
  171. std::string tmp(str);
  172. trimInPlace(tmp);
  173. removeInPlace(tmp, thSep);
  174. removeInPlace(tmp, 'f');
  175. replaceInPlace(tmp, decSep, '.');
  176. result = strToFloat(tmp.c_str());
  177. return !FPEnvironment::isInfinite(result) &&
  178. !FPEnvironment::isNaN(result);
  179. }
  180. bool strToDouble(const std::string& str, double& result, char decSep, char thSep)
  181. {
  182. if (str.empty()) return false;
  183. using namespace double_conversion;
  184. std::string tmp(str);
  185. trimInPlace(tmp);
  186. removeInPlace(tmp, thSep);
  187. replaceInPlace(tmp, decSep, '.');
  188. removeInPlace(tmp, 'f');
  189. result = strToDouble(tmp.c_str());
  190. return !FPEnvironment::isInfinite(result) &&
  191. !FPEnvironment::isNaN(result);
  192. }
  193. } // namespace Poco