automatic.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. #ifndef BOOST_NUMERIC_AUTOMATIC_HPP
  2. #define BOOST_NUMERIC_AUTOMATIC_HPP
  3. // Copyright (c) 2012 Robert Ramey
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. // policy which creates expanded results types designed
  9. // to avoid overflows.
  10. #include <limits>
  11. #include <cstdint> // (u)intmax_t,
  12. #include <type_traits> // conditional
  13. #include <boost/integer.hpp>
  14. #include "safe_common.hpp"
  15. #include "checked_result.hpp"
  16. #include "checked_default.hpp"
  17. #include "checked_integer.hpp"
  18. #include "checked_result_operations.hpp"
  19. #include "interval.hpp"
  20. #include "utility.hpp"
  21. namespace boost {
  22. namespace safe_numerics {
  23. struct automatic {
  24. private:
  25. // the following returns the "true" type. After calculating the new max and min
  26. // these return the minimum size type which can hold the expected result.
  27. struct defer_stored_signed_lazily {
  28. template<std::intmax_t Min, std::intmax_t Max>
  29. using type = utility::signed_stored_type<Min, Max>;
  30. };
  31. struct defer_stored_unsigned_lazily {
  32. template<std::uintmax_t Min, std::uintmax_t Max>
  33. using type = utility::unsigned_stored_type<Min, Max>;
  34. };
  35. template<typename T, T Min, T Max>
  36. struct result_type {
  37. using type = typename std::conditional<
  38. std::numeric_limits<T>::is_signed,
  39. defer_stored_signed_lazily,
  40. defer_stored_unsigned_lazily
  41. >::type::template type<Min, Max>;
  42. };
  43. public:
  44. ///////////////////////////////////////////////////////////////////////
  45. template<typename T, typename U>
  46. struct addition_result {
  47. using temp_base_type = typename std::conditional<
  48. // if both arguments are unsigned
  49. ! std::numeric_limits<T>::is_signed
  50. && ! std::numeric_limits<U>::is_signed,
  51. // result is unsigned
  52. std::uintmax_t,
  53. // otherwise result is signed
  54. std::intmax_t
  55. >::type;
  56. using r_type = checked_result<temp_base_type>;
  57. using r_interval_type = interval<r_type>;
  58. constexpr static const r_interval_type t_interval{
  59. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  60. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  61. };
  62. constexpr static const r_interval_type u_interval{
  63. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  64. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  65. };
  66. constexpr static const r_interval_type r_interval = t_interval + u_interval;
  67. constexpr static auto rl = r_interval.l;
  68. constexpr static auto ru = r_interval.u;
  69. using type = typename result_type<
  70. temp_base_type,
  71. rl.exception()
  72. ? std::numeric_limits<temp_base_type>::min()
  73. : static_cast<temp_base_type>(rl),
  74. ru.exception()
  75. ? std::numeric_limits<temp_base_type>::max()
  76. : static_cast<temp_base_type>(ru)
  77. >::type;
  78. };
  79. ///////////////////////////////////////////////////////////////////////
  80. template<typename T, typename U>
  81. struct subtraction_result {
  82. // result of subtraction are always signed.
  83. using temp_base_type = intmax_t;
  84. using r_type = checked_result<temp_base_type>;
  85. using r_interval_type = interval<r_type>;
  86. constexpr static const r_interval_type t_interval{
  87. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  88. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  89. };
  90. constexpr static const r_interval_type u_interval{
  91. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  92. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  93. };
  94. constexpr static const r_interval_type r_interval = t_interval - u_interval;
  95. constexpr static auto rl = r_interval.l;
  96. constexpr static auto ru = r_interval.u;
  97. using type = typename result_type<
  98. temp_base_type,
  99. rl.exception()
  100. ? std::numeric_limits<temp_base_type>::min()
  101. : static_cast<temp_base_type>(rl),
  102. ru.exception()
  103. ? std::numeric_limits<temp_base_type>::max()
  104. : static_cast<temp_base_type>(ru)
  105. >::type;
  106. };
  107. ///////////////////////////////////////////////////////////////////////
  108. template<typename T, typename U>
  109. struct multiplication_result {
  110. using temp_base_type = typename std::conditional<
  111. // if both arguments are unsigned
  112. ! std::numeric_limits<T>::is_signed
  113. && ! std::numeric_limits<U>::is_signed,
  114. // result is unsigned
  115. std::uintmax_t,
  116. // otherwise result is signed
  117. std::intmax_t
  118. >::type;
  119. using r_type = checked_result<temp_base_type>;
  120. using r_interval_type = interval<r_type>;
  121. constexpr static const r_interval_type t_interval{
  122. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  123. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  124. };
  125. constexpr static const r_interval_type u_interval{
  126. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  127. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  128. };
  129. constexpr static const r_interval_type r_interval = t_interval * u_interval;
  130. constexpr static const auto rl = r_interval.l;
  131. constexpr static const auto ru = r_interval.u;
  132. using type = typename result_type<
  133. temp_base_type,
  134. rl.exception()
  135. ? std::numeric_limits<temp_base_type>::min()
  136. : static_cast<temp_base_type>(rl),
  137. ru.exception()
  138. ? std::numeric_limits<temp_base_type>::max()
  139. : static_cast<temp_base_type>(ru)
  140. >::type;
  141. };
  142. ///////////////////////////////////////////////////////////////////////
  143. template<typename T, typename U>
  144. struct division_result {
  145. using temp_base_type = typename std::conditional<
  146. // if both arguments are unsigned
  147. ! std::numeric_limits<T>::is_signed
  148. && ! std::numeric_limits<U>::is_signed,
  149. // result is unsigned
  150. std::uintmax_t,
  151. // otherwise result is signed
  152. std::intmax_t
  153. >::type;
  154. using r_type = checked_result<temp_base_type>;
  155. using r_interval_type = interval<r_type>;
  156. constexpr static const r_interval_type t_interval{
  157. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  158. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  159. };
  160. constexpr static const r_interval_type u_interval{
  161. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  162. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  163. };
  164. constexpr static r_interval_type rx(){
  165. if(u_interval.u < r_type(0)
  166. || u_interval.l > r_type(0))
  167. return t_interval / u_interval;
  168. return utility::minmax(
  169. std::initializer_list<r_type> {
  170. t_interval.l / u_interval.l,
  171. t_interval.l / r_type(-1),
  172. t_interval.l / r_type(1),
  173. t_interval.l / u_interval.u,
  174. t_interval.u / u_interval.l,
  175. t_interval.u / r_type(-1),
  176. t_interval.u / r_type(1),
  177. t_interval.u / u_interval.u,
  178. }
  179. );
  180. }
  181. constexpr static const r_interval_type r_interval = rx();
  182. constexpr static auto rl = r_interval.l;
  183. constexpr static auto ru = r_interval.u;
  184. using type = typename result_type<
  185. temp_base_type,
  186. rl.exception()
  187. ? std::numeric_limits<temp_base_type>::min()
  188. : static_cast<temp_base_type>(rl),
  189. ru.exception()
  190. ? std::numeric_limits<temp_base_type>::max()
  191. : static_cast<temp_base_type>(ru)
  192. >::type;
  193. };
  194. ///////////////////////////////////////////////////////////////////////
  195. template<typename T, typename U>
  196. struct modulus_result {
  197. using temp_base_type = typename std::conditional<
  198. // if both arguments are unsigned
  199. ! std::numeric_limits<T>::is_signed
  200. && ! std::numeric_limits<U>::is_signed,
  201. // result is unsigned
  202. std::uintmax_t,
  203. // otherwise result is signed
  204. std::intmax_t
  205. >::type;
  206. using r_type = checked_result<temp_base_type>;
  207. using r_interval_type = interval<r_type>;
  208. constexpr static const r_interval_type t_interval{
  209. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  210. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  211. };
  212. constexpr static const r_interval_type u_interval{
  213. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  214. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  215. };
  216. constexpr static r_interval_type rx(){
  217. if(u_interval.u < r_type(0)
  218. || u_interval.l > r_type(0))
  219. return t_interval / u_interval;
  220. return utility::minmax(
  221. std::initializer_list<r_type> {
  222. t_interval.l % u_interval.l,
  223. t_interval.l % r_type(-1),
  224. t_interval.l % r_type(1),
  225. t_interval.l % u_interval.u,
  226. t_interval.u % u_interval.l,
  227. t_interval.u % r_type(-1),
  228. t_interval.u % r_type(1),
  229. t_interval.u % u_interval.u,
  230. }
  231. );
  232. }
  233. constexpr static const r_interval_type r_interval = rx();
  234. constexpr static auto rl = r_interval.l;
  235. constexpr static auto ru = r_interval.u;
  236. using type = typename result_type<
  237. temp_base_type,
  238. rl.exception()
  239. ? std::numeric_limits<temp_base_type>::min()
  240. : static_cast<temp_base_type>(rl),
  241. ru.exception()
  242. ? std::numeric_limits<temp_base_type>::max()
  243. : static_cast<temp_base_type>(ru)
  244. >::type;
  245. };
  246. ///////////////////////////////////////////////////////////////////////
  247. // note: comparison_result (<, >, ...) is special.
  248. // The return value is always a bool. The type returned here is
  249. // the intermediate type applied to make the values comparable.
  250. template<typename T, typename U>
  251. struct comparison_result {
  252. using temp_base_type = typename std::conditional<
  253. // if both arguments are unsigned
  254. ! std::numeric_limits<T>::is_signed
  255. && ! std::numeric_limits<U>::is_signed,
  256. // result is unsigned
  257. std::uintmax_t,
  258. // otherwise result is signed
  259. std::intmax_t
  260. >::type;
  261. using r_type = checked_result<temp_base_type>;
  262. using r_interval_type = interval<r_type>;
  263. constexpr static const r_interval_type t_interval{
  264. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  265. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  266. };
  267. constexpr static const r_interval_type u_interval{
  268. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  269. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  270. };
  271. // workaround some microsoft problem
  272. #if 0
  273. constexpr static r_type min(const r_type & t, const r_type & u){
  274. // assert(! u.exception());
  275. // assert(! t.exception());
  276. return static_cast<bool>(t < u) ? t : u;
  277. }
  278. constexpr static r_type max(const r_type & t, const r_type & u){
  279. // assert(! u.exception());
  280. // assert(! t.exception());
  281. return static_cast<bool>(t < u) ? u : t;
  282. }
  283. #endif
  284. // union of two intervals
  285. // note: we can't use t_interval | u_interval because it
  286. // depends on max and min which in turn depend on < which in turn
  287. // depends on implicit conversion of tribool to bool
  288. constexpr static r_interval_type union_interval(
  289. const r_interval_type & t,
  290. const r_interval_type & u
  291. ){
  292. //const r_type & rl = min(t.l, u.l);
  293. const r_type & rmin = static_cast<bool>(t.l < u.l) ? t.l : u.l;
  294. //const r_type & ru = max(t.u, u.u);
  295. const r_type & rmax = static_cast<bool>(t.u < u.u) ? u.u : t.u;
  296. return r_interval_type(rmin, rmax);
  297. }
  298. constexpr static const r_interval_type r_interval =
  299. union_interval(t_interval, u_interval);
  300. constexpr static auto rl = r_interval.l;
  301. constexpr static auto ru = r_interval.u;
  302. using type = typename result_type<
  303. temp_base_type,
  304. rl.exception()
  305. ? std::numeric_limits<temp_base_type>::min()
  306. : static_cast<temp_base_type>(rl),
  307. ru.exception()
  308. ? std::numeric_limits<temp_base_type>::max()
  309. : static_cast<temp_base_type>(ru)
  310. >::type;
  311. };
  312. ///////////////////////////////////////////////////////////////////////
  313. // shift operations
  314. template<typename T, typename U>
  315. struct left_shift_result {
  316. using temp_base_type = typename std::conditional<
  317. std::numeric_limits<T>::is_signed,
  318. std::intmax_t,
  319. std::uintmax_t
  320. >::type;
  321. using r_type = checked_result<temp_base_type>;
  322. using r_interval_type = interval<r_type>;
  323. constexpr static const r_interval_type t_interval{
  324. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  325. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  326. };
  327. constexpr static const r_interval_type u_interval{
  328. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
  329. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  330. };
  331. constexpr static const r_interval_type r_interval =
  332. t_interval << u_interval;
  333. constexpr static auto rl = r_interval.l;
  334. constexpr static auto ru = r_interval.u;
  335. using type = typename result_type<
  336. temp_base_type,
  337. rl.exception()
  338. ? std::numeric_limits<temp_base_type>::min()
  339. : static_cast<temp_base_type>(rl),
  340. ru.exception()
  341. ? std::numeric_limits<temp_base_type>::max()
  342. : static_cast<temp_base_type>(ru)
  343. >::type;
  344. };
  345. ///////////////////////////////////////////////////////////////////////
  346. template<typename T, typename U>
  347. struct right_shift_result {
  348. using temp_base_type = typename std::conditional<
  349. std::numeric_limits<T>::is_signed,
  350. std::intmax_t,
  351. std::uintmax_t
  352. >::type;
  353. using r_type = checked_result<temp_base_type>;
  354. using r_interval_type = interval<r_type>;
  355. constexpr static const r_interval_type t_interval{
  356. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
  357. checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
  358. };
  359. constexpr static const r_type u_min
  360. = checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min()));
  361. constexpr static const r_interval_type u_interval{
  362. u_min.exception()
  363. ? r_type(0)
  364. : u_min,
  365. checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
  366. };
  367. constexpr static const r_interval_type r_interval = t_interval >> u_interval;
  368. constexpr static auto rl = r_interval.l;
  369. constexpr static auto ru = r_interval.u;
  370. using type = typename result_type<
  371. temp_base_type,
  372. rl.exception()
  373. ? std::numeric_limits<temp_base_type>::min()
  374. : static_cast<temp_base_type>(rl),
  375. ru.exception()
  376. ? std::numeric_limits<temp_base_type>::max()
  377. : static_cast<temp_base_type>(ru)
  378. >::type;
  379. };
  380. ///////////////////////////////////////////////////////////////////////
  381. template<typename T, typename U>
  382. struct bitwise_and_result {
  383. using type = decltype(
  384. typename base_type<T>::type()
  385. & typename base_type<U>::type()
  386. );
  387. };
  388. template<typename T, typename U>
  389. struct bitwise_or_result {
  390. using type = decltype(
  391. typename base_type<T>::type()
  392. | typename base_type<U>::type()
  393. );
  394. };
  395. template<typename T, typename U>
  396. struct bitwise_xor_result {
  397. using type = decltype(
  398. typename base_type<T>::type()
  399. ^ typename base_type<U>::type()
  400. );
  401. };
  402. };
  403. } // safe_numerics
  404. } // boost
  405. #endif // BOOST_NUMERIC_AUTOMATIC_HPP