Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
constant_divisor.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_BASE_CONSTANT_DIVISOR_H_
15#define OR_TOOLS_BASE_CONSTANT_DIVISOR_H_
16
17// Provides faster division in situations where the same divisor is used
18// repeatedly but is not known at compile time. For example, a hash table might
19// not be sized until the model is loaded, but once loaded it is not resized for
20// the life of the model. As this is not a compile time constant, the compiler
21// can not optimize away the division.
22//
23// However the cost of precomputing coefficients when the hash table is sized
24// can be dwarfed by the cycles saved avoiding hardware division on every
25// lookup. See benchmark section below to estimate the breakeven point. This
26// reduces the CPU penalty of non-power of two sized hash tables, bloom filters,
27// etc.
28//
29//
30// The following template and specializations are defined in this file:
31// - ConstantDivisor<T>
32// - ConstantDivisor<uint8_t>
33// - ConstantDivisor<uint16_t>
34// - ConstantDivisor<uint32_t> (Only supports denominators > 1)
35// - ConstantDivisor<uint64_t> (Only supports denominators > 1)
36//
37// Fast div/mod implementation based on
38// "Faster Remainder by Direct Computation: Applications to Compilers and
39// Software Libraries" Daniel Lemire, Owen Kaser, Nathan Kurz arXiv:1902.01961
40//
41// Usage:
42// uint64_t n; // Not known at compile time!
43// ConstantDivisor<uint64_t> divisor(n);
44// uint64_t m = ...;
45// EXPECT_EQ(m / n, divisor.div(m));
46// EXPECT_EQ(m % n, divisor.mod(m));
47//
48
49#include <cstdint>
50
51#include "absl/numeric/int128.h"
52
53namespace util {
54namespace math {
55
56template <typename T>
58 public:
59 typedef T value_type;
60
61 explicit ConstantDivisor(value_type denominator)
62 : denominator_(denominator) {}
63
64 value_type div(value_type n) const { return n / denominator_; }
65
66 value_type mod(value_type n) const { return n % denominator_; }
67
69 return b.div(a);
70 }
71
73 return b.mod(a);
74 }
75
76 private:
77 value_type denominator_;
78};
79
80namespace internal {
81
82// Common code for all specializations.
83template <typename T, typename MagicT, typename Impl>
85 public:
86 using value_type = T;
87
89 : magic_(magic), denominator_(denominator) {}
90
91 value_type mod(value_type numerator) const {
92 return numerator -
93 static_cast<const Impl*>(this)->div(numerator) * denominator_;
94 }
95
96 friend value_type operator/(value_type a, const Impl& b) { return b.div(a); }
97
98 friend value_type operator%(value_type a, const Impl& b) { return b.mod(a); }
99
100 value_type denominator() const { return denominator_; }
101
102 protected:
103 using MagicValueType = MagicT;
104 static_assert(sizeof(MagicT) >= 2 * sizeof(value_type));
105 MagicT magic_;
106
107 private:
108 value_type denominator_;
109};
110} // namespace internal
111
112// Division and modulus using uint64_t numerators and denominators.
113template <>
114class ConstantDivisor<uint64_t>
115 : public internal::ConstantDivisorBase<uint64_t, absl::uint128,
116 ConstantDivisor<uint64_t>> {
117 public:
118 // REQUIRES: denominator > 1
120
121 value_type div(value_type numerator) const {
122 return MultiplyHi(magic_, numerator);
123 }
124
125 private:
126 static uint64_t MultiplyHi(absl::uint128 a, uint64_t b) {
127 absl::uint128 lo(absl::Uint128Low64(a));
128 absl::uint128 hi(absl::Uint128High64(a));
129 absl::uint128 bottom = (lo * b) >> 64;
130 absl::uint128 top = (hi * b);
131 return absl::Uint128High64(bottom + top);
132 }
133};
134
135// Division and modulus using uint32_t numerators and denominators.
136template <>
137class ConstantDivisor<uint32_t>
138 : public internal::ConstantDivisorBase<uint32_t, uint64_t,
139 ConstantDivisor<uint32_t>> {
140 public:
141 using value_type = uint32_t;
142
143 // REQUIRES: denominator > 1
145
146 value_type div(value_type numerator) const {
147 return absl::Uint128High64(absl::uint128(numerator) * magic_);
148 }
149};
150
151// Division and modulus using uint16_t numerators and denominators.
152template <>
153class ConstantDivisor<uint16_t>
154 : public internal::ConstantDivisorBase<uint16_t, uint64_t,
155 ConstantDivisor<uint16_t>> {
156 public:
157 using value_type = uint16_t;
158
160
161 value_type div(value_type numerator) const {
162 return static_cast<uint16_t>(
163 (magic_ * static_cast<MagicValueType>(numerator)) >> kShift);
164 }
165
166 private:
167 // Any value in [32;48] works here.
168 static constexpr MagicValueType kShift = 32;
169};
170
171// Division and modulus using uint8_t numerators and denominators.
172template <>
173class ConstantDivisor<uint8_t>
174 : public internal::ConstantDivisorBase<uint8_t, uint32_t,
175 ConstantDivisor<uint8_t>> {
176 public:
177 using value_type = uint8_t;
178
180
181 value_type div(value_type numerator) const {
182 return static_cast<uint8_t>(
183 (magic_ * static_cast<MagicValueType>(numerator)) >> kShift);
184 }
185
186 private:
187 // Any value in [16;24] works here.
188 static constexpr MagicValueType kShift = 16;
189};
190
191} // namespace math
192} // namespace util
193
194#endif // OR_TOOLS_BASE_CONSTANT_DIVISOR_H_
value_type div(value_type numerator) const
ConstantDivisor(value_type denominator)
REQUIRES: denominator > 1.
value_type div(value_type numerator) const
ConstantDivisor(value_type denominator)
REQUIRES: denominator > 1.
value_type div(value_type numerator) const
value_type div(value_type numerator) const
value_type div(value_type n) const
value_type mod(value_type n) const
ConstantDivisor(value_type denominator)
friend value_type operator%(value_type a, const ConstantDivisor &b)
friend value_type operator/(value_type a, const ConstantDivisor &b)
Common code for all specializations.
ConstantDivisorBase(MagicT magic, value_type denominator)
friend value_type operator%(value_type a, const Impl &b)
friend value_type operator/(value_type a, const Impl &b)
value_type mod(value_type numerator) const
A collections of i/o utilities for the Graph classes in ./graph.h.