SeqAn3 3.4.0-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-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 for (exp_t i = 0; i < exp; ++i)
127 {
128 if ((base < 0 ? std::numeric_limits<base_t>::min() : std::numeric_limits<base_t>::max()) / base < result)
129 {
130 std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp)
131 + " will result in an "
132 + (std::same_as<base_t, int64_t> ? "int64_t" : "uint64_t")};
133 if (base < 0)
134 throw std::underflow_error{error_message + " underflow."};
135 else
136 throw std::overflow_error{error_message + " overflow."};
137 }
138 result *= base;
139 }
140#else
141 for (; exp; exp >>= 1, base *= base)
142 result *= (exp & 1) ? base : 1;
143#endif
144 return result;
145}
146
148// If base and exponent are unsigned integrals, promote the base to `uint64_t`.
149template <std::integral base_t, std::unsigned_integral exp_t>
150 requires (std::unsigned_integral<base_t> && !std::same_as<base_t, uint64_t>)
151uint64_t pow(base_t base, exp_t exp)
152{
153 return pow(static_cast<uint64_t>(base), exp);
154}
155
156// If the base is a signed integral and the exponent is an unsigned integral, promote the base to `int64_t`.
157template <std::integral base_t, std::unsigned_integral exp_t>
158 requires (!std::unsigned_integral<base_t> && !std::same_as<base_t, int64_t>)
159int64_t pow(base_t base, exp_t exp)
160{
161 return pow(static_cast<int64_t>(base), exp);
162}
163
164// Otherwise delegate to `std::pow`.
165template <typename base_t, typename exp_t>
166 requires (!(std::integral<base_t> && std::unsigned_integral<exp_t>))
167auto pow(base_t base, exp_t exp)
168{
169 return std::pow(base, exp);
170}
172
173} // 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: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