forked from mpusz/mp-units
Fix magnitude constraints
I got my requires expressions/clauses mixed up. Unfortunately, this means we can't just shove all the "implementation details" down to the bottom of the file. Oh well.
This commit is contained in:
@@ -134,69 +134,8 @@ constexpr auto inverse(BP bp) {
|
|||||||
return bp;
|
return bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation helpers for `magnitude<...>` constraints (below).
|
// A variety of implementation detail helpers.
|
||||||
namespace detail {
|
namespace detail {
|
||||||
constexpr bool is_valid_base_power(const BasePower auto &bp);
|
|
||||||
|
|
||||||
template<typename... Ts>
|
|
||||||
constexpr bool strictly_increasing(Ts&&... ts);
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A representation for positive real numbers which optimizes taking products and rational powers.
|
|
||||||
*
|
|
||||||
* Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, and compare
|
|
||||||
* for equality.
|
|
||||||
*/
|
|
||||||
template<BasePower auto... BPs>
|
|
||||||
requires requires {
|
|
||||||
(detail::is_valid_base_power(BPs) && ... && detail::strictly_increasing(BPs.get_base()...));
|
|
||||||
}
|
|
||||||
struct magnitude {};
|
|
||||||
|
|
||||||
// Implementation for Magnitude concept (below).
|
|
||||||
namespace detail {
|
|
||||||
template<typename T>
|
|
||||||
struct is_magnitude : std::false_type {};
|
|
||||||
template<BasePower auto... BPs>
|
|
||||||
struct is_magnitude<magnitude<BPs...>> : std::true_type {};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Concept to detect whether T is a valid Magnitude.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
concept Magnitude = detail::is_magnitude<T>::value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convert any positive integer to a Magnitude.
|
|
||||||
*
|
|
||||||
* This will be the main way end users create Magnitudes. They should rarely (if ever) create a magnitude<...> by
|
|
||||||
* manually adding base powers.
|
|
||||||
*/
|
|
||||||
template<ratio R>
|
|
||||||
requires requires { R.num > 0; }
|
|
||||||
constexpr Magnitude auto as_magnitude();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A base to represent pi.
|
|
||||||
*/
|
|
||||||
struct pi_base {
|
|
||||||
static constexpr long double value = std::numbers::pi_v<long double>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A simple way to create a Magnitude representing a rational power of pi.
|
|
||||||
*/
|
|
||||||
template<ratio Power>
|
|
||||||
constexpr auto pi_to_the() { return magnitude<base_power<pi_base>{Power}>{}; }
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Implementation details below.
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
// Find the smallest prime factor of `n`.
|
// Find the smallest prime factor of `n`.
|
||||||
constexpr std::intmax_t find_first_factor(std::intmax_t n)
|
constexpr std::intmax_t find_first_factor(std::intmax_t n)
|
||||||
@@ -232,22 +171,11 @@ constexpr std::intmax_t remove_power(std::intmax_t base, std::intmax_t pow, std:
|
|||||||
// Helpers to perform prime factorization at compile time.
|
// Helpers to perform prime factorization at compile time.
|
||||||
template<std::intmax_t N>
|
template<std::intmax_t N>
|
||||||
requires requires { N > 0; }
|
requires requires { N > 0; }
|
||||||
struct prime_factorization {
|
struct prime_factorization;
|
||||||
static constexpr int first_base = find_first_factor(N);
|
|
||||||
static constexpr std::intmax_t first_power = multiplicity(first_base, N);
|
|
||||||
static constexpr std::intmax_t remainder = remove_power(first_base, first_power, N);
|
|
||||||
|
|
||||||
static constexpr auto value = magnitude<base_power{first_base, first_power}>{}
|
|
||||||
* prime_factorization<remainder>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<std::intmax_t N>
|
template<std::intmax_t N>
|
||||||
static constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
static constexpr auto prime_factorization_v = prime_factorization<N>::value;
|
||||||
|
|
||||||
// Specialization for the prime factorization of 1 (base case).
|
|
||||||
template<>
|
|
||||||
struct prime_factorization<1> { static constexpr magnitude<> value{}; };
|
|
||||||
|
|
||||||
// A way to check whether a number is prime at compile time.
|
// A way to check whether a number is prime at compile time.
|
||||||
constexpr bool is_prime(std::intmax_t n) { return (n > 1) && (find_first_factor(n) == n); }
|
constexpr bool is_prime(std::intmax_t n) { return (n > 1) && (find_first_factor(n) == n); }
|
||||||
|
|
||||||
@@ -289,6 +217,53 @@ constexpr bool strictly_increasing(Ts&&... ts) {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A representation for positive real numbers which optimizes taking products and rational powers.
|
||||||
|
*
|
||||||
|
* Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, and compare
|
||||||
|
* for equality.
|
||||||
|
*/
|
||||||
|
template<BasePower auto... BPs>
|
||||||
|
requires ((detail::is_valid_base_power(BPs) && ... && detail::strictly_increasing(BPs.get_base()...)))
|
||||||
|
struct magnitude {};
|
||||||
|
|
||||||
|
// Implementation for Magnitude concept (below).
|
||||||
|
namespace detail {
|
||||||
|
template<typename T>
|
||||||
|
struct is_magnitude : std::false_type {};
|
||||||
|
template<BasePower auto... BPs>
|
||||||
|
struct is_magnitude<magnitude<BPs...>> : std::true_type {};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Concept to detect whether T is a valid Magnitude.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Magnitude = detail::is_magnitude<T>::value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert any positive integer to a Magnitude.
|
||||||
|
*
|
||||||
|
* This will be the main way end users create Magnitudes. They should rarely (if ever) create a magnitude<...> by
|
||||||
|
* manually adding base powers.
|
||||||
|
*/
|
||||||
|
template<ratio R>
|
||||||
|
requires requires { R.num > 0; }
|
||||||
|
constexpr Magnitude auto as_magnitude();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A base to represent pi.
|
||||||
|
*/
|
||||||
|
struct pi_base {
|
||||||
|
static constexpr long double value = std::numbers::pi_v<long double>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A simple way to create a Magnitude representing a rational power of pi.
|
||||||
|
*/
|
||||||
|
template<ratio Power>
|
||||||
|
constexpr auto pi_to_the() { return magnitude<base_power<pi_base>{Power}>{}; }
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Magnitude equality implementation.
|
// Magnitude equality implementation.
|
||||||
|
|
||||||
@@ -358,4 +333,23 @@ constexpr Magnitude auto as_magnitude() {
|
|||||||
return detail::prime_factorization_v<R.num> / detail::prime_factorization_v<R.den>;
|
return detail::prime_factorization_v<R.num> / detail::prime_factorization_v<R.den>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// Default implementation.
|
||||||
|
template<std::intmax_t N>
|
||||||
|
requires requires { N > 0; }
|
||||||
|
struct prime_factorization {
|
||||||
|
static constexpr int first_base = find_first_factor(N);
|
||||||
|
static constexpr std::intmax_t first_power = multiplicity(first_base, N);
|
||||||
|
static constexpr std::intmax_t remainder = remove_power(first_base, first_power, N);
|
||||||
|
|
||||||
|
static constexpr auto value = magnitude<base_power{first_base, first_power}>{}
|
||||||
|
* prime_factorization<remainder>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for the prime factorization of 1 (base case).
|
||||||
|
template<>
|
||||||
|
struct prime_factorization<1> { static constexpr magnitude<> value{}; };
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace units::mag
|
} // namespace units::mag
|
||||||
|
Reference in New Issue
Block a user