SeqAn3 3.4.0-rc.3
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
math.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 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
19
20namespace seqan3::detail
21{
22
50template <std::unsigned_integral unsigned_t>
51constexpr unsigned_t floor_log2(unsigned_t const n) noexcept
52{
53 assert(n > 0u); // n == 0 is undefined behaviour
54 return std::bit_width(n) - 1;
55}
56
84template <std::unsigned_integral unsigned_t>
85constexpr unsigned_t ceil_log2(unsigned_t const n) noexcept
86{
87 assert(n > 0u); // n == 0 is undefined behaviour
88 return (n == 1u) ? 0u : seqan3::detail::floor_log2(n - 1u) + 1u;
89}
90
91} // namespace seqan3::detail
92
93namespace seqan3
94{
117template <typename base_t, std::unsigned_integral exp_t>
118 requires (std::same_as<base_t, uint64_t> || std::same_as<base_t, int64_t>)
119base_t pow(base_t base, exp_t exp)
120{
121 base_t result{1};
122#ifndef NDEBUG
123 if (base == 0)
124 return 0;
125
126 auto check = [base](base_t result)
127 {
128 if (base > 0)
129 {
131 }
132 else if (result < 0) // and base < 0
133 {
135 }
136 else // base < 0 and result > 0
137 {
139 }
140 };
141
142 for (exp_t i = 0; i < exp; ++i)
143 {
144 if (check(result))
145 {
146 std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp)
147 + " will result in an "
148 + (std::same_as<base_t, int64_t> ? "int64_t" : "uint64_t")};
149 if (base < 0)
150 throw std::underflow_error{error_message + " underflow."};
151 else
152 throw std::overflow_error{error_message + " overflow."};
153 }
154 result *= base;
155 }
156#else
157 for (; exp; exp >>= 1, base *= base)
158 result *= (exp & 1) ? base : 1;
159#endif
160 return result;
161}
162
164// If base and exponent are unsigned integrals, promote the base to `uint64_t`.
165template <std::integral base_t, std::unsigned_integral exp_t>
166 requires (std::unsigned_integral<base_t> && !std::same_as<base_t, uint64_t>)
167uint64_t pow(base_t base, exp_t exp)
168{
169 return pow(static_cast<uint64_t>(base), exp);
170}
171
172// If the base is a signed integral and the exponent is an unsigned integral, promote the base to `int64_t`.
173template <std::integral base_t, std::unsigned_integral exp_t>
174 requires (!std::unsigned_integral<base_t> && !std::same_as<base_t, int64_t>)
175int64_t pow(base_t base, exp_t exp)
176{
177 return pow(static_cast<int64_t>(base), exp);
178}
179
180// Otherwise delegate to `std::pow`.
181template <typename base_t, typename exp_t>
182 requires (!(std::integral<base_t> && std::unsigned_integral<exp_t>))
183auto pow(base_t base, exp_t exp)
184{
185 return std::pow(base, exp);
186}
188
189} // namespace seqan3
T bit_width(T... args)
A "pretty printer" for most SeqAn data structures and related types.
Definition debug_stream_type.hpp:79
base_t pow(base_t base, exp_t exp)
Computes the value of base raised to the power exp.
Definition math.hpp:119
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