SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
math.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 <cmath>
16 #include <seqan3/std/concepts>
17 #include <stdexcept>
18 
20 
21 namespace seqan3::detail
22 {
23 
51 template <std::unsigned_integral unsigned_t>
52 constexpr unsigned_t floor_log2(unsigned_t const n) noexcept
53 {
54  assert(n > 0u); // n == 0 is undefined behaviour
55  return most_significant_bit_set(n);
56 }
57 
85 template <std::unsigned_integral unsigned_t>
86 constexpr 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 
94 namespace seqan3
95 {
118 template <typename base_t, std::unsigned_integral exp_t>
120  requires (std::same_as<base_t, uint64_t> || std::same_as<base_t, int64_t>)
122 base_t pow(base_t base, exp_t exp)
123 {
124  base_t result{1};
125 #ifndef NDEBUG
126  if (base == 0)
127  return 0;
128 
129  for (exp_t i = 0; i < exp; ++i)
130  {
131  if ((base < 0 ? std::numeric_limits<base_t>::min() : std::numeric_limits<base_t>::max()) / base < result)
132  {
133  std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp) +
134  " will result in an " + (std::same_as<base_t, int64_t> ? "int64_t" : "uint64_t")};
135  if (base < 0)
136  throw std::underflow_error{error_message + " underflow."};
137  else
138  throw std::overflow_error{error_message + " overflow."};
139  }
140  result *= base;
141  }
142 #else
143  for (; exp; exp >>= 1, base *= base)
144  result *= (exp & 1) ? base : 1;
145 #endif
146  return result;
147 }
148 
150 // If base and exponent are unsigned integrals, promote the base to `uint64_t`.
151 template <std::integral base_t, std::unsigned_integral exp_t>
152  requires (std::unsigned_integral<base_t> && !std::same_as<base_t, uint64_t>)
153 uint64_t pow(base_t base, exp_t exp)
154 {
155  return pow(static_cast<uint64_t>(base), exp);
156 }
157 
158 // If the base is a signed integral and the exponent is an unsigned integral, promote the base to `int64_t`.
159 template <std::integral base_t, std::unsigned_integral exp_t>
160  requires (!std::unsigned_integral<base_t> && !std::same_as<base_t, int64_t>)
161 int64_t pow(base_t base, exp_t exp)
162 {
163  return pow(static_cast<int64_t>(base), exp);
164 }
165 
166 // Otherwise delegate to `std::pow`.
167 template <typename base_t, typename exp_t>
168  requires (!(std::integral<base_t> && std::unsigned_integral<exp_t>))
169 auto pow(base_t base, exp_t exp)
170 {
171  return std::pow(base, exp);
172 }
174 
175 } // namespace seqan3
bit_manipulation.hpp
Provides utility functions for bit twiddling.
std::string
std::underflow_error
std::overflow_error
seqan3::pow
base_t pow(base_t base, exp_t exp)
Computes the value of base raised to the power exp.
Definition: math.hpp:122
cmath
concepts
The Concepts library.
stdexcept
std::to_string
T to_string(T... args)
seqan3
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
std::numeric_limits
std::pow
T pow(T... args)