signed_unsigned_tools.hpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* boost random/detail/signed_unsigned_tools.hpp header file
  2. *
  3. * Copyright Jens Maurer 2006
  4. * Distributed under the Boost Software License, Version 1.0. (See
  5. * accompanying file LICENSE_1_0.txt or copy at
  6. * http://www.boost.org/LICENSE_1_0.txt)
  7. *
  8. * See http://www.boost.org for most recent version including documentation.
  9. */
  10. #ifndef BOOST_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS
  11. #define BOOST_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS
  12. #include <boost/limits.hpp>
  13. #include <boost/config.hpp>
  14. #include <boost/random/traits.hpp>
  15. namespace boost {
  16. namespace random {
  17. namespace detail {
  18. /*
  19. * Compute x - y, we know that x >= y, return an unsigned value.
  20. */
  21. template<class T, bool sgn = std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_bounded>
  22. struct subtract { };
  23. template<class T>
  24. struct subtract<T, /* signed */ false>
  25. {
  26. typedef T result_type;
  27. result_type operator()(T x, T y) { return x - y; }
  28. };
  29. template<class T>
  30. struct subtract<T, /* signed */ true>
  31. {
  32. typedef typename boost::random::traits::make_unsigned_or_unbounded<T>::type result_type;
  33. result_type operator()(T x, T y)
  34. {
  35. if (y >= 0) // because x >= y, it follows that x >= 0, too
  36. return result_type(x) - result_type(y);
  37. if (x >= 0) // y < 0
  38. // avoid the nasty two's complement case for y == min()
  39. return result_type(x) + result_type(-(y+1)) + 1;
  40. // both x and y are negative: no signed overflow
  41. return result_type(x - y);
  42. }
  43. };
  44. /*
  45. * Compute x + y, x is unsigned, result fits in type of "y".
  46. */
  47. template<class T1, class T2, bool sgn = (std::numeric_limits<T2>::is_signed && (std::numeric_limits<T1>::digits >= std::numeric_limits<T2>::digits))>
  48. struct add { };
  49. template<class T1, class T2>
  50. struct add<T1, T2, /* signed or else T2 has more digits than T1 so the cast always works - needed when T2 is a multiprecision type and T1 is a native integer */ false>
  51. {
  52. typedef T2 result_type;
  53. result_type operator()(T1 x, T2 y) { return T2(x) + y; }
  54. };
  55. template<class T1, class T2>
  56. struct add<T1, T2, /* signed */ true>
  57. {
  58. typedef T2 result_type;
  59. result_type operator()(T1 x, T2 y)
  60. {
  61. if (y >= 0)
  62. return T2(x) + y;
  63. // y < 0
  64. if (x > T1(-(y+1))) // result >= 0 after subtraction
  65. // avoid the nasty two's complement edge case for y == min()
  66. return T2(x - T1(-(y+1)) - 1);
  67. // abs(x) < abs(y), thus T2 able to represent x
  68. return T2(x) + y;
  69. }
  70. };
  71. } // namespace detail
  72. } // namespace random
  73. } // namespace boost
  74. #endif // BOOST_RANDOM_DETAIL_SIGNED_UNSIGNED_TOOLS