SeqAn3 3.4.1-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
math.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <bit>
13#include <cassert>
14#include <cmath>
15#include <concepts>
16#include <stdexcept>
17#include <string>
18
20
21namespace seqan3::detail
22{
23
51template <std::unsigned_integral unsigned_t>
52constexpr unsigned_t floor_log2(unsigned_t const n) noexcept
53{
54 assert(n > 0u); // n == 0 is undefined behaviour
55 return std::bit_width(n) - 1;
56}
57
85template <std::unsigned_integral unsigned_t>
86constexpr unsigned_t ceil_log2(unsigned_t const n) noexcept
87{
88 assert(n > 0u); // n == 0 is undefined behaviour
89 return (n == 1u) ? 0u : seqan3::detail::floor_log2(n - 1u) + 1u;
90}
91
92} // namespace seqan3::detail
93
94namespace seqan3
95{
118template <typename base_t, std::unsigned_integral exp_t>
119 requires (std::same_as<base_t, uint64_t> || std::same_as<base_t, int64_t>)
120base_t pow(base_t base, exp_t exp)
121{
122 base_t result{1};
123#ifndef NDEBUG
124 if (base == 0)
125 return 0;
126
127 auto check = [base](base_t result)
128 {
129 if (base > 0)
130 {
131 return result > std::numeric_limits<base_t>::max() / base;
132 }
133 else if (result < 0) // and base < 0
134 {
135 return result < std::numeric_limits<base_t>::max() / base;
136 }
137 else // base < 0 and result > 0
138 {
139 return base < std::numeric_limits<base_t>::min() / result;
140 }
141 };
142
143 for (exp_t i = 0; i < exp; ++i)
144 {
145 if (check(result))
146 {
147 std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp)
148 + " will result in an "
149 + (std::same_as<base_t, int64_t> ? "int64_t" : "uint64_t")};
150 if (base < 0)
151 throw std::underflow_error{error_message + " underflow."};
152 else
153 throw std::overflow_error{error_message + " overflow."};
154 }
155 result *= base;
156 }
157#else
158 for (; exp; exp >>= 1, base *= base)
159 result *= (exp & 1) ? base : 1;
160#endif
161 return result;
162}
163
165// If base and exponent are unsigned integrals, promote the base to `uint64_t`.
166template <std::integral base_t, std::unsigned_integral exp_t>
167 requires (std::unsigned_integral<base_t> && !std::same_as<base_t, uint64_t>)
168uint64_t pow(base_t base, exp_t exp)
169{
170 return pow(static_cast<uint64_t>(base), exp);
171}
172
173// If the base is a signed integral and the exponent is an unsigned integral, promote the base to `int64_t`.
174template <std::integral base_t, std::unsigned_integral exp_t>
175 requires (!std::unsigned_integral<base_t> && !std::same_as<base_t, int64_t>)
176int64_t pow(base_t base, exp_t exp)
177{
178 return pow(static_cast<int64_t>(base), exp);
179}
180
181// Otherwise delegate to `std::pow`.
182template <typename base_t, typename exp_t>
183 requires (!(std::integral<base_t> && std::unsigned_integral<exp_t>))
184auto pow(base_t base, exp_t exp)
185{
186 return std::pow(base, exp);
187}
189
190} // namespace seqan3
T bit_width(T... args)
base_t pow(base_t base, exp_t exp)
Computes the value of base raised to the power exp.
Definition math.hpp:120
T max(T... args)
The main SeqAn3 namespace.
Definition aligned_sequence_concept.hpp:26
Provides platform and dependency checks.
T pow(T... args)
T to_string(T... args)
Hide me