blob: c9c6434311df155f15a84b505c2c0ee7d7c7b071 [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001/* 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: large_arithmetic.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $
11 */
12
13#ifndef NDNBOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP
14#define NDNBOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP
15
16#include <ndnboost/cstdint.hpp>
17#include <ndnboost/integer.hpp>
18#include <ndnboost/limits.hpp>
19#include <ndnboost/random/detail/integer_log2.hpp>
20
21#include <ndnboost/random/detail/disable_warnings.hpp>
22
23namespace ndnboost {
24namespace random {
25namespace detail {
26
27struct div_t {
28 ndnboost::uintmax_t quotient;
29 ndnboost::uintmax_t remainder;
30};
31
32inline div_t muldivmod(ndnboost::uintmax_t a, ndnboost::uintmax_t b, ndnboost::uintmax_t m)
33{
34 static const int bits =
35 ::std::numeric_limits< ::ndnboost::uintmax_t>::digits / 2;
36 static const ::ndnboost::uintmax_t mask = (::ndnboost::uintmax_t(1) << bits) - 1;
37 typedef ::ndnboost::uint_t<bits>::fast digit_t;
38
39 int shift = std::numeric_limits< ::ndnboost::uintmax_t>::digits - 1
40 - detail::integer_log2(m);
41
42 a <<= shift;
43 m <<= shift;
44
45 digit_t product[4] = { 0, 0, 0, 0 };
46 digit_t a_[2] = { digit_t(a & mask), digit_t((a >> bits) & mask) };
47 digit_t b_[2] = { digit_t(b & mask), digit_t((b >> bits) & mask) };
48 digit_t m_[2] = { digit_t(m & mask), digit_t((m >> bits) & mask) };
49
50 // multiply a * b
51 for(int i = 0; i < 2; ++i) {
52 digit_t carry = 0;
53 for(int j = 0; j < 2; ++j) {
54 ::ndnboost::uint64_t temp = ::ndnboost::uintmax_t(a_[i]) * b_[j] +
55 carry + product[i + j];
56 product[i + j] = digit_t(temp & mask);
57 carry = digit_t(temp >> bits);
58 }
59 if(carry != 0) {
60 product[i + 2] += carry;
61 }
62 }
63
64 digit_t quotient[2];
65
66 if(m == 0) {
67 div_t result = {
68 ((::ndnboost::uintmax_t(product[3]) << bits) | product[2]),
69 ((::ndnboost::uintmax_t(product[1]) << bits) | product[0]) >> shift,
70 };
71 return result;
72 }
73
74 // divide product / m
75 for(int i = 3; i >= 2; --i) {
76 ::ndnboost::uintmax_t temp =
77 ::ndnboost::uintmax_t(product[i]) << bits | product[i - 1];
78
79 digit_t q = digit_t((product[i] == m_[1]) ? mask : temp / m_[1]);
80
81 ::ndnboost::uintmax_t rem =
82 ((temp - ::ndnboost::uintmax_t(q) * m_[1]) << bits) + product[i - 2];
83
84 ::ndnboost::uintmax_t diff = m_[0] * ::ndnboost::uintmax_t(q);
85
86 int error = 0;
87 if(diff > rem) {
88 if(diff - rem > m) {
89 error = 2;
90 } else {
91 error = 1;
92 }
93 }
94 q -= error;
95 rem = rem + error * m - diff;
96
97 quotient[i - 2] = q;
98 product[i] = 0;
99 product[i-1] = (rem >> bits) & mask;
100 product[i-2] = rem & mask;
101 }
102
103 div_t result = {
104 ((::ndnboost::uintmax_t(quotient[1]) << bits) | quotient[0]),
105 ((::ndnboost::uintmax_t(product[1]) << bits) | product[0]) >> shift,
106 };
107 return result;
108}
109
110inline ndnboost::uintmax_t muldiv(ndnboost::uintmax_t a, ndnboost::uintmax_t b, ndnboost::uintmax_t m)
111{ return detail::muldivmod(a, b, m).quotient; }
112
113inline ndnboost::uintmax_t mulmod(ndnboost::uintmax_t a, ndnboost::uintmax_t b, ndnboost::uintmax_t m)
114{ return detail::muldivmod(a, b, m).remainder; }
115
116} // namespace detail
117} // namespace random
118} // namespace ndnboost
119
120#include <ndnboost/random/detail/enable_warnings.hpp>
121
122#endif // NDNBOOST_RANDOM_DETAIL_LARGE_ARITHMETIC_HPP