real_impl.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*=============================================================================
  2. Copyright (c) 2001-2019 Joel de Guzman
  3. Copyright (c) 2001-2011 Hartmut Kaiser
  4. http://spirit.sourceforge.net/
  5. Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #ifndef BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
  9. #define BOOST_SPIRIT_QI_NUMERIC_DETAIL_REAL_IMPL_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <cmath>
  14. #include <boost/limits.hpp>
  15. #include <boost/type_traits/is_same.hpp>
  16. #include <boost/spirit/home/support/unused.hpp>
  17. #include <boost/spirit/home/qi/detail/attributes.hpp>
  18. #include <boost/spirit/home/support/detail/pow10.hpp>
  19. #include <boost/integer.hpp>
  20. #include <boost/assert.hpp>
  21. #include <boost/core/cmath.hpp>
  22. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  23. # pragma warning(push)
  24. # pragma warning(disable: 4100) // 'p': unreferenced formal parameter
  25. # pragma warning(disable: 4127) // conditional expression is constant
  26. #endif
  27. namespace boost { namespace spirit { namespace traits
  28. {
  29. using spirit::traits::pow10;
  30. namespace detail
  31. {
  32. template <typename T, typename AccT>
  33. void compensate_roundoff(T& n, AccT acc_n, mpl::true_)
  34. {
  35. // at the lowest extremes, we compensate for floating point
  36. // roundoff errors by doing imprecise computation using T
  37. int const comp = 10;
  38. n = T((acc_n / comp) * comp);
  39. n += T(acc_n % comp);
  40. }
  41. template <typename T, typename AccT>
  42. void compensate_roundoff(T& n, AccT acc_n, mpl::false_)
  43. {
  44. // no need to compensate
  45. n = acc_n;
  46. }
  47. template <typename T, typename AccT>
  48. void compensate_roundoff(T& n, AccT acc_n)
  49. {
  50. compensate_roundoff(n, acc_n, is_integral<AccT>());
  51. }
  52. }
  53. template <typename T, typename AccT>
  54. inline bool
  55. scale(int exp, T& n, AccT acc_n)
  56. {
  57. if (exp >= 0)
  58. {
  59. int const max_exp = std::numeric_limits<T>::max_exponent10;
  60. // return false if exp exceeds the max_exp
  61. // do this check only for primitive types!
  62. if (is_floating_point<T>() && (exp > max_exp))
  63. return false;
  64. n = acc_n * pow10<T>(exp);
  65. }
  66. else
  67. {
  68. if (exp < std::numeric_limits<T>::min_exponent10)
  69. {
  70. int const min_exp = std::numeric_limits<T>::min_exponent10;
  71. detail::compensate_roundoff(n, acc_n);
  72. n /= pow10<T>(-min_exp);
  73. // return false if exp still exceeds the min_exp
  74. // do this check only for primitive types!
  75. exp += -min_exp;
  76. if (is_floating_point<T>() && exp < min_exp)
  77. return false;
  78. n /= pow10<T>(-exp);
  79. }
  80. else
  81. {
  82. n = T(acc_n) / pow10<T>(-exp);
  83. }
  84. }
  85. return true;
  86. }
  87. inline bool
  88. scale(int /*exp*/, unused_type /*n*/, unused_type /*acc_n*/)
  89. {
  90. // no-op for unused_type
  91. return true;
  92. }
  93. template <typename T, typename AccT>
  94. inline bool
  95. scale(int exp, int frac, T& n, AccT acc_n)
  96. {
  97. return scale(exp - frac, n, acc_n);
  98. }
  99. inline bool
  100. scale(int /*exp*/, int /*frac*/, unused_type /*n*/)
  101. {
  102. // no-op for unused_type
  103. return true;
  104. }
  105. inline float
  106. negate(bool neg, float n)
  107. {
  108. return neg ? (core::copysign)(n, -1.f) : n;
  109. }
  110. inline double
  111. negate(bool neg, double n)
  112. {
  113. return neg ? (core::copysign)(n, -1.) : n;
  114. }
  115. inline long double
  116. negate(bool neg, long double n)
  117. {
  118. return neg ? (core::copysign)(n, static_cast<long double>(-1)) : n;
  119. }
  120. template <typename T>
  121. inline T
  122. negate(bool neg, T const& n)
  123. {
  124. return neg ? -n : n;
  125. }
  126. inline unused_type
  127. negate(bool /*neg*/, unused_type n)
  128. {
  129. // no-op for unused_type
  130. return n;
  131. }
  132. template <typename T>
  133. struct real_accumulator : mpl::identity<T> {};
  134. template <>
  135. struct real_accumulator<float>
  136. : mpl::identity<uint_t<(sizeof(float)*CHAR_BIT)>::least> {};
  137. template <>
  138. struct real_accumulator<double>
  139. : mpl::identity<uint_t<(sizeof(double)*CHAR_BIT)>::least> {};
  140. }}}
  141. namespace boost { namespace spirit { namespace qi { namespace detail
  142. {
  143. BOOST_MPL_HAS_XXX_TRAIT_DEF(version)
  144. template <typename T, typename RealPolicies>
  145. struct real_impl
  146. {
  147. template <typename Iterator>
  148. static std::size_t
  149. ignore_excess_digits(Iterator& /* first */, Iterator const& /* last */, mpl::false_)
  150. {
  151. return 0;
  152. }
  153. template <typename Iterator>
  154. static std::size_t
  155. ignore_excess_digits(Iterator& first, Iterator const& last, mpl::true_)
  156. {
  157. return RealPolicies::ignore_excess_digits(first, last);
  158. }
  159. template <typename Iterator>
  160. static std::size_t
  161. ignore_excess_digits(Iterator& first, Iterator const& last)
  162. {
  163. typedef mpl::bool_<has_version<RealPolicies>::value> has_version;
  164. return ignore_excess_digits(first, last, has_version());
  165. }
  166. template <typename Iterator, typename Attribute>
  167. static bool
  168. parse(Iterator& first, Iterator const& last, Attribute& attr,
  169. RealPolicies const& p)
  170. {
  171. if (first == last)
  172. return false;
  173. Iterator save = first;
  174. // Start by parsing the sign. neg will be true if
  175. // we got a "-" sign, false otherwise.
  176. bool neg = p.parse_sign(first, last);
  177. // Now attempt to parse an integer
  178. T n;
  179. typename traits::real_accumulator<T>::type acc_n = 0;
  180. bool got_a_number = p.parse_n(first, last, acc_n);
  181. int excess_n = 0;
  182. // If we did not get a number it might be a NaN, Inf or a leading
  183. // dot.
  184. if (!got_a_number)
  185. {
  186. // Check whether the number to parse is a NaN or Inf
  187. if (p.parse_nan(first, last, n) ||
  188. p.parse_inf(first, last, n))
  189. {
  190. // If we got a negative sign, negate the number
  191. traits::assign_to(traits::negate(neg, n), attr);
  192. return true; // got a NaN or Inf, return early
  193. }
  194. // If we did not get a number and our policies do not
  195. // allow a leading dot, fail and return early (no-match)
  196. if (!p.allow_leading_dot)
  197. {
  198. first = save;
  199. return false;
  200. }
  201. }
  202. else
  203. {
  204. // We got a number and we still see digits. This happens if acc_n (an integer)
  205. // exceeds the integer's capacity. Collect the excess digits.
  206. excess_n = static_cast<int>(ignore_excess_digits(first, last));
  207. }
  208. bool e_hit = false;
  209. Iterator e_pos;
  210. int frac_digits = 0;
  211. // Try to parse the dot ('.' decimal point)
  212. if (p.parse_dot(first, last))
  213. {
  214. // We got the decimal point. Now we will try to parse
  215. // the fraction if it is there. If not, it defaults
  216. // to zero (0) only if we already got a number.
  217. if (excess_n != 0)
  218. {
  219. // We skip the fractions if we already exceeded our digits capacity
  220. ignore_excess_digits(first, last);
  221. }
  222. else if (p.parse_frac_n(first, last, acc_n, frac_digits))
  223. {
  224. BOOST_ASSERT(frac_digits >= 0);
  225. }
  226. else if (!got_a_number || !p.allow_trailing_dot)
  227. {
  228. // We did not get a fraction. If we still haven't got a
  229. // number and our policies do not allow a trailing dot,
  230. // return no-match.
  231. first = save;
  232. return false;
  233. }
  234. // Now, let's see if we can parse the exponent prefix
  235. e_pos = first;
  236. e_hit = p.parse_exp(first, last);
  237. }
  238. else
  239. {
  240. // No dot and no number! Return no-match.
  241. if (!got_a_number)
  242. {
  243. first = save;
  244. return false;
  245. }
  246. // If we must expect a dot and we didn't see an exponent
  247. // prefix, return no-match.
  248. e_pos = first;
  249. e_hit = p.parse_exp(first, last);
  250. if (p.expect_dot && !e_hit)
  251. {
  252. first = save;
  253. return false;
  254. }
  255. }
  256. if (e_hit)
  257. {
  258. // We got the exponent prefix. Now we will try to parse the
  259. // actual exponent.
  260. int exp = 0;
  261. if (p.parse_exp_n(first, last, exp))
  262. {
  263. // Got the exponent value. Scale the number by
  264. // exp + excess_n - frac_digits.
  265. if (!traits::scale(exp + excess_n, frac_digits, n, acc_n))
  266. return false;
  267. }
  268. else
  269. {
  270. // If there is no number, disregard the exponent altogether.
  271. // by resetting 'first' prior to the exponent prefix (e|E)
  272. first = e_pos;
  273. // Scale the number by -frac_digits.
  274. bool r = traits::scale(-frac_digits, n, acc_n);
  275. BOOST_VERIFY(r);
  276. }
  277. }
  278. else if (frac_digits)
  279. {
  280. // No exponent found. Scale the number by -frac_digits.
  281. bool r = traits::scale(-frac_digits, n, acc_n);
  282. BOOST_VERIFY(r);
  283. }
  284. else
  285. {
  286. if (excess_n)
  287. {
  288. if (!traits::scale(excess_n, n, acc_n))
  289. return false;
  290. }
  291. else
  292. {
  293. n = static_cast<T>(acc_n);
  294. }
  295. }
  296. // If we got a negative sign, negate the number
  297. traits::assign_to(traits::negate(neg, n), attr);
  298. // Success!!!
  299. return true;
  300. }
  301. };
  302. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  303. # pragma warning(pop)
  304. #endif
  305. }}}}
  306. #endif