79 lines
2.0 KiB
C++
79 lines
2.0 KiB
C++
// vi:set ft=cpp: -*- Mode: C++ -*-
|
|
/*
|
|
* Copyright (C) 2025 Kernkonzept GmbH.
|
|
* Author(s): Martin Decky <martin.decky@kernkonzept.com>
|
|
*
|
|
* License: see LICENSE.spdx (in this directory or the directories above)
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <l4/cxx/type_traits>
|
|
|
|
namespace cxx {
|
|
|
|
/**
|
|
* Compute the greatest common divisor of two unsigned values.
|
|
*
|
|
* This uses the Euclidean modulo algorithm.
|
|
*
|
|
* \note Contrary to the C++17 specification, this implementation requires the
|
|
* same unsigned type of both arguments and returns the same type (not
|
|
* a common type). This should be fine for most practical use cases.
|
|
*
|
|
* \note Contrary to the C++17 specification, this implementation does not
|
|
* accept signed arguments and negative literals.
|
|
*
|
|
* \tparam T Unsigned integer type of the values.
|
|
* \param a First input.
|
|
* \param b Second input.
|
|
*
|
|
* \return Greatest common divisor of the input values.
|
|
*/
|
|
template <typename T>
|
|
constexpr T gcd(T a, T b)
|
|
{
|
|
static_assert(Type_traits<T>::is_unsigned, "Type must be unsigned");
|
|
|
|
while (b != 0)
|
|
{
|
|
T remainder = a % b;
|
|
a = b;
|
|
b = remainder;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Compute the least common multiple of two unsigned values.
|
|
*
|
|
* This uses the greatest common divisor to compute the least common
|
|
* multiple.
|
|
*
|
|
* \note Contrary to the C++17 specification, this implementation requires the
|
|
* same unsigned type of both arguments and returns the same type (not
|
|
* a common type). This should be fine for most practical use cases.
|
|
*
|
|
* \note Contrary to the C++17 specification, this implementation does not
|
|
* accept signed arguments and negative literals.
|
|
*
|
|
* \tparam T Unsigned integer type of the values.
|
|
* \param a First input.
|
|
* \param b Second input.
|
|
*
|
|
* \return Least common multiple of the input values.
|
|
*/
|
|
template <typename T>
|
|
constexpr T lcm(T a, T b)
|
|
{
|
|
static_assert(Type_traits<T>::is_unsigned, "Type must be unsigned");
|
|
|
|
if (a == 0 || b == 0)
|
|
return 0;
|
|
|
|
return (a / gcd(a, b)) * b;
|
|
}
|
|
|
|
}
|