//****************************************************************************//
// Copyright (C) 2016 Florent Hivert <Florent.Hivert@lri.fr>, //
// //
// Distributed under the terms of the GNU General Public License (GPL) //
// //
// This code is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
// General Public License for more details. //
// //
// The full text of the GPL is available at: //
// //
// http://www.gnu.org/licenses/ //
//****************************************************************************//
/** @file
* @brief Generic compile time power
*
* The goal of this file is to be able to write expressions such as @c
* pow<23>(2.5) or @c pow<n>(x) where the first expression is entirely
* computed as compile time and the second one is expanded also as compile
* time to a O(log n) long sequence of multiplication. Furthermore such
* expression not only works for numbers for for any type where there is a
* neutral element and an associative (non necessarily commutative) product,
* namely what mathematician calls a \e monoid. This include for example,
* strings where the neutral element is the empty string and the product is
* the concatenation.
*
* see HPCombi::power_helper::Monoid<std::string>
*
* @example stringmonoid.cpp
* This is an example of how to use pow with a non numerical Monoid.
*/
#ifndef HPCOMBI_POWER_HPP_INCLUDED
#define HPCOMBI_POWER_HPP_INCLUDED
namespace HPCombi {
namespace power_helper {
// Forward declaration
template <
typename T>
struct Monoid;
}
// namespace power_helper
/** A generic compile time squaring function
*
* @param x the number to square
* @return @a x squared
*
* @details To use for a specific type the user should pass a monoid
* structure as second parameter to the template. Alternatively a
* default monoid structure can be defined for a given type by specializing
* the template struct #HPCombi::power_helper::Monoid
*/
template <
typename T,
typename M = power_helper::Monoid<T>>
const T square(
const T x) {
return M::prod(x, x);
}
/** A generic compile time exponentiation function
*
* @tparam exp the power
* @param x the number to exponentiate
* @return @a x to the power @a exp
*
* @details Raise x to the exponent exp where exp is known at compile
* time. We use the classical recursive binary algorithm, but the recursion
* is unfolded and optimized at compile time giving an assembly code which is
* just a sequence of multiplication.
*
* To use for a specific type the user should pass a Monoid structure (see
* below) as third parameter to the template. Alternatively a default monoid
* structure can be defined for a given type by specializing the template
* struct #HPCombi::power_helper::Monoid
*/
template <
unsigned exp,
typename T,
typename M = power_helper::Monoid<T>>
const T pow(
const T x) {
return (exp ==
0)
? M::one()
: (exp %
2 ==
0)
? square<T, M>(pow<
unsigned(exp /
2), T, M>(x))
: M::prod(x,
square<T, M>(pow<
unsigned(exp /
2), T, M>(x)));
}
namespace power_helper {
/** Algebraic monoid structure used by default for type T by the pow
* function and prod function
*
* @details A Monoid structure is required to define two static members
* - T #one() : the unit of the monoid
* - T #prod(T, T) : the product of two elements in the monoid
*
* By default for any type \c T, #one is constructed from the litteral 1 and
* #prod calls the operator *. One can change these default by specializing
* the template for some specific type \c T.
*/
template <
typename T>
struct Monoid {
/// The one of type T
static const T one() {
return 1; }
/** the product of two elements of type T
* @param a the first element to be multiplied
* @param b the second element to be multiplied
* @return the product a * b
*/
static const T prod(T a, T b) {
return a * b; }
};
}
// namespace power_helper
}
// namespace HPCombi
#endif // HPCOMBI_POWER_HPP_INCLUDED
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland