libfoedus-core
FOEDUS Core Library
const_div.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
18 #ifndef FOEDUS_ASSORTED_CONST_DIV_HPP_
19 #define FOEDUS_ASSORTED_CONST_DIV_HPP_
20 #include <stdint.h>
21 
22 #include "foedus/assert_nd.hpp"
23 #include "foedus/cxx11.hpp"
24 
25 namespace foedus {
26 namespace assorted {
27 const uint32_t kPower2To31 = 1U << 31;
28 const uint64_t kPower2To63 = 1ULL << 63;
29 const uint32_t kFull32Bits = 0xFFFFFFFF;
30 const uint32_t kFull31Bits = 0x7FFFFFFF;
31 const uint64_t kFull64Bits = 0xFFFFFFFFFFFFFFFFULL;
32 const uint64_t kFull63Bits = 0x7FFFFFFFFFFFFFFFULL;
33 
67 struct ConstDiv {
68  enum Constants {
72  kFlagAdd32 = 0x02,
74  kFlagAdd64 = 0x04,
75  };
76 
81  explicit ConstDiv(uint32_t d) {
82  init(d);
83  }
84 
86  init(1);
87  }
88 
89  void init(uint32_t d);
90 
99  uint32_t div32(uint32_t n) const;
101  uint32_t rem32(uint32_t n, uint32_t d, uint32_t q) const;
102 
108  uint64_t div64(uint64_t n) const;
110  uint32_t rem64(uint64_t n, uint32_t d, uint64_t q) const;
111 
113  uint8_t d_highest_bits_; // +1 => 1
114 
116  uint8_t shift32_; // +1 => 2
117 
119  uint8_t shift64_; // +1 => 3
120 
122  uint8_t flags_; // +1 => 4
123 
125  uint32_t magic32_; // +4 => 8
126 
128  uint64_t magic64_; // +8 => 16
129 
130 #ifndef NDEBUG
131 
132  uint32_t d_;
133  uint32_t dummy_;
134 #endif // NDEBUG
135 };
136 
137 inline void ConstDiv::init(uint32_t d) {
138  // this one is inlined just to avoid multiple-definition, not for performance.
139  ASSERT_ND(d);
140  d_highest_bits_ = 31 - __builtin_clz(d); // TASK(Hideaki): non-GCC support
141 #ifndef NDEBUG
142  d_ = d;
143  dummy_ = 0;
144 #endif // NDEBUG
145 
146  // power of 2 is a bit special.
147  if ((d & (d - 1)) == 0) {
148  ASSERT_ND(d == (1U << d_highest_bits_));
149  shift32_ = 0;
150  shift64_ = 0;
152  magic32_ = 0;
153  magic64_ = 0;
154  return;
155  }
156 
157  flags_ = 0;
158 
159  // calculate 32bit/64bit magic numbers and add indicator, this part is based on [libdivide-pdf]
160  // rather than [HACKERS] although it is also based on [HACKERS].
161  {
163  uint32_t m = (1ULL << (32 + d_highest_bits_)) / d;
164  uint32_t rem = (1ULL << (32 + d_highest_bits_)) % d;
165  ASSERT_ND(rem > 0 && rem < d);
166  uint32_t e = d - rem;
167  if (e >= (1U << d_highest_bits_)) {
168  // we have add indicator (2^W <= M < 2^(W+1), m = M - 2^W).
169  // here is a nice idea in libdivide.
170  // We let it overflow, but we do so for remainder too, thus even with overflow
171  // we can correctly calculate the quotient!
172  // We use the magic number for this case with divide-by-2 in div32 to account for this.
173  flags_ |= kFlagAdd32;
174  m *= 2;
175  uint32_t twice_rem = rem * 2;
176  if (twice_rem >= d || twice_rem < rem) {
177  ++m;
178  }
179  }
180  magic32_ = m + 1;
181  }
182 
183  // then 64bit version.
184  {
186  // At least GCC and clang supports __uint128_t
187  __uint128_t numer = 1;
188  numer <<= 64 + d_highest_bits_;
189  uint64_t m = numer / d;
190  uint32_t rem = numer % d;
191  ASSERT_ND(rem > 0 && rem < d);
192  uint32_t e = d - rem;
193  if (e >= (1ULL << d_highest_bits_)) {
194  flags_ |= kFlagAdd64;
195  m *= 2;
196  uint32_t twice_rem = rem * 2;
197  if (twice_rem >= d || twice_rem < rem) {
198  ++m;
199  }
200  }
201  magic64_ = m + 1;
202  }
203 }
204 
205 inline uint32_t ConstDiv::rem32(uint32_t n, uint32_t d, uint32_t q) const {
206 #ifndef NDEBUG
207  ASSERT_ND(d == d_);
208 #endif // NDEBUG
209  ASSERT_ND(n / d == q);
210  if (flags_ & kFlagPowerOfTwo) {
211  return n & ((1 << d_highest_bits_) - 1);
212  } else {
213  return n - d * q;
214  }
215 }
216 inline uint32_t ConstDiv::rem64(uint64_t n, uint32_t d, uint64_t q) const {
217 #ifndef NDEBUG
218  ASSERT_ND(d == d_);
219 #endif // NDEBUG
220  ASSERT_ND(n / d == q);
221  if (flags_ & kFlagPowerOfTwo) {
222  return n & ((1ULL << d_highest_bits_) - 1ULL);
223  } else {
224  return n - d * q;
225  }
226 }
227 
228 inline uint32_t ConstDiv::div32(uint32_t n) const {
229  if (flags_ & kFlagPowerOfTwo) {
230  return n >> d_highest_bits_;
231  } else {
232  uint64_t product = static_cast<uint64_t>(n) * magic32_;
233  uint32_t quotient = static_cast<uint32_t>(product >> 32);
234  if (flags_ & kFlagAdd32) {
235  quotient += (n - quotient) >> 1;
236  }
237  return quotient >> shift32_;
238  }
239 }
240 
241 inline uint64_t ConstDiv::div64(uint64_t n) const {
242  if (flags_ & kFlagPowerOfTwo) {
243  return n >> d_highest_bits_;
244  }
245 
246  if (n < (1ULL << 32)) {
247  // cheap case
248  return div32(static_cast<uint32_t>(n));
249  }
250 
251  ASSERT_ND(n >= (1ULL << 32));
252  // At least GCC and clang supports __uint128_t
253  __uint128_t product = static_cast<__uint128_t>(n) * magic64_;
254  uint64_t quotient = static_cast<uint64_t>(product >> 64);
255  if (flags_ & kFlagAdd64) {
256  quotient += (n - quotient) >> 1;
257  }
258  return quotient >> shift64_;
259 }
260 
261 } // namespace assorted
262 } // namespace foedus
263 #endif // FOEDUS_ASSORTED_CONST_DIV_HPP_
uint8_t flags_
misc flags.
Definition: const_div.hpp:122
Add inidicator for 64bit division.
Definition: const_div.hpp:74
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
const uint32_t kPower2To31
Definition: const_div.hpp:27
ConstDiv(uint32_t d)
Pre-calculate the p-m pair for the given divisor.
Definition: const_div.hpp:81
The pre-calculated p-m pair for optimized integer division by constant.
Definition: const_div.hpp:67
const uint64_t kFull63Bits
Definition: const_div.hpp:32
uint32_t magic32_
magic number for 32 bit division.
Definition: const_div.hpp:125
uint32_t d_
Oridinal divisor.
Definition: const_div.hpp:132
Whether the divisor is a power of 2.
Definition: const_div.hpp:70
uint32_t rem32(uint32_t n, uint32_t d, uint32_t q) const
Calculate remainder.
Definition: const_div.hpp:205
const uint64_t kPower2To63
Definition: const_div.hpp:28
const uint32_t kFull32Bits
Definition: const_div.hpp:29
Add inidicator for 32bit division.
Definition: const_div.hpp:72
uint64_t magic64_
magic number for 64 bit division.
Definition: const_div.hpp:128
uint8_t d_highest_bits_
Highest bits to represent d.
Definition: const_div.hpp:113
const uint64_t kFull64Bits
Definition: const_div.hpp:31
uint8_t shift32_
"s" for 32 bit division.
Definition: const_div.hpp:116
const uint32_t kFull31Bits
Definition: const_div.hpp:30
uint32_t rem64(uint64_t n, uint32_t d, uint64_t q) const
Calculate remainder.
Definition: const_div.hpp:216
void init(uint32_t d)
Definition: const_div.hpp:137
uint8_t shift64_
"s" for 64 bit division.
Definition: const_div.hpp:119
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
Definition: assert_nd.hpp:72
uint64_t div64(uint64_t n) const
64-bit integer division that outputs both quotient and remainder.
Definition: const_div.hpp:241
uint32_t div32(uint32_t n) const
32-bit integer division that outputs both quotient and remainder.
Definition: const_div.hpp:228