SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
math.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
4// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6// -----------------------------------------------------------------------------------------------------
7
13#pragma once
14
15#include <seqan3/std/bit>
16#include <cassert>
17#include <cmath>
18#include <seqan3/std/concepts>
19#include <stdexcept>
20
22
23namespace seqan3::detail
24{
25
53template <std::unsigned_integral unsigned_t>
54constexpr unsigned_t floor_log2(unsigned_t const n) noexcept
55{
56 assert(n > 0u); // n == 0 is undefined behaviour
57 return std::bit_width(n) - 1;
58}
59
87template <std::unsigned_integral unsigned_t>
88constexpr unsigned_t ceil_log2(unsigned_t const n) noexcept
89{
90 assert(n > 0u); // n == 0 is undefined behaviour
91 return (n == 1u) ? 0u : seqan3::detail::floor_log2(n - 1u) + 1u;
92}
93
94} // namespace seqan3::detail
95
96namespace seqan3
97{
120template <typename base_t, std::unsigned_integral exp_t>
122 requires (std::same_as<base_t, uint64_t> || std::same_as<base_t, int64_t>)
124base_t pow(base_t base, exp_t exp)
125{
126 base_t result{1};
127#ifndef NDEBUG
128 if (base == 0)
129 return 0;
130
131 for (exp_t i = 0; i < exp; ++i)
132 {
133 if ((base < 0 ? std::numeric_limits<base_t>::min() : std::numeric_limits<base_t>::max()) / base < result)
134 {
135 std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp) +
136 " will result in an " + (std::same_as<base_t, int64_t> ? "int64_t" : "uint64_t")};
137 if (base < 0)
138 throw std::underflow_error{error_message + " underflow."};
139 else
140 throw std::overflow_error{error_message + " overflow."};
141 }
142 result *= base;
143 }
144#else
145 for (; exp; exp >>= 1, base *= base)
146 result *= (exp & 1) ? base : 1;
147#endif
148 return result;
149}
150
152// If base and exponent are unsigned integrals, promote the base to `uint64_t`.
153template <std::integral base_t, std::unsigned_integral exp_t>
154 requires (std::unsigned_integral<base_t> && !std::same_as<base_t, uint64_t>)
155uint64_t pow(base_t base, exp_t exp)
156{
157 return pow(static_cast<uint64_t>(base), exp);
158}
159
160// If the base is a signed integral and the exponent is an unsigned integral, promote the base to `int64_t`.
161template <std::integral base_t, std::unsigned_integral exp_t>
162 requires (!std::unsigned_integral<base_t> && !std::same_as<base_t, int64_t>)
163int64_t pow(base_t base, exp_t exp)
164{
165 return pow(static_cast<int64_t>(base), exp);
166}
167
168// Otherwise delegate to `std::pow`.
169template <typename base_t, typename exp_t>
170 requires (!(std::integral<base_t> && std::unsigned_integral<exp_t>))
171auto pow(base_t base, exp_t exp)
172{
173 return std::pow(base, exp);
174}
176
177} // namespace seqan3
The <bit> header from C++20's standard library.
The <concepts> header from C++20's standard library.
constexpr T bit_width(T x) noexcept
If x is not zero, calculates the number of bits needed to store the value x, that is,...
Definition: bit:183
base_t pow(base_t base, exp_t exp)
Computes the value of base raised to the power exp.
Definition: math.hpp:124
The main SeqAn3 namespace.
Definition: cigar_operation_table.hpp:2
Provides platform and dependency checks.
T pow(T... args)
T to_string(T... args)