MySQL 9.6.0
Source Code Documentation
int_pow.h
Go to the documentation of this file.
1// Copyright (c) 2024, 2025, Oracle and/or its affiliates.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of MySQL hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License, version 2.0, for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
24#ifndef MYSQL_MATH_INT_POW_H
25#define MYSQL_MATH_INT_POW_H
26
27/// @file
28/// Experimental API header
29
30#include <bit> // bit_width
31#include <concepts> // integral
32#include <limits> // numeric_limits
33
34/// @addtogroup GroupLibsMysqlMath
35/// @{
36
37namespace mysql::math {
38
39/// Return pow(base, exponent), where the exponent is an integer.
40///
41/// This does not check for overflow.
42///
43/// Complexity: For constexpr arguments, reduces to a compile-time constant.
44/// Otherwise, logarithmic in the exponent. The number of multiplications is
45/// equal to the 2-logarithm of the exponent, plus the number of 1-bits in the
46/// exponent.
47template <class Value_t>
48[[nodiscard]] constexpr Value_t int_pow(Value_t base, unsigned exponent) {
49 // We use the following equality:
50 //
51 // pow(b, n - k) = pow(b, n) / pow(b, k), or equivalently,
52 // pow(b, n) = pow(b, k) * pow(b, n - k).
53 //
54 // With b = base, n = exponent, k = floor(exponent / 2), we get
55 //
56 // n - k = k, if n is even;
57 // n - k = k + 1, if n is odd.
58 //
59 // Using the equality pow(b, k + 1) = pow(b, k) * b, we obtain:
60 //
61 // pow(b, n) = pow(b, k) * pow(b, n - k)
62 // = pow(b, k) * pow(b, k), if n is even
63 // pow(b, n) = pow(b, k) * pow(b, n - k)
64 // = pow(b, k) * pow(b, k + 1)
65 // = pow(b, k) * pow(b, k) * b, if n is odd
66 if (exponent == 0) return 1;
67 Value_t ret = int_pow(base, exponent >> 1);
68 ret *= ret;
69 if ((exponent & 1) == 1) ret *= base;
70 return ret;
71}
72
73/// Return the floor of the base-`base` logarithm of
74/// numeric_limits<decltype(base>)>::max().
75///
76/// @tparam base base of the logarithm
77///
78/// Complexity: reduces to a compile-time constant.
79template <auto base>
80 requires std::integral<decltype(base)> && (base >= 2)
81[[nodiscard]] constexpr unsigned int_log_max() {
82 // Count how many times we can divide by `base` until the result becomes 0.
83 decltype(base) v = std::numeric_limits<decltype(base)>::max();
84 unsigned ret{0};
85 while (v >= base) {
86 v /= base;
87 ++ret;
88 }
89 return ret;
90}
91
92} // namespace mysql::math
93
95
96/// Return the base-`base` logarithm of value, assuming that
97/// `value < pow(base, 2 * bound)`, where `bound` is a power of two.
98///
99/// @tparam Value_t Data type
100///
101/// @tparam base The base of the logarithm.
102///
103/// @tparam bound Power of two, such that value < pow(base, 2 * bound).
104///
105/// @param value Value to test.
106///
107/// @return the base-`base` logarithm of `value`.
108template <auto base, unsigned bound, std::unsigned_integral Value_t>
109 requires std::same_as<decltype(base), Value_t> && (base >= 2)
110[[nodiscard]] constexpr unsigned int_log_helper(Value_t value) {
111 // Make use of the equality log_b(v/n) = log_b(v) - log_b(n), which holds for
112 // all positive real numbers b, v, n, for the usual real-valued logarithm.
113 //
114 // When n is a power of b and v >= n, the analogous formula holds for the
115 // integer-valued, integer-argument logarithm, i.e.:
116 // int(log_b(int(v/n))) = int(log_b(int(v))) - int(log_b(int(n)))
117 // = int(log_b(v)) - log_b(n)
118 //
119 // This gives us the recursive formula:
120 //
121 // int(log_b(v)) = int(log_b(int(v / n))) + log_b(n), if v >= n
122 // int(log_b(v)) = int(log_b(v)), otherwise
123 //
124 // Using n = pow(base, bound), log_b(n) can be computed at compile time, and
125 // the recursive calls int(log_b(int(v/n))) and int(log_b(v)) both have half
126 // the bound. Thus, only log2(bound) recursive calls are needed.
127 if constexpr (bound == 0) return 0;
128 constexpr Value_t base_to_power = int_pow(base, bound);
129 if (value >= base_to_power) {
130 return int_log_helper<base, bound / 2>(Value_t(value / base_to_power)) +
131 bound;
132 } else {
133 return int_log_helper<base, bound / 2>(value);
134 }
135}
136
137} // namespace mysql::math::detail
138
139namespace mysql::math {
140
141/// Return the base-`base` logarithm of `value`.
142///
143/// @tparam base Base of the logarithm.
144///
145/// @tparam Value_t The integral data type.
146///
147/// @param value Value to compute the logarithm for.
148///
149/// @return int(log_base(value)), or 0 if value == 0.
150///
151/// Complexity: For constexpr arguments, reduces to a constant. Otherwise,
152/// logarithmic in the `base` logarithm of std::numeric_limits<Value_t>::max().
153/// The number of divisions is the floor of log2(int_log_max<Value_t, base>()),
154/// and the denominator is a compile-time constant which is a power of `base`,
155/// so that the compiler may use denominator-specific optimizations such as
156/// shift-right instead of division operations.
157template <auto base, std::unsigned_integral Value_t>
158 requires std::same_as<decltype(base), Value_t> && (base >= 2)
159[[nodiscard]] constexpr unsigned int_log(Value_t value) {
160 // NOLINTNEXTLINE(clang-analyzer-core.BitwiseShift): warning is spurious
161 constexpr unsigned bound = 1U << (std::bit_width(int_log_max<base>()) - 1);
162 return detail::int_log_helper<base, bound>(value);
163}
164
165} // namespace mysql::math
166
167// addtogroup GroupLibsMysqlMath
168/// @}
169
170#endif // ifndef MYSQL_MATH_INT_POW_H
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
ValueType max(X &&first)
Definition: gtid.h:103
Definition: int_pow.h:94
constexpr unsigned int_log_helper(Value_t value)
Return the base-base logarithm of value, assuming that value < pow(base, 2 * bound),...
Definition: int_pow.h:110
Definition: bounded_arithmetic.h:34
constexpr unsigned int_log(Value_t value)
Return the base-base logarithm of value.
Definition: int_pow.h:159
constexpr Value_t int_pow(Value_t base, unsigned exponent)
Return pow(base, exponent), where the exponent is an integer.
Definition: int_pow.h:48
constexpr unsigned int_log_max()
Return the floor of the base-base logarithm of numeric_limits<decltype(base>)>max().
Definition: int_pow.h:81