diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e2cf0a..3338348 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ set(HEADER_FILES io/path.h io/nativefilestream.h io/misc.h - math/math.h + misc/math.h misc/memory.h misc/multiarray.h misc/traits.h @@ -52,7 +52,7 @@ set(SRC_FILES io/path.cpp io/nativefilestream.cpp io/misc.cpp - math/math.cpp + misc/math.cpp misc/levenshtein.cpp tests/testutils.cpp) diff --git a/math/math.cpp b/math/math.cpp deleted file mode 100644 index 27b209a..0000000 --- a/math/math.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "./math.h" - -#include -#include - -/*! - * \namespace MathUtilities - * \brief Contains various mathematical functions. - * \todo Move math.h and math.cpp to misc in v5. - */ - -namespace MathUtilities { - -/*! - * \brief Returns the digitsum of the given \a number using the specified \a base. - * \todo Make constexpr/template in v5. - */ -int digitsum(int number, int base) -{ - int res = 0; - while (number > 0) { - res += number % base; - number /= base; - } - return res; -} - -/*! - * \brief Returns the factorial of the given \a number. - * \todo Make constexpr/template in v5. - */ -int factorial(int number) -{ - int res = 1; - for (int i = 1; i <= number; ++i) { - res *= i; - } - return res; -} - -/*! - * \brief Computes \a base power \a exponent modulo \a module. - * \todo Make constexpr/template in v5. - */ -std::uint64_t powerModulo(const std::uint64_t base, const std::uint64_t exponent, const std::uint64_t module) -{ - std::uint64_t res = 1; - for (std::uint64_t mask = 0x8000000000000000; mask; mask >>= 1) { - if (mask & exponent) { - res *= base; - } - if (mask != 1) { - res *= res; - } - res %= module; - } - return res; -} - -/*! - * \brief Computes the inverse of \a number modulo \a module. - * \todo Make constexpr/template in v5. - */ -std::int64_t inverseModulo(std::int64_t number, std::int64_t module) -{ - std::int64_t y1 = 0, y2 = 1, tmp; - while (number != 1) { - tmp = y1 - (module / number) * y2; - y1 = y2; - y2 = tmp; - tmp = module % number; - module = number; - number = tmp; - } - return y2; -} - -/*! - * \brief Computes the order of \a number modulo \a module. - * \todo Make constexpr/template in v5. - */ -std::uint64_t orderModulo(const std::uint64_t number, const std::uint64_t module) -{ - std::uint64_t order = 1; - for (; powerModulo(number, order, module) != 1 && order != module; ++order) - ; - return order != module ? order : 0; -} -} // namespace MathUtilities diff --git a/math/math.h b/math/math.h deleted file mode 100644 index 4436eb1..0000000 --- a/math/math.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef MATHUTILITIES_H -#define MATHUTILITIES_H - -#include "../global.h" - -#include - -namespace MathUtilities { - -CPP_UTILITIES_EXPORT int digitsum(int number, int base = 10); -CPP_UTILITIES_EXPORT int factorial(int number); -CPP_UTILITIES_EXPORT std::uint64_t powerModulo(std::uint64_t base, std::uint64_t expontent, std::uint64_t module); -CPP_UTILITIES_EXPORT std::int64_t inverseModulo(std::int64_t number, std::int64_t module); -CPP_UTILITIES_EXPORT std::uint64_t orderModulo(std::uint64_t number, std::uint64_t module); - -/// \brief Returns the smallest of the given items. -template constexpr T min(T first, T second) -{ - return first < second ? first : second; -} - -/// \brief Returns the smallest of the given items. -template constexpr T1 min(T1 first, T1 second, T2... remaining) -{ - return first < second ? min(first, remaining...) : min(second, remaining...); -} - -/// \brief Returns the greatest of the given items. -template constexpr T max(T first, T second) -{ - return first > second ? first : second; -} - -/// \brief Returns the greatest of the given items. -template constexpr T1 max(T1 first, T1 second, T2... remaining) -{ - return first > second ? max(first, remaining...) : max(second, remaining...); -} - -} // namespace MathUtilities - -#endif // MATHUTILITIES_H diff --git a/misc/levenshtein.cpp b/misc/levenshtein.cpp index 3dfa385..84f3cba 100644 --- a/misc/levenshtein.cpp +++ b/misc/levenshtein.cpp @@ -1,7 +1,7 @@ #include "./levenshtein.h" -#include "./multiarray.h" -#include "../math/math.h" +#include "./math.h" +#include "./multiarray.h" #include #include diff --git a/misc/math.cpp b/misc/math.cpp new file mode 100644 index 0000000..df7e1f6 --- /dev/null +++ b/misc/math.cpp @@ -0,0 +1,13 @@ +#include "./math.h" + +#include +#include + +/*! + * \namespace MathUtilities + * \brief Contains various mathematical functions. + */ + +namespace MathUtilities { + +} // namespace MathUtilities diff --git a/misc/math.h b/misc/math.h new file mode 100644 index 0000000..0129a64 --- /dev/null +++ b/misc/math.h @@ -0,0 +1,113 @@ +#ifndef MATHUTILITIES_H +#define MATHUTILITIES_H + +#include "../global.h" +#include "./traits.h" + +#include +#include + +namespace MathUtilities { + +/*! + * \brief Returns the digitsum of the given \a number using the specified \a base. + */ +template > * = nullptr> +constexpr IntegralType digitsum(IntegralType number, IntegralType base = 10) +{ + IntegralType res = 0; + while (number > 0) { + res += number % base; + number /= base; + } + return res; +} + +/*! + * \brief Returns the factorial of the given \a number. + */ +template > * = nullptr> constexpr IntegralType factorial(IntegralType number) +{ + IntegralType res = 1; + for (IntegralType i = 1; i <= number; ++i) { + res *= i; + } + return res; +} + +/*! + * \brief Computes \a base power \a exponent modulo \a module. + */ +template , std::is_unsigned> * = nullptr> +constexpr IntegralType powerModulo(const IntegralType base, const IntegralType exponent, const IntegralType module) +{ + IntegralType res = 1; + for (IntegralType mask = static_cast(1) << static_cast(sizeof(IntegralType) * 8 - 1); mask; mask >>= 1) { + if (mask & exponent) { + res *= base; + } + if (mask != 1) { + res *= res; + } + res %= module; + } + return res; +} + +/*! + * \brief Computes the inverse of \a number modulo \a module. + */ +template , std::is_unsigned> * = nullptr> +constexpr IntegralType inverseModulo(IntegralType number, IntegralType module) +{ + IntegralType y1 = 0, y2 = 1, tmp; + while (number != 1) { + tmp = y1 - (module / number) * y2; + y1 = y2; + y2 = tmp; + tmp = module % number; + module = number; + number = tmp; + } + return y2; +} + +/*! + * \brief Computes the order of \a number modulo \a module. + */ +template , std::is_unsigned> * = nullptr> +constexpr IntegralType orderModulo(const IntegralType number, const IntegralType module) +{ + IntegralType order = 1; + for (; powerModulo(number, order, module) != 1 && order != module; ++order) + ; + return order != module ? order : 0; +} + +/// \brief Returns the smallest of the given items. +template constexpr T min(T first, T second) +{ + return first < second ? first : second; +} + +/// \brief Returns the smallest of the given items. +template constexpr T1 min(T1 first, T1 second, T2... remaining) +{ + return first < second ? min(first, remaining...) : min(second, remaining...); +} + +/// \brief Returns the greatest of the given items. +template constexpr T max(T first, T second) +{ + return first > second ? first : second; +} + +/// \brief Returns the greatest of the given items. +template constexpr T1 max(T1 first, T1 second, T2... remaining) +{ + return first > second ? max(first, remaining...) : max(second, remaining...); +} + +} // namespace MathUtilities + +#endif // MATHUTILITIES_H diff --git a/tests/mathtests.cpp b/tests/mathtests.cpp index 9b4b4d6..87aaa7a 100644 --- a/tests/mathtests.cpp +++ b/tests/mathtests.cpp @@ -1,4 +1,4 @@ -#include "../math/math.h" +#include "../misc/math.h" #include "../tests/testutils.h" #include @@ -66,19 +66,19 @@ void MathTests::testFactorial() void MathTests::testPowerModulo() { - CPPUNIT_ASSERT_EQUAL(25_uint64, powerModulo(5, 2, 30)); - CPPUNIT_ASSERT_EQUAL(5_uint64, powerModulo(5, 2, 20)); + CPPUNIT_ASSERT_EQUAL(25u, powerModulo(5u, 2u, 30u)); + CPPUNIT_ASSERT_EQUAL(5u, powerModulo(5u, 2u, 20u)); } void MathTests::testInverseModulo() { - CPPUNIT_ASSERT_EQUAL(-12_int64, inverseModulo(2, 25)); - CPPUNIT_ASSERT_EQUAL(-8_int64, inverseModulo(3, 25)); + CPPUNIT_ASSERT_EQUAL(-12u, inverseModulo(2u, 25u)); + CPPUNIT_ASSERT_EQUAL(-8u, inverseModulo(3u, 25u)); } void MathTests::testOrderModulo() { - CPPUNIT_ASSERT_EQUAL(20_uint64, orderModulo(2, 25)); - CPPUNIT_ASSERT_EQUAL(5_uint64, orderModulo(6, 25)); - CPPUNIT_ASSERT_EQUAL(0_uint64, orderModulo(5, 25)); + CPPUNIT_ASSERT_EQUAL(20u, orderModulo(2u, 25u)); + CPPUNIT_ASSERT_EQUAL(5u, orderModulo(6u, 25u)); + CPPUNIT_ASSERT_EQUAL(0u, orderModulo(5u, 25u)); }