large_arithmetic.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /* boost random/detail/large_arithmetic.hpp header file
  2. *
  3. * Copyright Steven Watanabe 2011
  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. * $Id$
  11. */
  12. #ifndef BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP
  13. #define BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP
  14. #include <boost/cstdint.hpp>
  15. #include <boost/integer.hpp>
  16. #include <boost/limits.hpp>
  17. #include <boost/random/detail/integer_log2.hpp>
  18. #include <boost/random/detail/disable_warnings.hpp>
  19. namespace boost {
  20. namespace random {
  21. namespace detail {
  22. struct div_t {
  23. boost::uintmax_t quotient;
  24. boost::uintmax_t remainder;
  25. };
  26. inline div_t muldivmod(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m)
  27. {
  28. const int bits =
  29. ::std::numeric_limits< ::boost::uintmax_t>::digits / 2;
  30. const ::boost::uintmax_t mask = (::boost::uintmax_t(1) << bits) - 1;
  31. typedef ::boost::uint_t<bits>::fast digit_t;
  32. int shift = std::numeric_limits< ::boost::uintmax_t>::digits - 1
  33. - detail::integer_log2(m);
  34. a <<= shift;
  35. m <<= shift;
  36. digit_t product[4] = { 0, 0, 0, 0 };
  37. digit_t a_[2] = { digit_t(a & mask), digit_t((a >> bits) & mask) };
  38. digit_t b_[2] = { digit_t(b & mask), digit_t((b >> bits) & mask) };
  39. digit_t m_[2] = { digit_t(m & mask), digit_t((m >> bits) & mask) };
  40. // multiply a * b
  41. for(int i = 0; i < 2; ++i) {
  42. digit_t carry = 0;
  43. for(int j = 0; j < 2; ++j) {
  44. ::boost::uint64_t temp = ::boost::uintmax_t(a_[i]) * b_[j] +
  45. carry + product[i + j];
  46. product[i + j] = digit_t(temp & mask);
  47. carry = digit_t(temp >> bits);
  48. }
  49. if(carry != 0) {
  50. product[i + 2] += carry;
  51. }
  52. }
  53. digit_t quotient[2];
  54. if(m == 0) {
  55. div_t result = {
  56. ((::boost::uintmax_t(product[3]) << bits) | product[2]),
  57. ((::boost::uintmax_t(product[1]) << bits) | product[0]) >> shift,
  58. };
  59. return result;
  60. }
  61. // divide product / m
  62. for(int i = 3; i >= 2; --i) {
  63. ::boost::uintmax_t temp =
  64. ::boost::uintmax_t(product[i]) << bits | product[i - 1];
  65. digit_t q = digit_t((product[i] == m_[1]) ? mask : temp / m_[1]);
  66. ::boost::uintmax_t rem =
  67. ((temp - ::boost::uintmax_t(q) * m_[1]) << bits) + product[i - 2];
  68. ::boost::uintmax_t diff = m_[0] * ::boost::uintmax_t(q);
  69. int error = 0;
  70. if(diff > rem) {
  71. if(diff - rem > m) {
  72. error = 2;
  73. } else {
  74. error = 1;
  75. }
  76. }
  77. q -= error;
  78. rem = rem + error * m - diff;
  79. quotient[i - 2] = q;
  80. product[i] = 0;
  81. product[i-1] = static_cast<digit_t>((rem >> bits) & mask);
  82. product[i-2] = static_cast<digit_t>(rem & mask);
  83. }
  84. div_t result = {
  85. ((::boost::uintmax_t(quotient[1]) << bits) | quotient[0]),
  86. ((::boost::uintmax_t(product[1]) << bits) | product[0]) >> shift,
  87. };
  88. return result;
  89. }
  90. inline boost::uintmax_t muldiv(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m)
  91. { return detail::muldivmod(a, b, m).quotient; }
  92. inline boost::uintmax_t mulmod(boost::uintmax_t a, boost::uintmax_t b, boost::uintmax_t m)
  93. { return detail::muldivmod(a, b, m).remainder; }
  94. } // namespace detail
  95. } // namespace random
  96. } // namespace boost
  97. #include <boost/random/detail/enable_warnings.hpp>
  98. #endif // BOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP