mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 02:17:16 +02:00
NTTP ratio support added (resolves #49)
This commit is contained in:
@ -8,6 +8,7 @@
|
||||
- `math.h` function signatures refactored to use a `Quantity` concept (thanks [@kwikius](https://github.com/kwikius))
|
||||
- FPS system added (thanks [@mikeford3](https://github.com/mikeford3))
|
||||
- `quantity_point` support added (thanks [@johelegp](https://github.com/johelegp))
|
||||
- `ratio` changed to the NTTP kind
|
||||
|
||||
- **0.5.0 May 17, 2020**
|
||||
- Major refactoring and rewrite of the library
|
||||
|
@ -186,20 +186,23 @@ Those units are the scaled versions of a time dimension's base unit,
|
||||
namely second. Those can be defined easily in the library using
|
||||
`named_scaled_unit` class template::
|
||||
|
||||
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<60>, minute> {};
|
||||
struct day : named_scaled_unit<hour, "d", no_prefix, ratio<24>, hour> {};
|
||||
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio(60), second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(60), minute> {};
|
||||
struct day : named_scaled_unit<hour, "d", no_prefix, ratio(24), hour> {};
|
||||
|
||||
where `no_prefix` is a special tag type describing that the library should
|
||||
not allow to define a new prefixed unit that would use this unit as a
|
||||
reference ("kilohours" does not have much sense, right?). The `ratio` type
|
||||
used in the definition is really similar to ``std::ratio`` but it takes
|
||||
the third additional argument that defines the exponent of the ratio.
|
||||
an additional ``Exp`` template parameter that defines the exponent of the ratio.
|
||||
Another important difference is the fact that the objects of that class are used
|
||||
as class NTTPs rather then a type template parameter kind.
|
||||
|
||||
Thanks to it we can address nearly infinite scaling factors between units
|
||||
and define units like::
|
||||
|
||||
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix,
|
||||
ratio<1'602'176'634, 1'000'000'000, -19>, joule> {};
|
||||
ratio(1'602'176'634, 1'000'000'000, -19), joule> {};
|
||||
|
||||
..
|
||||
TODO Submit a bug for above lexing problem
|
||||
@ -221,26 +224,26 @@ complete list of all the :term:`SI` prefixes supported by the library::
|
||||
|
||||
struct prefix : prefix_family {};
|
||||
|
||||
struct yocto : units::prefix<yocto, prefix, "y", ratio<1, 1, -24>> {};
|
||||
struct zepto : units::prefix<zepto, prefix, "z", ratio<1, 1, -21>> {};
|
||||
struct atto : units::prefix<atto, prefix, "a", ratio<1, 1, -18>> {};
|
||||
struct femto : units::prefix<femto, prefix, "f", ratio<1, 1, -15>> {};
|
||||
struct pico : units::prefix<pico, prefix, "p", ratio<1, 1, -12>> {};
|
||||
struct nano : units::prefix<nano, prefix, "n", ratio<1, 1, -9>> {};
|
||||
struct micro : units::prefix<micro, prefix, "µ", ratio<1, 1, -6>> {};
|
||||
struct milli : units::prefix<milli, prefix, "m", ratio<1, 1, -3>> {};
|
||||
struct centi : units::prefix<centi, prefix, "c", ratio<1, 1, -2>> {};
|
||||
struct deci : units::prefix<deci, prefix, "d", ratio<1, 1, -1>> {};
|
||||
struct deca : units::prefix<deca, prefix, "da", ratio<1, 1, 1>> {};
|
||||
struct hecto : units::prefix<hecto, prefix, "h", ratio<1, 1, 2>> {};
|
||||
struct kilo : units::prefix<kilo, prefix, "k", ratio<1, 1, 3>> {};
|
||||
struct mega : units::prefix<mega, prefix, "M", ratio<1, 1, 6>> {};
|
||||
struct giga : units::prefix<giga, prefix, "G", ratio<1, 1, 9>> {};
|
||||
struct tera : units::prefix<tera, prefix, "T", ratio<1, 1, 12>> {};
|
||||
struct peta : units::prefix<peta, prefix, "P", ratio<1, 1, 15>> {};
|
||||
struct exa : units::prefix<exa, prefix, "E", ratio<1, 1, 18>> {};
|
||||
struct zetta : units::prefix<zetta, prefix, "Z", ratio<1, 1, 21>> {};
|
||||
struct yotta : units::prefix<yotta, prefix, "Y", ratio<1, 1, 24>> {};
|
||||
struct yocto : units::prefix<yocto, prefix, "y", ratio(1, 1, -24)> {};
|
||||
struct zepto : units::prefix<zepto, prefix, "z", ratio(1, 1, -21)> {};
|
||||
struct atto : units::prefix<atto, prefix, "a", ratio(1, 1, -18)> {};
|
||||
struct femto : units::prefix<femto, prefix, "f", ratio(1, 1, -15)> {};
|
||||
struct pico : units::prefix<pico, prefix, "p", ratio(1, 1, -12)> {};
|
||||
struct nano : units::prefix<nano, prefix, "n", ratio(1, 1, -9)> {};
|
||||
struct micro : units::prefix<micro, prefix, "µ", ratio(1, 1, -6)> {};
|
||||
struct milli : units::prefix<milli, prefix, "m", ratio(1, 1, -3)> {};
|
||||
struct centi : units::prefix<centi, prefix, "c", ratio(1, 1, -2)> {};
|
||||
struct deci : units::prefix<deci, prefix, "d", ratio(1, 1, -1)> {};
|
||||
struct deca : units::prefix<deca, prefix, "da", ratio(1, 1, 1)> {};
|
||||
struct hecto : units::prefix<hecto, prefix, "h", ratio(1, 1, 2)> {};
|
||||
struct kilo : units::prefix<kilo, prefix, "k", ratio(1, 1, 3)> {};
|
||||
struct mega : units::prefix<mega, prefix, "M", ratio(1, 1, 6)> {};
|
||||
struct giga : units::prefix<giga, prefix, "G", ratio(1, 1, 9)> {};
|
||||
struct tera : units::prefix<tera, prefix, "T", ratio(1, 1, 12)> {};
|
||||
struct peta : units::prefix<peta, prefix, "P", ratio(1, 1, 15)> {};
|
||||
struct exa : units::prefix<exa, prefix, "E", ratio(1, 1, 18)> {};
|
||||
struct zetta : units::prefix<zetta, prefix, "Z", ratio(1, 1, 21)> {};
|
||||
struct yotta : units::prefix<yotta, prefix, "Y", ratio(1, 1, 24)> {};
|
||||
|
||||
}
|
||||
|
||||
@ -251,12 +254,12 @@ domain::
|
||||
|
||||
struct prefix : prefix_family {};
|
||||
|
||||
struct kibi : units::prefix<kibi, prefix, "Ki", ratio< 1'024>> {};
|
||||
struct mebi : units::prefix<mebi, prefix, "Mi", ratio< 1'048'576>> {};
|
||||
struct gibi : units::prefix<gibi, prefix, "Gi", ratio< 1'073'741'824>> {};
|
||||
struct tebi : units::prefix<tebi, prefix, "Ti", ratio< 1'099'511'627'776>> {};
|
||||
struct pebi : units::prefix<pebi, prefix, "Pi", ratio< 1'125'899'906'842'624>> {};
|
||||
struct exbi : units::prefix<exbi, prefix, "Ei", ratio<1'152'921'504'606'846'976>> {};
|
||||
struct kibi : units::prefix<kibi, prefix, "Ki", ratio( 1'024)> {};
|
||||
struct mebi : units::prefix<mebi, prefix, "Mi", ratio( 1'048'576)> {};
|
||||
struct gibi : units::prefix<gibi, prefix, "Gi", ratio( 1'073'741'824)> {};
|
||||
struct tebi : units::prefix<tebi, prefix, "Ti", ratio( 1'099'511'627'776)> {};
|
||||
struct pebi : units::prefix<pebi, prefix, "Pi", ratio( 1'125'899'906'842'624)> {};
|
||||
struct exbi : units::prefix<exbi, prefix, "Ei", ratio(1'152'921'504'606'846'976)> {};
|
||||
|
||||
}
|
||||
|
||||
@ -381,7 +384,7 @@ unknown/undefined unit type like in the below example::
|
||||
Length auto l = 100q_km_per_h * 10q_s;
|
||||
|
||||
The type of ``l`` above will be
|
||||
:expr:`si::length<scaled_unit<ratio<1, 36, 1>, si::metre>, long double>`. This is caused
|
||||
:expr:`si::length<scaled_unit<ratio(1, 36, 1), si::metre>, long double>`. This is caused
|
||||
by the fact that the library does not define a unit of a length quantity that has the
|
||||
ratio ``10/36`` of a `si::metre`. If such a unit was predefined we would see its concrete
|
||||
type here instead.
|
||||
|
@ -16,14 +16,9 @@ Concepts
|
||||
|
||||
A concept matching a symbol prefix. Satisfied by all instantiations of :class:`prefix`.
|
||||
|
||||
.. concept:: template<typename T> Ratio
|
||||
.. concept:: template<ratio R> UnitRatio
|
||||
|
||||
A concept matching a ratio. Satisfied by all instantiations of :class:`ratio`.
|
||||
|
||||
.. concept:: template<typename R> UnitRatio
|
||||
|
||||
A concept matching unit's ratio. Satisfied by all types that satisfy :expr:`Ratio<R>` and
|
||||
for which :expr:`R::num > 0` and :expr:`R::den > 0`.
|
||||
Satisfied by all ratio values for which :expr:`R.num > 0` and :expr:`R.den > 0`.
|
||||
|
||||
.. concept:: template<typename T> BaseDimension
|
||||
|
||||
|
@ -22,7 +22,7 @@ Defining a New Unit
|
||||
My working desk is of ``180 cm x 60 cm`` which gives an area of ``0.3 m²``. I would like to
|
||||
make it a unit of area for my project::
|
||||
|
||||
struct desk : named_scaled_unit<desk, "desk", no_prefix, ratio<3, 10>, si::square_metre> {};
|
||||
struct desk : named_scaled_unit<desk, "desk", no_prefix, ratio(3, 10), si::square_metre> {};
|
||||
|
||||
With the above I can define a quantity with the area of ``2 desks``::
|
||||
|
||||
@ -59,7 +59,7 @@ Enabling a Unit for Prefixing
|
||||
In case I decide it is reasonable to express my desks with SI prefixes the only thing I have
|
||||
to change in the above code is to replace `no_prefix` with `si_prefix`::
|
||||
|
||||
struct desk : named_scaled_unit<desk, "desk", si::prefix, ratio<3, 10>, si::square_metre> {};
|
||||
struct desk : named_scaled_unit<desk, "desk", si::prefix, ratio(3, 10), si::square_metre> {};
|
||||
|
||||
Now I can define a new unit named ``kilodesk``::
|
||||
|
||||
@ -72,12 +72,12 @@ prefix family and prefixes are needed::
|
||||
|
||||
struct shipping_prefix : prefix_family {};
|
||||
|
||||
struct package : prefix<package, shipping_prefix, "pkg", ratio<6>> {};
|
||||
struct lorry : prefix<lorry, shipping_prefix, "lorry", ratio<6 * 40>> {};
|
||||
struct package : prefix<package, shipping_prefix, "pkg", ratio(6)> {};
|
||||
struct lorry : prefix<lorry, shipping_prefix, "lorry", ratio(6 * 40)> {};
|
||||
|
||||
Now we can use it for our unit::
|
||||
|
||||
struct desk : named_scaled_unit<desk, "desk", shipping_prefix, ratio<3, 10>, si::square_metre> {};
|
||||
struct desk : named_scaled_unit<desk, "desk", shipping_prefix, ratio(3, 10), si::square_metre> {};
|
||||
struct packagedesk : prefixed_unit<packagedesk, package, desk> {};
|
||||
struct lorrydesk : prefixed_unit<lorrydesk, lorry, desk> {};
|
||||
|
||||
|
@ -30,31 +30,22 @@ namespace units::detail {
|
||||
|
||||
template<Exponent E>
|
||||
requires (E::den == 1 || E::den == 2) // TODO provide support for any den
|
||||
struct exp_ratio {
|
||||
using base_ratio = E::dimension::base_unit::ratio;
|
||||
using positive_ratio = conditional<E::num * E::den < 0, ratio<base_ratio::den, base_ratio::num, -base_ratio::exp>, base_ratio>;
|
||||
static constexpr std::intmax_t N = E::num * E::den < 0 ? -E::num : E::num;
|
||||
using pow = ratio_pow<positive_ratio, N>;
|
||||
using type = conditional<E::den == 2, ratio_sqrt<pow>, pow>;
|
||||
};
|
||||
|
||||
template<typename ExpList>
|
||||
struct base_units_ratio_impl;
|
||||
|
||||
template<typename E, typename... Es>
|
||||
struct base_units_ratio_impl<exp_list<E, Es...>> {
|
||||
using type = ratio_multiply<typename exp_ratio<E>::type, typename base_units_ratio_impl<exp_list<Es...>>::type>;
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
struct base_units_ratio_impl<exp_list<E>> {
|
||||
using type = exp_ratio<E>::type;
|
||||
};
|
||||
constexpr ratio exp_ratio()
|
||||
{
|
||||
const ratio base_ratio = E::dimension::base_unit::ratio;
|
||||
const ratio positive_ratio = E::num * E::den < 0 ? ratio(base_ratio.den, base_ratio.num, -base_ratio.exp) : base_ratio;
|
||||
const std::intmax_t N = E::num * E::den < 0 ? -E::num : E::num;
|
||||
const ratio ratio_pow = pow<N>(positive_ratio);
|
||||
return E::den == 2 ? sqrt(ratio_pow) : ratio_pow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates the common ratio of all the references of base units in the derived dimension
|
||||
*/
|
||||
template<typename D>
|
||||
using base_units_ratio = base_units_ratio_impl<typename D::exponents>::type;
|
||||
template<typename... Es>
|
||||
constexpr ratio base_units_ratio(exp_list<Es...>)
|
||||
{
|
||||
return (exp_ratio<Es>() * ...);
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
|
@ -44,20 +44,20 @@ struct common_quantity_impl<quantity<D, U, Rep1>, quantity<D, U, Rep2>, Rep> {
|
||||
|
||||
template<typename D, typename U1, typename Rep1, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D, U1, Rep1>, quantity<D, U2, Rep2>, Rep> {
|
||||
using type = quantity<D, downcast_unit<D, common_ratio<typename U1::ratio, typename U2::ratio>>, Rep>;
|
||||
using type = quantity<D, downcast_unit<D, common_ratio(U1::ratio, U2::ratio)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
|
||||
requires same_unit_reference<dimension_unit<D1>, dimension_unit<D2>>::value
|
||||
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio<typename U1::ratio, typename U2::ratio>>, Rep>;
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio(U1::ratio, U2::ratio)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D1, typename U1, typename Rep1, typename D2, typename U2, typename Rep2, typename Rep>
|
||||
struct common_quantity_impl<quantity<D1, U1, Rep1>, quantity<D2, U2, Rep2>, Rep> {
|
||||
using ratio1 = ratio_multiply<typename D1::base_units_ratio, typename U1::ratio>;
|
||||
using ratio2 = ratio_multiply<typename D2::base_units_ratio, typename U2::ratio>;
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio<ratio1, ratio2>>, Rep>;
|
||||
static constexpr ratio r1 = D1::base_units_ratio * U1::ratio;
|
||||
static constexpr ratio r2 = D2::base_units_ratio * U2::ratio;
|
||||
using type = quantity<D1, downcast_unit<D1, common_ratio(r1, r2)>, Rep>;
|
||||
};
|
||||
|
||||
template<typename D, typename U, typename Rep>
|
||||
|
@ -34,39 +34,23 @@ template<typename... Es, Unit... Us>
|
||||
inline constexpr bool same_scaled_units<exp_list<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
|
||||
|
||||
// deduced_unit
|
||||
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
|
||||
struct ratio_op;
|
||||
|
||||
template<typename Result, int UnitExpDen, typename UnitRatio>
|
||||
struct ratio_op<Result, 0, UnitExpDen, UnitRatio> {
|
||||
using ratio = Result;
|
||||
};
|
||||
template<Exponent E>
|
||||
constexpr ratio inverse_if_negative(const ratio& r)
|
||||
{
|
||||
if constexpr(E::num * E::den > 0)
|
||||
return r;
|
||||
else
|
||||
return inverse(r);
|
||||
}
|
||||
|
||||
template<typename Result, int UnitExpNum, int UnitExpDen, typename UnitRatio>
|
||||
struct ratio_op {
|
||||
using calc_ratio =
|
||||
conditional<(UnitExpNum * UnitExpDen > 0), ratio_multiply<Result, UnitRatio>, ratio_divide<Result, UnitRatio>>;
|
||||
static constexpr int value = (UnitExpNum * UnitExpDen > 0) ? (UnitExpNum - UnitExpDen) : (UnitExpNum + UnitExpDen);
|
||||
using ratio = ratio_op<calc_ratio, value, UnitExpDen, UnitRatio>::ratio;
|
||||
};
|
||||
|
||||
template<typename ExpList, Unit... Us>
|
||||
struct derived_ratio;
|
||||
|
||||
template<Unit... Us>
|
||||
struct derived_ratio<exp_list<>, Us...> {
|
||||
using ratio = ::units::ratio<1>;
|
||||
};
|
||||
|
||||
template<typename E, typename... ERest, Unit U, Unit... URest>
|
||||
struct derived_ratio<exp_list<E, ERest...>, U, URest...> {
|
||||
using rest_ratio = derived_ratio<exp_list<ERest...>, URest...>::ratio;
|
||||
using unit_ratio = ratio_op<rest_ratio, E::num, E::den, typename U::ratio>::ratio;
|
||||
using ratio = ratio_divide<unit_ratio, typename dimension_unit<typename E::dimension>::ratio>;
|
||||
};
|
||||
template<Unit... Us, typename... Es>
|
||||
constexpr ratio derived_ratio(exp_list<Es...>)
|
||||
{
|
||||
return (... * inverse_if_negative<Es>(pow<detail::abs(Es::num)>(Us::ratio) / dimension_unit<typename Es::dimension>::ratio));
|
||||
}
|
||||
|
||||
template<DerivedDimension D, Unit... Us>
|
||||
using deduced_unit =
|
||||
scaled_unit<typename detail::derived_ratio<typename D::recipe, Us...>::ratio, typename D::coherent_unit::reference>;
|
||||
using deduced_unit = scaled_unit<derived_ratio<Us...>(typename D::recipe()), typename D::coherent_unit::reference>;
|
||||
|
||||
} // namespace units::detail
|
||||
|
@ -66,14 +66,14 @@ inline constexpr bool equivalent_dim = detail::equivalent_dim_impl<D1, D2>::valu
|
||||
*
|
||||
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
|
||||
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
|
||||
* and ratio<1>.
|
||||
* and ratio(1).
|
||||
*
|
||||
* @tparam E the list of exponents of ingredient dimensions
|
||||
* @tparam ERest the list of exponents of ingredient dimensions
|
||||
*/
|
||||
template<Exponent E, Exponent... ERest>
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, scaled_unit<ratio<1>, unknown_coherent_unit>, E, ERest...> {
|
||||
using coherent_unit = scaled_unit<ratio<1>, unknown_coherent_unit>;
|
||||
struct unknown_dimension : derived_dimension<unknown_dimension<E, ERest...>, scaled_unit<ratio(1), unknown_coherent_unit>, E, ERest...> {
|
||||
using coherent_unit = scaled_unit<ratio(1), unknown_coherent_unit>;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
@ -23,7 +23,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <units/concepts.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
@ -46,7 +45,7 @@ template<typename T>
|
||||
|
||||
// Computes (a * b) mod m relies on unsigned integer arithmetic, should not
|
||||
// overflow
|
||||
constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m)
|
||||
[[nodiscard]] constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m)
|
||||
{
|
||||
std::uint64_t res = 0;
|
||||
|
||||
@ -78,7 +77,7 @@ constexpr std::uint64_t mulmod(std::uint64_t a, std::uint64_t b, std::uint64_t m
|
||||
}
|
||||
|
||||
// Calculates (a ^ e) mod m , should not overflow.
|
||||
constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m)
|
||||
[[nodiscard]] constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m)
|
||||
{
|
||||
a %= m;
|
||||
std::uint64_t result = 1;
|
||||
@ -94,7 +93,7 @@ constexpr std::uint64_t modpow(std::uint64_t a, std::uint64_t e, std::uint64_t m
|
||||
}
|
||||
|
||||
// gcd(a * 10 ^ e, b), should not overflow
|
||||
constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept
|
||||
[[nodiscard]] constexpr std::intmax_t gcdpow(std::intmax_t a, std::intmax_t e, std::intmax_t b) noexcept
|
||||
{
|
||||
assert(a > 0);
|
||||
assert(e >= 0);
|
||||
@ -120,8 +119,8 @@ constexpr void cwap(std::intmax_t& lhs, std::intmax_t& rhs)
|
||||
}
|
||||
|
||||
// Computes the rational gcd of n1/d1 x 10^e1 and n2/d2 x 10^e2
|
||||
constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2, std::intmax_t d2,
|
||||
std::intmax_t e2) noexcept
|
||||
[[nodiscard]] constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, std::intmax_t n2, std::intmax_t d2,
|
||||
std::intmax_t e2) noexcept
|
||||
{
|
||||
// Short cut for equal ratios
|
||||
if (n1 == n2 && d1 == d2 && e1 == e2) {
|
||||
@ -152,8 +151,14 @@ constexpr auto gcd_frac(std::intmax_t n1, std::intmax_t d1, std::intmax_t e1, st
|
||||
return std::array{num / gcd, den / gcd, exp};
|
||||
}
|
||||
|
||||
constexpr auto normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp)
|
||||
constexpr void normalize(std::intmax_t& num, std::intmax_t& den, std::intmax_t& exp)
|
||||
{
|
||||
if(num == 0) {
|
||||
den = 1;
|
||||
exp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
std::intmax_t gcd = std::gcd(num, den);
|
||||
num = num * (den < 0 ? -1 : 1) / gcd;
|
||||
den = detail::abs(den) / gcd;
|
||||
@ -166,8 +171,23 @@ constexpr auto normalize(std::intmax_t num, std::intmax_t den, std::intmax_t exp
|
||||
den /= 10;
|
||||
--exp;
|
||||
}
|
||||
}
|
||||
|
||||
return std::array{num, den, exp};
|
||||
[[nodiscard]] static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
|
||||
{
|
||||
constexpr std::intmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
|
||||
|
||||
const std::intmax_t a0 = detail::abs(lhs) % c;
|
||||
const std::intmax_t a1 = detail::abs(lhs) / c;
|
||||
const std::intmax_t b0 = detail::abs(rhs) % c;
|
||||
const std::intmax_t b1 = detail::abs(rhs) / c;
|
||||
|
||||
Expects(a1 == 0 || b1 == 0); // overflow in multiplication
|
||||
Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
|
||||
Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
|
||||
Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
|
||||
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
} // namespace units::detail
|
||||
|
@ -32,31 +32,31 @@ namespace units::detail {
|
||||
|
||||
inline constexpr basic_symbol_text base_multiplier("\u00D7 10", "x 10");
|
||||
|
||||
template<typename Ratio>
|
||||
template<ratio R>
|
||||
constexpr auto ratio_text()
|
||||
{
|
||||
if constexpr(Ratio::num == 1 && Ratio::den == 1 && Ratio::exp != 0) {
|
||||
return base_multiplier + superscript<Ratio::exp>() + basic_fixed_string(" ");
|
||||
if constexpr(R.num == 1 && R.den == 1 && R.exp != 0) {
|
||||
return base_multiplier + superscript<R.exp>() + basic_fixed_string(" ");
|
||||
}
|
||||
else if constexpr(Ratio::num != 1 || Ratio::den != 1 || Ratio::exp != 0) {
|
||||
auto txt = basic_fixed_string("[") + regular<Ratio::num>();
|
||||
if constexpr(Ratio::den == 1) {
|
||||
if constexpr(Ratio::exp == 0) {
|
||||
else if constexpr(R.num != 1 || R.den != 1 || R.exp != 0) {
|
||||
auto txt = basic_fixed_string("[") + regular<R.num>();
|
||||
if constexpr(R.den == 1) {
|
||||
if constexpr(R.exp == 0) {
|
||||
return txt + basic_fixed_string("] ");
|
||||
}
|
||||
else {
|
||||
return txt + " " + base_multiplier + superscript<Ratio::exp>() +
|
||||
return txt + " " + base_multiplier + superscript<R.exp>() +
|
||||
basic_fixed_string("] ");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if constexpr(Ratio::exp == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<Ratio::den>() +
|
||||
if constexpr(R.exp == 0) {
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() +
|
||||
basic_fixed_string("] ");
|
||||
}
|
||||
else {
|
||||
return txt + basic_fixed_string("/") + regular<Ratio::den>() +
|
||||
" " + base_multiplier + superscript<Ratio::exp>() +
|
||||
return txt + basic_fixed_string("/") + regular<R.den>() +
|
||||
" " + base_multiplier + superscript<R.exp>() +
|
||||
basic_fixed_string("] ");
|
||||
}
|
||||
}
|
||||
@ -66,30 +66,30 @@ constexpr auto ratio_text()
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ratio, typename PrefixFamily>
|
||||
template<ratio R, typename PrefixFamily>
|
||||
constexpr auto prefix_or_ratio_text()
|
||||
{
|
||||
if constexpr(Ratio::num == 1 && Ratio::den == 1 && Ratio::exp == 0) {
|
||||
if constexpr(R.num == 1 && R.den == 1 && R.exp == 0) {
|
||||
// no ratio/prefix
|
||||
return basic_fixed_string("");
|
||||
}
|
||||
else {
|
||||
if constexpr (!std::is_same_v<PrefixFamily, no_prefix>) {
|
||||
// try to form a prefix
|
||||
using prefix = downcast<detail::prefix_base<PrefixFamily, Ratio>>;
|
||||
using prefix = downcast<detail::prefix_base<PrefixFamily, R>>;
|
||||
|
||||
if constexpr(!std::is_same_v<prefix, prefix_base<PrefixFamily, Ratio>>) {
|
||||
if constexpr(!std::is_same_v<prefix, prefix_base<PrefixFamily, R>>) {
|
||||
// print as a prefixed unit
|
||||
return prefix::symbol;
|
||||
}
|
||||
else {
|
||||
// print as a ratio of the coherent unit
|
||||
return ratio_text<Ratio>();
|
||||
return ratio_text<R>();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// print as a ratio of the coherent unit
|
||||
return ratio_text<Ratio>();
|
||||
return ratio_text<R>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,8 +150,7 @@ constexpr auto unit_text()
|
||||
else {
|
||||
// print as a prefix or ratio of a coherent unit
|
||||
using coherent_unit = dimension_unit<Dim>;
|
||||
using ratio = ratio_divide<typename U::ratio, typename coherent_unit::ratio>;
|
||||
auto prefix_txt = prefix_or_ratio_text<ratio, typename U::reference::prefix_family>();
|
||||
auto prefix_txt = prefix_or_ratio_text<U::ratio / coherent_unit::ratio, typename U::reference::prefix_family>();
|
||||
|
||||
if constexpr(has_symbol<coherent_unit>) {
|
||||
// use predefined coherent unit symbol
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <units/bits/external/downcasting.h>
|
||||
#include <units/bits/external/fixed_string.h>
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <units/ratio.h>
|
||||
#include <units/bits/external/type_traits.h>
|
||||
|
||||
namespace units {
|
||||
@ -63,40 +64,40 @@ template<typename T>
|
||||
concept Prefix = true;
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_ratio = false;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching a ratio
|
||||
*
|
||||
* Satisfied by all instantiations of `ratio`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Ratio = detail::is_ratio<T>;
|
||||
|
||||
/**
|
||||
* @brief A concept matching unit's ratio
|
||||
*
|
||||
* Satisfied by all types that satisfy `Ratio<R>` and for which `R::num > 0` and `R::den > 0`
|
||||
* Satisfied by all ratio values for which `R.num > 0` and `R.den > 0`.
|
||||
*/
|
||||
template<typename R>
|
||||
concept UnitRatio = Ratio<R> && R::num > 0 && R::den > 0; // double negatives not allowed
|
||||
template<ratio R>
|
||||
concept UnitRatio = R.num > 0 && R.den > 0;
|
||||
|
||||
// Unit
|
||||
template<UnitRatio R, typename U>
|
||||
template<ratio R, typename U>
|
||||
requires UnitRatio<R>
|
||||
struct scaled_unit;
|
||||
|
||||
// TODO: Remove when P1985 accepted
|
||||
namespace detail {
|
||||
|
||||
struct is_derived_from_scaled_unit_impl {
|
||||
template<ratio R, typename U>
|
||||
static constexpr std::true_type check_base(const scaled_unit<R, U>&);
|
||||
static constexpr std::false_type check_base(...);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_derived_from_scaled_unit = decltype(is_derived_from_scaled_unit_impl::check_base(std::declval<T>()))::value;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief A concept matching all unit types in the library
|
||||
*
|
||||
* Satisfied by all unit types derived from the instantiation of :class:`scaled_unit`.
|
||||
*/
|
||||
template<typename T>
|
||||
concept Unit = is_derived_from_instantiation<T, scaled_unit>;
|
||||
concept Unit = detail::is_derived_from_scaled_unit<T>;
|
||||
|
||||
template<basic_fixed_string Symbol, Unit U>
|
||||
requires U::is_named
|
||||
|
@ -36,7 +36,7 @@ struct gibibit : prefixed_unit<gibibit, gibi, bit> {};
|
||||
struct tebibit : prefixed_unit<tebibit, tebi, bit> {};
|
||||
struct pebibit : prefixed_unit<pebibit, pebi, bit> {};
|
||||
|
||||
struct byte : named_scaled_unit<byte, "B", prefix, ratio<8>, bit> {};
|
||||
struct byte : named_scaled_unit<byte, "B", prefix, ratio(8), bit> {};
|
||||
struct kibibyte : prefixed_unit<kibibyte, kibi, byte> {};
|
||||
struct mebibyte : prefixed_unit<mebibyte, mebi, byte> {};
|
||||
struct gibibyte : prefixed_unit<gibibyte, gibi, byte> {};
|
||||
|
@ -28,11 +28,11 @@ namespace units::data {
|
||||
|
||||
struct prefix : prefix_family {};
|
||||
|
||||
struct kibi : units::prefix<kibi, prefix, "Ki", ratio< 1'024>> {};
|
||||
struct mebi : units::prefix<mebi, prefix, "Mi", ratio< 1'048'576>> {};
|
||||
struct gibi : units::prefix<gibi, prefix, "Gi", ratio< 1'073'741'824>> {};
|
||||
struct tebi : units::prefix<tebi, prefix, "Ti", ratio< 1'099'511'627'776>> {};
|
||||
struct pebi : units::prefix<pebi, prefix, "Pi", ratio< 1'125'899'906'842'624>> {};
|
||||
struct exbi : units::prefix<exbi, prefix, "Ei", ratio<1'152'921'504'606'846'976>> {};
|
||||
struct kibi : units::prefix<kibi, prefix, "Ki", ratio( 1'024)> {};
|
||||
struct mebi : units::prefix<mebi, prefix, "Mi", ratio( 1'048'576)> {};
|
||||
struct gibi : units::prefix<gibi, prefix, "Gi", ratio( 1'073'741'824)> {};
|
||||
struct tebi : units::prefix<tebi, prefix, "Ti", ratio( 1'099'511'627'776)> {};
|
||||
struct pebi : units::prefix<pebi, prefix, "Pi", ratio( 1'125'899'906'842'624)> {};
|
||||
struct exbi : units::prefix<exbi, prefix, "Ei", ratio(1'152'921'504'606'846'976)> {};
|
||||
|
||||
} // namespace units::data
|
||||
|
@ -82,7 +82,7 @@ template<typename Child, Unit U, Exponent E, Exponent... ERest>
|
||||
struct derived_dimension : downcast_child<Child, typename detail::make_dimension<E, ERest...>> {
|
||||
using recipe = exp_list<E, ERest...>;
|
||||
using coherent_unit = U;
|
||||
using base_units_ratio = detail::base_units_ratio<derived_dimension>;
|
||||
static constexpr ratio base_units_ratio = detail::base_units_ratio(typename derived_dimension::exponents());
|
||||
};
|
||||
|
||||
} // namespace units
|
||||
|
@ -70,10 +70,8 @@ namespace detail {
|
||||
|
||||
template<Exponent E, std::intmax_t Num, std::intmax_t Den>
|
||||
struct exp_multiply_impl {
|
||||
using r1 = ratio<E::num, E::den>;
|
||||
using r2 = ratio<Num, Den>;
|
||||
using r = ratio_multiply<r1, r2>;
|
||||
using type = exp<typename E::dimension, r::num, r::den>;
|
||||
static constexpr ratio r = ratio(E::num, E::den) * ratio(Num, Den);
|
||||
using type = exp<typename E::dimension, r.num, r.den>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
@ -44,8 +44,7 @@ inline Quantity AUTO pow(const Q& q) noexcept
|
||||
requires requires { std::pow(q.count(), N); }
|
||||
{
|
||||
using dim = dimension_pow<typename Q::dimension, N>;
|
||||
using ratio = ratio_pow<typename Q::unit::ratio, N>;
|
||||
using unit = downcast_unit<dim, ratio>;
|
||||
using unit = downcast_unit<dim, pow<N>(Q::unit::ratio)>;
|
||||
using rep = Q::rep;
|
||||
return quantity<dim, unit, rep>(static_cast<rep>(std::pow(q.count(), N)));
|
||||
}
|
||||
@ -75,8 +74,7 @@ inline Quantity AUTO sqrt(const Q& q) noexcept
|
||||
requires requires { std::sqrt(q.count()); }
|
||||
{
|
||||
using dim = dimension_sqrt<typename Q::dimension>;
|
||||
using ratio = ratio_sqrt<typename Q::unit::ratio>;
|
||||
using unit = downcast_unit<dim, ratio>;
|
||||
using unit = downcast_unit<dim, sqrt(Q::unit::ratio)>;
|
||||
using rep = Q::rep;
|
||||
return quantity<dim, unit, rep>(static_cast<rep>(std::sqrt(q.count())));
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace units::physical::fps {
|
||||
struct poundal : named_unit<poundal, "pdl", no_prefix> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Pound_(force)
|
||||
struct pound_force : named_scaled_unit<pound_force, "lbf", si::prefix, ratio<32'174'049, 1'000'000>, poundal> {};
|
||||
struct pound_force : named_scaled_unit<pound_force, "lbf", si::prefix, ratio(32'174'049, 1'000'000), poundal> {};
|
||||
|
||||
struct kilopound_force : prefixed_unit<kilopound_force, si::kilo, pound_force> {};
|
||||
|
||||
|
@ -29,24 +29,24 @@
|
||||
namespace units::physical::fps {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Foot_(unit)
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<3'048, 1'000, -1>, si::metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio(3'048, 1'000, -1), si::metre> {};
|
||||
|
||||
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio<1, 12>, foot> {};
|
||||
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio(1, 12), foot> {};
|
||||
|
||||
// thousandth of an inch
|
||||
struct thousandth : named_scaled_unit<thousandth, "thou", no_prefix, ratio<1, 1'000>, inch> {};
|
||||
struct thousandth : named_scaled_unit<thousandth, "thou", no_prefix, ratio(1, 1'000), inch> {};
|
||||
struct thou : alias_unit<thousandth, "thou", no_prefix>{};
|
||||
struct mil : alias_unit<thousandth, "mil", no_prefix>{};
|
||||
|
||||
struct yard : named_scaled_unit<yard, "yd", si::prefix, ratio<3, 1>, foot> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", si::prefix, ratio(3, 1), foot> {};
|
||||
|
||||
struct fathom : named_scaled_unit<fathom, "ftm", no_prefix, ratio<6, 1>, foot> {};
|
||||
struct fathom : named_scaled_unit<fathom, "ftm", no_prefix, ratio(6, 1), foot> {};
|
||||
|
||||
struct kiloyard : prefixed_unit<kiloyard, si::kilo, yard> {};
|
||||
|
||||
struct mile : named_scaled_unit<mile, "mile", no_prefix, ratio<5'280>, foot> {};
|
||||
struct mile : named_scaled_unit<mile, "mile", no_prefix, ratio(5'280), foot> {};
|
||||
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", no_prefix, ratio<2'000>, yard> {};
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", no_prefix, ratio(2'000), yard> {};
|
||||
|
||||
|
||||
|
||||
|
@ -29,28 +29,28 @@
|
||||
namespace units::physical::fps {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Pound_(mass)
|
||||
struct pound : named_scaled_unit<pound, "lb", no_prefix, ratio<45'359'237, 100'000'000>, si::kilogram> {};
|
||||
struct pound : named_scaled_unit<pound, "lb", no_prefix, ratio(45'359'237, 100'000'000), si::kilogram> {};
|
||||
|
||||
struct dim_mass : physical::dim_mass<pound> {};
|
||||
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using mass = quantity<dim_mass, U, Rep>;
|
||||
|
||||
struct grain : named_scaled_unit<grain, "gr", no_prefix, ratio<1, 7000>, pound>{};
|
||||
struct grain : named_scaled_unit<grain, "gr", no_prefix, ratio(1, 7000), pound>{};
|
||||
|
||||
struct dram : named_scaled_unit<dram, "dr", no_prefix, ratio<1, 256>, pound>{};
|
||||
struct dram : named_scaled_unit<dram, "dr", no_prefix, ratio(1, 256), pound>{};
|
||||
|
||||
struct ounce : named_scaled_unit<ounce, "oz", no_prefix, ratio<1, 16>, pound>{};
|
||||
struct ounce : named_scaled_unit<ounce, "oz", no_prefix, ratio(1, 16), pound>{};
|
||||
|
||||
struct stone : named_scaled_unit<stone, "st", no_prefix, ratio<14, 1>, pound>{};
|
||||
struct stone : named_scaled_unit<stone, "st", no_prefix, ratio(14, 1), pound>{};
|
||||
|
||||
struct quarter : named_scaled_unit<quarter, "qr", no_prefix, ratio<28, 1>, pound>{};
|
||||
struct quarter : named_scaled_unit<quarter, "qr", no_prefix, ratio(28, 1), pound>{};
|
||||
|
||||
struct hundredweight : named_scaled_unit<hundredweight, "cwt", no_prefix, ratio<112, 1>, pound>{};
|
||||
struct hundredweight : named_scaled_unit<hundredweight, "cwt", no_prefix, ratio(112, 1), pound>{};
|
||||
|
||||
struct short_ton : named_scaled_unit<short_ton, "ton (short)", no_prefix, ratio<2'000, 1>, pound>{};
|
||||
struct short_ton : named_scaled_unit<short_ton, "ton (short)", no_prefix, ratio(2'000, 1), pound>{};
|
||||
|
||||
struct long_ton : named_scaled_unit<long_ton, "ton (long)", no_prefix, ratio<2'240, 1>, pound>{};
|
||||
struct long_ton : named_scaled_unit<long_ton, "ton (long)", no_prefix, ratio(2'240, 1), pound>{};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@ -35,7 +35,7 @@ struct dim_power : physical::dim_power<dim_power, foot_poundal_per_second, dim_e
|
||||
|
||||
struct foot_pound_force_per_second : deduced_unit<foot_pound_force_per_second, dim_power, foot_pound_force, second> {};
|
||||
|
||||
struct horse_power : named_scaled_unit<horse_power, "hp", no_prefix, ratio<550>, foot_pound_force_per_second> {};
|
||||
struct horse_power : named_scaled_unit<horse_power, "hp", no_prefix, ratio(550), foot_pound_force_per_second> {};
|
||||
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using power = quantity<dim_power, U, Rep>;
|
||||
|
@ -37,9 +37,9 @@ struct dim_pressure : physical::dim_pressure<dim_pressure, poundal_per_foot_sq,
|
||||
template<Unit U, Scalar Rep = double>
|
||||
using pressure = quantity<dim_pressure, U, Rep>;
|
||||
|
||||
struct pound_force_per_foot_sq : named_scaled_unit<pound_force_per_foot_sq, "lbf ft2", si::prefix, ratio<32'174'049, 1'000'000>, poundal_per_foot_sq> {};
|
||||
struct pound_force_per_foot_sq : named_scaled_unit<pound_force_per_foot_sq, "lbf ft2", si::prefix, ratio(32'174'049, 1'000'000), poundal_per_foot_sq> {};
|
||||
|
||||
struct pound_force_per_inch_sq : named_scaled_unit<pound_force_per_inch_sq, "psi", si::prefix, ratio<1, 144>, pound_force_per_foot_sq> {};
|
||||
struct pound_force_per_inch_sq : named_scaled_unit<pound_force_per_inch_sq, "psi", si::prefix, ratio(1, 144), pound_force_per_foot_sq> {};
|
||||
|
||||
struct kilopound_force_per_inch_sq : prefixed_unit<kilopound_force_per_inch_sq, si::kilo, pound_force_per_inch_sq> {};
|
||||
|
||||
|
@ -28,13 +28,13 @@
|
||||
namespace units::physical::iau {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Light-year
|
||||
struct light_year : named_scaled_unit<light_year, "ly", no_prefix, ratio<9460730472580800>, si::metre> {};
|
||||
struct light_year : named_scaled_unit<light_year, "ly", no_prefix, ratio(9460730472580800), si::metre> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Parsec
|
||||
struct parsec : named_scaled_unit<parsec, "pc", si::prefix, ratio<30'856'775'814'913'673>, si::metre> {};
|
||||
struct parsec : named_scaled_unit<parsec, "pc", si::prefix, ratio(30'856'775'814'913'673), si::metre> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Angstrom
|
||||
struct angstrom : named_scaled_unit<angstrom, "angstrom", no_prefix, ratio<1, 1, -10>, si::metre> {};
|
||||
struct angstrom : named_scaled_unit<angstrom, "angstrom", no_prefix, ratio(1, 1, -10), si::metre> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@ -27,10 +27,10 @@
|
||||
namespace units::physical::imperial {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Chain_(unit)
|
||||
struct chain : named_scaled_unit<chain, "ch", no_prefix, ratio<22, 1>, international::yard> {};
|
||||
struct chain : named_scaled_unit<chain, "ch", no_prefix, ratio(22, 1), international::yard> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Rod_(unit)
|
||||
struct rod : named_scaled_unit<rod, "rd", no_prefix, ratio<1, 4>, chain> {};
|
||||
struct rod : named_scaled_unit<rod, "rd", no_prefix, ratio(1, 4), chain> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@ -29,30 +29,30 @@ namespace units::physical::international {
|
||||
|
||||
// international yard
|
||||
// https://en.wikipedia.org/wiki/International_yard_and_pound
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 1'000, -1>, si::metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio(9'144, 1'000, -1), si::metre> {};
|
||||
|
||||
// international foot
|
||||
// https://en.wikipedia.org/wiki/Foot_(unit)#International_foot
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio(1, 3), yard> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Fathom#International_fathom
|
||||
struct fathom : named_scaled_unit<fathom, "fathom", no_prefix, ratio<2>, yard> {};
|
||||
struct fathom : named_scaled_unit<fathom, "fathom", no_prefix, ratio(2), yard> {};
|
||||
|
||||
// international inch
|
||||
// https://en.wikipedia.org/wiki/Inch#Equivalences
|
||||
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio<1, 36>, yard> {};
|
||||
struct inch : named_scaled_unit<inch, "in", no_prefix, ratio(1, 36), yard> {};
|
||||
|
||||
// intrnational mile
|
||||
// https://en.wikipedia.org/wiki/Mile#International_mile
|
||||
struct mile : named_scaled_unit<mile, "mi", no_prefix, ratio<25'146, 15'625>, si::kilometre> {};
|
||||
struct mile : named_scaled_unit<mile, "mi", no_prefix, ratio(25'146, 15'625), si::kilometre> {};
|
||||
|
||||
// international nautical mile
|
||||
// https://en.wikipedia.org/wiki/Nautical_mile
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", no_prefix, ratio<1852>, si::metre> {};
|
||||
struct nautical_mile : named_scaled_unit<nautical_mile, "mi(naut)", no_prefix, ratio(1852), si::metre> {};
|
||||
|
||||
// thou
|
||||
// https://en.wikipedia.org/wiki/Thousandth_of_an_inch
|
||||
struct thou : named_scaled_unit<thou, "thou", no_prefix, ratio<1, 1000>, inch> {};
|
||||
struct thou : named_scaled_unit<thou, "thou", no_prefix, ratio(1, 1000), inch> {};
|
||||
|
||||
// mil - different name for thou
|
||||
// https://en.wikipedia.org/wiki/Thousandth_of_an_inch
|
||||
|
@ -52,7 +52,7 @@ struct exakatal : prefixed_unit<exakatal, exa, katal> {};
|
||||
struct zettakatal : prefixed_unit<zettakatal, zetta, katal> {};
|
||||
struct yottakatal : prefixed_unit<yottakatal, yotta, katal> {};
|
||||
|
||||
struct enzyme_unit : named_scaled_unit<enzyme_unit, "U", prefix, ratio<1, 60, -6>, katal> {};
|
||||
struct enzyme_unit : named_scaled_unit<enzyme_unit, "U", prefix, ratio(1, 60, -6), katal> {};
|
||||
|
||||
struct dim_catalytic_activity : physical::dim_catalytic_activity<dim_catalytic_activity, katal, dim_time, dim_substance> {};
|
||||
|
||||
|
@ -47,7 +47,7 @@ struct exajoule : prefixed_unit<exajoule, exa, joule> {};
|
||||
struct zettajoule : prefixed_unit<zettajoule, zetta, joule> {};
|
||||
struct yottajoule : prefixed_unit<yottajoule, yotta, joule> {};
|
||||
|
||||
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix, ratio<1'602'176'634, 1'000'000'000, -19>, joule> {};
|
||||
struct electronvolt : named_scaled_unit<electronvolt, "eV", prefix, ratio(1'602'176'634, 1'000'000'000, -19), joule> {};
|
||||
struct gigaelectronvolt : prefixed_unit<gigaelectronvolt, giga, electronvolt> {};
|
||||
|
||||
struct dim_energy : physical::dim_energy<dim_energy, joule, dim_force, dim_length> {};
|
||||
|
@ -50,7 +50,7 @@ struct exametre : prefixed_unit<exametre, exa, metre> {};
|
||||
struct zettametre : prefixed_unit<zettametre, zetta, metre> {};
|
||||
struct yottametre : prefixed_unit<yottametre, yotta, metre> {};
|
||||
|
||||
struct astronomical_unit : named_scaled_unit<astronomical_unit, "au", no_prefix, ratio<149'597'870'700>, metre> {};
|
||||
struct astronomical_unit : named_scaled_unit<astronomical_unit, "au", no_prefix, ratio(149'597'870'700), metre> {};
|
||||
|
||||
struct dim_length : physical::dim_length<metre> {};
|
||||
|
||||
|
@ -50,7 +50,7 @@ struct exatesla : prefixed_unit<exatesla, exa, tesla> {};
|
||||
struct zettatesla : prefixed_unit<zettatesla, zetta, tesla> {};
|
||||
struct yottatesla : prefixed_unit<yottatesla, yotta, tesla> {};
|
||||
|
||||
struct gauss : named_scaled_unit<gauss, "G", prefix, ratio<1, 10'000>, tesla> {};
|
||||
struct gauss : named_scaled_unit<gauss, "G", prefix, ratio(1, 10'000), tesla> {};
|
||||
|
||||
struct dim_magnetic_induction : physical::dim_magnetic_induction<dim_magnetic_induction, tesla, dim_voltage, dim_time, dim_length> {};
|
||||
|
||||
|
@ -72,7 +72,7 @@ struct exatonne : prefixed_alias_unit<yottagram, exa, tonne> {};
|
||||
struct zettatonne : prefixed_unit<zettatonne, zetta, tonne> {};
|
||||
struct yottatonne : prefixed_unit<yottatonne, yotta, tonne> {};
|
||||
|
||||
struct dalton : named_scaled_unit<dalton, "Da", no_prefix, ratio<16'605'390'666'050, 10'000'000'000'000, -27>, kilogram> {};
|
||||
struct dalton : named_scaled_unit<dalton, "Da", no_prefix, ratio(16'605'390'666'050, 10'000'000'000'000, -27), kilogram> {};
|
||||
|
||||
struct dim_mass : physical::dim_mass<kilogram> {};
|
||||
|
||||
|
@ -29,26 +29,26 @@ namespace units::physical::si {
|
||||
struct prefix : prefix_family {};
|
||||
|
||||
// clang-format off
|
||||
struct yocto : units::prefix<yocto, prefix, "y", ratio<1, 1, -24>> {};
|
||||
struct zepto : units::prefix<zepto, prefix, "z", ratio<1, 1, -21>> {};
|
||||
struct atto : units::prefix<atto, prefix, "a", ratio<1, 1, -18>> {};
|
||||
struct femto : units::prefix<femto, prefix, "f", ratio<1, 1, -15>> {};
|
||||
struct pico : units::prefix<pico, prefix, "p", ratio<1, 1, -12>> {};
|
||||
struct nano : units::prefix<nano, prefix, "n", ratio<1, 1, -9>> {};
|
||||
struct micro : units::prefix<micro, prefix, {"\u00b5", "u"}, ratio<1, 1, -6>> {};
|
||||
struct milli : units::prefix<milli, prefix, "m", ratio<1, 1, -3>> {};
|
||||
struct centi : units::prefix<centi, prefix, "c", ratio<1, 1, -2>> {};
|
||||
struct deci : units::prefix<deci, prefix, "d", ratio<1, 1, -1>> {};
|
||||
struct deca : units::prefix<deca, prefix, "da", ratio<1, 1, 1>> {};
|
||||
struct hecto : units::prefix<hecto, prefix, "h", ratio<1, 1, 2>> {};
|
||||
struct kilo : units::prefix<kilo, prefix, "k", ratio<1, 1, 3>> {};
|
||||
struct mega : units::prefix<mega, prefix, "M", ratio<1, 1, 6>> {};
|
||||
struct giga : units::prefix<giga, prefix, "G", ratio<1, 1, 9>> {};
|
||||
struct tera : units::prefix<tera, prefix, "T", ratio<1, 1, 12>> {};
|
||||
struct peta : units::prefix<peta, prefix, "P", ratio<1, 1, 15>> {};
|
||||
struct exa : units::prefix<exa, prefix, "E", ratio<1, 1, 18>> {};
|
||||
struct zetta : units::prefix<zetta, prefix, "Z", ratio<1, 1, 21>> {};
|
||||
struct yotta : units::prefix<yotta, prefix, "Y", ratio<1, 1, 24>> {};
|
||||
struct yocto : units::prefix<yocto, prefix, "y", ratio(1, 1, -24)> {};
|
||||
struct zepto : units::prefix<zepto, prefix, "z", ratio(1, 1, -21)> {};
|
||||
struct atto : units::prefix<atto, prefix, "a", ratio(1, 1, -18)> {};
|
||||
struct femto : units::prefix<femto, prefix, "f", ratio(1, 1, -15)> {};
|
||||
struct pico : units::prefix<pico, prefix, "p", ratio(1, 1, -12)> {};
|
||||
struct nano : units::prefix<nano, prefix, "n", ratio(1, 1, -9)> {};
|
||||
struct micro : units::prefix<micro, prefix, {"\u00b5", "u"}, ratio(1, 1, -6)> {};
|
||||
struct milli : units::prefix<milli, prefix, "m", ratio(1, 1, -3)> {};
|
||||
struct centi : units::prefix<centi, prefix, "c", ratio(1, 1, -2)> {};
|
||||
struct deci : units::prefix<deci, prefix, "d", ratio(1, 1, -1)> {};
|
||||
struct deca : units::prefix<deca, prefix, "da", ratio(1, 1, 1)> {};
|
||||
struct hecto : units::prefix<hecto, prefix, "h", ratio(1, 1, 2)> {};
|
||||
struct kilo : units::prefix<kilo, prefix, "k", ratio(1, 1, 3)> {};
|
||||
struct mega : units::prefix<mega, prefix, "M", ratio(1, 1, 6)> {};
|
||||
struct giga : units::prefix<giga, prefix, "G", ratio(1, 1, 9)> {};
|
||||
struct tera : units::prefix<tera, prefix, "T", ratio(1, 1, 12)> {};
|
||||
struct peta : units::prefix<peta, prefix, "P", ratio(1, 1, 15)> {};
|
||||
struct exa : units::prefix<exa, prefix, "E", ratio(1, 1, 18)> {};
|
||||
struct zetta : units::prefix<zetta, prefix, "Z", ratio(1, 1, 21)> {};
|
||||
struct yotta : units::prefix<yotta, prefix, "Y", ratio(1, 1, 24)> {};
|
||||
// clang-format on
|
||||
|
||||
} // namespace units::physical::si
|
||||
|
@ -37,9 +37,9 @@ struct picosecond : prefixed_unit<picosecond, pico, second> {};
|
||||
struct nanosecond : prefixed_unit<nanosecond, nano, second> {};
|
||||
struct microsecond : prefixed_unit<microsecond, micro, second> {};
|
||||
struct millisecond : prefixed_unit<millisecond, milli, second> {};
|
||||
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio<60>, second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<60>, minute> {};
|
||||
struct day : named_scaled_unit<hour, "d", no_prefix, ratio<24>, hour> {};
|
||||
struct minute : named_scaled_unit<minute, "min", no_prefix, ratio(60), second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(60), minute> {};
|
||||
struct day : named_scaled_unit<hour, "d", no_prefix, ratio(24), hour> {};
|
||||
|
||||
struct dim_time : physical::dim_time<second> {};
|
||||
|
||||
|
@ -28,10 +28,10 @@
|
||||
namespace units::physical::typographic {
|
||||
|
||||
// TODO Conflicts with (https://en.wikipedia.org/wiki/Pica_(typography)), verify correctness of below conversion factors and provide hyperlinks to definitions
|
||||
struct pica_comp : named_scaled_unit<pica_comp, "pica(comp)", no_prefix, ratio<4233333, 1000000, -3>, si::metre> {};
|
||||
struct pica_prn : named_scaled_unit<pica_prn, "pica(prn)", no_prefix, ratio<2108759, 500000, -3>, si::metre> {};
|
||||
struct point_comp : named_scaled_unit<point_comp, "point(comp)", no_prefix, ratio<1763889, 500000, -4>, si::metre> {};
|
||||
struct point_prn : named_scaled_unit<point_prn, "point(prn)", no_prefix, ratio<1757299, 500000, -4>, si::metre> {};
|
||||
struct pica_comp : named_scaled_unit<pica_comp, "pica(comp)", no_prefix, ratio(4233333, 1000000, -3), si::metre> {};
|
||||
struct pica_prn : named_scaled_unit<pica_prn, "pica(prn)", no_prefix, ratio(2108759, 500000, -3), si::metre> {};
|
||||
struct point_comp : named_scaled_unit<point_comp, "point(comp)", no_prefix, ratio(1763889, 500000, -4), si::metre> {};
|
||||
struct point_prn : named_scaled_unit<point_prn, "point(prn)", no_prefix, ratio(1757299, 500000, -4), si::metre> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@ -28,14 +28,14 @@ namespace units::physical::us {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Foot_(unit)#US_survey_foot
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct foot : named_scaled_unit<foot, "ft(us)", no_prefix, ratio<1'200, 3'937>, si::metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft(us)", no_prefix, ratio(1'200, 3'937), si::metre> {};
|
||||
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct fathom : named_scaled_unit<fathom, "fathom(us)", no_prefix, ratio<6>, foot> {};
|
||||
struct fathom : named_scaled_unit<fathom, "fathom(us)", no_prefix, ratio(6), foot> {};
|
||||
|
||||
// https://en.wikipedia.org/wiki/Mile#U.S._survey_mile
|
||||
// https://www.nist.gov/pml/special-publication-811/nist-guide-si-appendix-b-conversion-factors#B6
|
||||
struct mile : named_scaled_unit<mile, "mi(us)", no_prefix, ratio<5280>, us::foot> {};
|
||||
struct mile : named_scaled_unit<mile, "mi(us)", no_prefix, ratio(5280), us::foot> {};
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
@ -45,10 +45,10 @@ struct no_prefix : prefix_family {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<PrefixFamily PF, Ratio R>
|
||||
template<PrefixFamily PF, ratio R>
|
||||
struct prefix_base : downcast_base<prefix_base<PF, R>> {
|
||||
using prefix_family = PF;
|
||||
using ratio = R;
|
||||
static constexpr ::units::ratio ratio = R;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@ -68,7 +68,7 @@ struct prefix_base : downcast_base<prefix_base<PF, R>> {
|
||||
* @tparam Symbol a text representation of the prefix
|
||||
* @tparam R factor to be used to scale a unit
|
||||
*/
|
||||
template<typename Child, PrefixFamily PF, basic_symbol_text Symbol, Ratio R>
|
||||
template<typename Child, PrefixFamily PF, basic_symbol_text Symbol, ratio R>
|
||||
requires (!std::same_as<PF, no_prefix>)
|
||||
struct prefix : downcast_child<Child, detail::prefix_base<PF, R>> {
|
||||
static constexpr auto symbol = Symbol;
|
||||
|
@ -46,7 +46,7 @@ concept safe_convertible = // exposition only
|
||||
template<typename Rep, typename UnitFrom, typename UnitTo>
|
||||
concept safe_divisible = // exposition only
|
||||
treat_as_floating_point<Rep> ||
|
||||
ratio_divide<typename UnitFrom::ratio, typename UnitTo::ratio>::is_integral();
|
||||
is_integral(UnitFrom::ratio / UnitTo::ratio);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -344,11 +344,11 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
equivalent_dim<D1, dim_invert<D2>>
|
||||
{
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
using ratio = ratio_multiply<typename U1::ratio, typename U2::ratio>;
|
||||
const ratio r = U1::ratio * U2::ratio;
|
||||
if constexpr (treat_as_floating_point<common_rep>) {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(ratio::num * fpow10(ratio::exp)) / static_cast<common_rep>(ratio::den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * fpow10<common_rep>(r.exp)) / static_cast<common_rep>(r.den);
|
||||
} else {
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(ratio::num * ipow10(ratio::exp)) / static_cast<common_rep>(ratio::den);
|
||||
return lhs.count() * rhs.count() * static_cast<common_rep>(r.num * ipow10(r.exp)) / static_cast<common_rep>(r.den);
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,10 +357,7 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
requires std::regular_invocable<std::multiplies<>, Rep1, Rep2>
|
||||
{
|
||||
using dim = dimension_multiply<D1, D2>;
|
||||
using ratio1 = ratio_divide<typename U1::ratio, typename dimension_unit<D1>::ratio>;
|
||||
using ratio2 = ratio_divide<typename U2::ratio, typename dimension_unit<D2>::ratio>;
|
||||
using ratio = ratio_multiply<ratio_multiply<ratio1, ratio2>, typename dimension_unit<dim>::ratio>;
|
||||
using unit = downcast_unit<dim, ratio>;
|
||||
using unit = downcast_unit<dim, (U1::ratio / dimension_unit<D1>::ratio) * (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
|
||||
using common_rep = decltype(lhs.count() * rhs.count());
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(lhs.count() * rhs.count());
|
||||
@ -373,8 +370,7 @@ template<Scalar Value, typename D, typename U, typename Rep>
|
||||
Expects(q.count() != 0);
|
||||
|
||||
using dim = dim_invert<D>;
|
||||
using ratio = ratio<U::ratio::den, U::ratio::num, -U::ratio::exp>;
|
||||
using unit = downcast_unit<dim, ratio>;
|
||||
using unit = downcast_unit<dim, ratio(U::ratio.den, U::ratio.num, -U::ratio.exp)>;
|
||||
using common_rep = decltype(v / q.count());
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(v / q.count());
|
||||
@ -411,10 +407,7 @@ template<typename D1, typename U1, typename Rep1, typename D2, typename U2, type
|
||||
|
||||
using common_rep = decltype(lhs.count() / rhs.count());
|
||||
using dim = dimension_divide<D1, D2>;
|
||||
using ratio1 = ratio_divide<typename U1::ratio, typename dimension_unit<D1>::ratio>;
|
||||
using ratio2 = ratio_divide<typename U2::ratio, typename dimension_unit<D2>::ratio>;
|
||||
using ratio = ratio_multiply<ratio_divide<ratio1, ratio2>, typename dimension_unit<dim>::ratio>;
|
||||
using unit = downcast_unit<dim, ratio>;
|
||||
using unit = downcast_unit<dim, (U1::ratio / dimension_unit<D1>::ratio) / (U2::ratio / dimension_unit<D2>::ratio) * dimension_unit<dim>::ratio>;
|
||||
using ret = quantity<dim, unit, common_rep>;
|
||||
return ret(lhs.count() / rhs.count());
|
||||
}
|
||||
|
@ -69,10 +69,10 @@ concept QuantityOf = Quantity<T> && Dimension<Dim> && equivalent_dim<typename T:
|
||||
// quantity_cast
|
||||
namespace detail {
|
||||
|
||||
template<typename To, typename CRatio, typename CRep, bool NumIsOne, bool DenIsOne, bool ExpIsZero>
|
||||
template<typename To, ratio CRatio, typename CRep, bool NumIsOne, bool DenIsOne, bool ExpIsZero>
|
||||
struct quantity_cast_impl;
|
||||
|
||||
template<typename To, typename CRatio, typename CRep>
|
||||
template<typename To, ratio CRatio, typename CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, true, true> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
@ -81,235 +81,227 @@ struct quantity_cast_impl<To, CRatio, CRep, true, true, true> {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio::exp))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio::exp))));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp))));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(ipow10(-CRatio::exp))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(ipow10(-CRatio.exp))));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, false, true> {
|
||||
template<typename Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||
(static_cast<CRep>(CRatio::num) /
|
||||
static_cast<CRep>(CRatio::den))));
|
||||
(static_cast<CRep>(CRatio.num) /
|
||||
static_cast<CRep>(CRatio.den))));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
|
||||
template<typename Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(fpow10<CRep>(CRatio::exp)) *
|
||||
(static_cast<CRep>(CRatio::num) /
|
||||
static_cast<CRep>(CRatio::den))));
|
||||
static_cast<CRep>(fpow10<CRep>(CRatio.exp)) *
|
||||
(static_cast<CRep>(CRatio.num) /
|
||||
static_cast<CRep>(CRatio.den))));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(CRatio::num) *
|
||||
static_cast<CRep>(ipow10(CRatio::exp)) /
|
||||
static_cast<CRep>(CRatio::den)));
|
||||
static_cast<CRep>(CRatio.num) *
|
||||
static_cast<CRep>(ipow10(CRatio.exp)) /
|
||||
static_cast<CRep>(CRatio.den)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) *
|
||||
static_cast<CRep>(CRatio::num) /
|
||||
(static_cast<CRep>(CRatio::den) *
|
||||
static_cast<CRep>(ipow10(-CRatio::exp)))));
|
||||
static_cast<CRep>(CRatio.num) /
|
||||
(static_cast<CRep>(CRatio.den) *
|
||||
static_cast<CRep>(ipow10(-CRatio.exp)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, false, true> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio::den)));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / static_cast<CRep>(CRatio.den)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio::exp)) * (CRep{1} / static_cast<CRep>(CRatio::den))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(fpow10<CRep>(CRatio.exp)) * (CRep{1} / static_cast<CRep>(CRatio.den))));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio::exp)) / static_cast<CRep>(CRatio::den)));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(ipow10(CRatio.exp)) / static_cast<CRep>(CRatio.den)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(ipow10(-CRatio::exp)) * static_cast<CRep>(CRatio::den))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) / (static_cast<CRep>(ipow10(-CRatio.exp)) * static_cast<CRep>(CRatio.den))));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, true, true> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num)));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) * static_cast<CRep>(fpow10<CRep>(CRatio::exp))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(fpow10<CRep>(CRatio.exp))));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) * static_cast<CRep>(ipow10(CRatio::exp))));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) * static_cast<CRep>(ipow10(CRatio.exp))));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio::num) / static_cast<CRep>(ipow10(-CRatio::exp))));
|
||||
return To(static_cast<To::rep>(static_cast<CRep>(q.count()) * static_cast<CRep>(CRatio.num) / static_cast<CRep>(ipow10(-CRatio.exp))));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, true, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio::exp)));
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio.exp)));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * ipow10(CRatio::exp)));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * ipow10(CRatio.exp)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(q.count() / ipow10(-CRatio::exp)));
|
||||
return To(static_cast<To::rep>(q.count() / ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, false, true> {
|
||||
template<typename Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(q.count() * (CRatio::num / CRatio::den)));
|
||||
return To(static_cast<To::rep>(q.count() * (CRatio.num / CRatio.den)));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, false, false> {
|
||||
template<typename Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio::exp) * (CRatio::num / CRatio::den)));
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio.exp) * (CRatio.num / CRatio.den)));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio::num * ipow10(CRatio::exp) / CRatio::den));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp) / CRatio.den));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(q.count()) * CRatio::num / (CRatio::den * ipow10(-CRatio::exp)));
|
||||
return To(static_cast<To::rep>(q.count()) * CRatio.num / (CRatio.den * ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, false, true> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(q.count() / CRatio::den));
|
||||
return To(static_cast<To::rep>(q.count() / CRatio.den));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, true, false, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio::exp) / CRatio::den));
|
||||
return To(static_cast<To::rep>(q.count() * fpow10<CRep>(CRatio.exp) / CRatio.den));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * ipow10(CRatio::exp) / CRatio::den));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * ipow10(CRatio.exp) / CRatio.den));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(q.count() / (ipow10(-CRatio::exp) * CRatio::den)));
|
||||
return To(static_cast<To::rep>(q.count() / (ipow10(-CRatio.exp) * CRatio.den)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, true, true> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
return To(static_cast<To::rep>(q.count() * CRatio::num));
|
||||
return To(static_cast<To::rep>(q.count() * CRatio.num));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename CRatio, not_constructible_from_integral CRep>
|
||||
template<typename To, ratio CRatio, not_constructible_from_integral CRep>
|
||||
struct quantity_cast_impl<To, CRatio, CRep, false, true, false> {
|
||||
template<Quantity Q>
|
||||
static constexpr To cast(const Q& q)
|
||||
{
|
||||
if constexpr (treat_as_floating_point<CRep>) {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio::num * fpow10<CRep>(CRatio::exp)));
|
||||
return To(static_cast<To::rep>(q.count() * CRatio.num * fpow10<CRep>(CRatio.exp)));
|
||||
} else {
|
||||
if constexpr (CRatio::exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio::num * ipow10(CRatio::exp)));
|
||||
if constexpr (CRatio.exp > 0) {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio.num * ipow10(CRatio.exp)));
|
||||
}
|
||||
else {
|
||||
return To(static_cast<To::rep>(q.count() * CRatio::num / ipow10(-CRatio::exp)));
|
||||
return To(static_cast<To::rep>(q.count() * CRatio.num / ipow10(-CRatio.exp)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<Dimension FromD, Unit FromU, Dimension ToD, Unit ToU>
|
||||
struct cast_ratio;
|
||||
|
||||
template<BaseDimension FromD, Unit FromU, BaseDimension ToD, Unit ToU>
|
||||
struct cast_ratio<FromD, FromU, ToD, ToU> {
|
||||
using type = ratio_divide<typename FromU::ratio, typename ToU::ratio>;
|
||||
};
|
||||
|
||||
template<DerivedDimension FromD, Unit FromU, DerivedDimension ToD, Unit ToU>
|
||||
requires same_unit_reference<FromU, ToU>::value
|
||||
struct cast_ratio<FromD, FromU, ToD, ToU> {
|
||||
using type = ratio_divide<typename FromU::ratio, typename ToU::ratio>;
|
||||
};
|
||||
|
||||
template<DerivedDimension FromD, Unit FromU, DerivedDimension ToD, Unit ToU>
|
||||
struct cast_ratio<FromD, FromU, ToD, ToU> {
|
||||
using from_ratio = ratio_multiply<typename FromD::base_units_ratio, typename FromU::ratio>;
|
||||
using to_ratio = ratio_multiply<typename ToD::base_units_ratio, typename ToU::ratio>;
|
||||
using type = ratio_divide<from_ratio, to_ratio>;
|
||||
};
|
||||
constexpr ratio cast_ratio()
|
||||
{
|
||||
if constexpr(BaseDimension<FromD> || same_unit_reference<FromU, ToU>::value) {
|
||||
return FromU::ratio / ToU::ratio;
|
||||
}
|
||||
else {
|
||||
const ratio from_ratio = FromD::base_units_ratio * FromU::ratio;
|
||||
const ratio to_ratio = ToD::base_units_ratio * ToU::ratio;
|
||||
return from_ratio / to_ratio;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -329,11 +321,11 @@ template<Quantity To, typename D, typename U, typename Rep>
|
||||
[[nodiscard]] constexpr auto quantity_cast(const quantity<D, U, Rep>& q)
|
||||
requires QuantityOf<To, D>
|
||||
{
|
||||
using c_ratio = detail::cast_ratio<D, U, typename To::dimension, typename To::unit>::type;
|
||||
using c_ratio = std::integral_constant<ratio, detail::cast_ratio<D, U, typename To::dimension, typename To::unit>()>;
|
||||
using c_rep = std::common_type_t<typename To::rep, Rep>;
|
||||
using ret_unit = downcast_unit<typename To::dimension, typename To::unit::ratio>;
|
||||
using ret_unit = downcast_unit<typename To::dimension, To::unit::ratio>;
|
||||
using ret = quantity<typename To::dimension, ret_unit, typename To::rep>;
|
||||
using cast = detail::quantity_cast_impl<ret, c_ratio, c_rep, c_ratio::num == 1, c_ratio::den == 1, c_ratio::exp == 0>;
|
||||
using cast = detail::quantity_cast_impl<ret, c_ratio::value, c_rep, c_ratio::value.num == 1, c_ratio::value.den == 1, c_ratio::value.exp == 0>;
|
||||
return cast::cast(q);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <units/bits/external/hacks.h>
|
||||
#include <units/concepts.h>
|
||||
#include <units/bits/ratio_maths.h>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
@ -33,192 +32,91 @@
|
||||
|
||||
namespace units {
|
||||
|
||||
struct ratio;
|
||||
constexpr ratio inverse(const ratio& r);
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time rational arithmetic support.
|
||||
*
|
||||
* This class is really similar to @c std::ratio but gets an additional `Exp`
|
||||
* template parameter.
|
||||
*
|
||||
* @tparam Num Numerator
|
||||
* @tparam Den Denominator (default @c 1)
|
||||
* @tparam Exp Exponent (default @c 0)
|
||||
* template parameter that defines the exponent of the ratio. Another important
|
||||
* difference is the fact that the objects of that class are used as class NTTPs
|
||||
* rather then a type template parameter kind.
|
||||
*/
|
||||
template<std::intmax_t Num, std::intmax_t Den = 1, std::intmax_t Exp = 0>
|
||||
requires(Den != 0)
|
||||
struct ratio {
|
||||
static_assert(-INTMAX_MAX <= Num, "numerator too negative");
|
||||
static_assert(-INTMAX_MAX <= Den, "denominator too negative");
|
||||
std::intmax_t num;
|
||||
std::intmax_t den;
|
||||
std::intmax_t exp;
|
||||
|
||||
private:
|
||||
static constexpr auto norm = detail::normalize(Num, Den, Exp);
|
||||
explicit constexpr ratio(std::intmax_t n, std::intmax_t d = 1, std::intmax_t e = 0): num(n), den(d), exp(e)
|
||||
{
|
||||
detail::normalize(num, den, exp);
|
||||
}
|
||||
|
||||
public:
|
||||
static constexpr std::intmax_t num = norm[0];
|
||||
static constexpr std::intmax_t den = norm[1];
|
||||
static constexpr std::intmax_t exp = norm[2];
|
||||
#if __GNUC__ >= 10
|
||||
|
||||
using type = ratio<num, den, exp>;
|
||||
[[nodiscard]] friend constexpr bool operator==(const ratio&, const ratio&) = default;
|
||||
|
||||
static constexpr bool is_integral() {
|
||||
if constexpr (exp < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return detail::gcdpow(num, exp, den) == den;
|
||||
}
|
||||
#else
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator==(const ratio& lhs, const ratio& rhs)
|
||||
{
|
||||
return lhs.num == rhs.num && lhs.den == rhs.den && lhs.exp == rhs.exp;
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr bool operator!=(const ratio& lhs, const ratio& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator*(const ratio& lhs, const ratio& rhs)
|
||||
{
|
||||
const std::intmax_t gcd1 = std::gcd(lhs.num, rhs.den);
|
||||
const std::intmax_t gcd2 = std::gcd(rhs.num, lhs.den);
|
||||
return ratio(detail::safe_multiply(lhs.num / gcd1, rhs.num / gcd2),
|
||||
detail::safe_multiply(lhs.den / gcd2, rhs.den / gcd1),
|
||||
lhs.exp + rhs.exp);
|
||||
}
|
||||
|
||||
[[nodiscard]] friend constexpr ratio operator/(const ratio& lhs, const ratio& rhs)
|
||||
{
|
||||
return lhs * inverse(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<intmax_t Num, intmax_t Den, intmax_t Exp>
|
||||
inline constexpr bool is_ratio<ratio<Num, Den, Exp>> = true;
|
||||
|
||||
// unused, and align exponents process could be subject to overflow in extreme cases
|
||||
|
||||
// template<Ratio R1, Ratio R2>
|
||||
// constexpr auto ratio_add_detail() {
|
||||
// std::intmax_t num1 = R1::num;
|
||||
// std::intmax_t num2 = R2::num;
|
||||
|
||||
// // align exponents
|
||||
// std::intmax_t new_exp = R1::exp;
|
||||
// if constexpr (R1::exp > R2::exp) {
|
||||
// new_exp = R1::exp;
|
||||
// while (new_exp > R2::exp) {
|
||||
// num1 *= 10;
|
||||
// --new_exp;
|
||||
// }
|
||||
// } else if constexpr (R1::exp < R2::exp) {
|
||||
// new_exp = R2::exp;
|
||||
// while (R1::exp < new_exp) {
|
||||
// num2 *= 10;
|
||||
// --new_exp;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // common denominator
|
||||
// std::intmax_t lcm_den = std::lcm(R1::den, R2::den);
|
||||
// num1 = num1 * (lcm_den / R1::den);
|
||||
// num2 = num2 * (lcm_den / R2::den);
|
||||
|
||||
// return std::array{num1 + num2, lcm_den, new_exp};
|
||||
// }
|
||||
|
||||
|
||||
// template<Ratio R1, Ratio R2>
|
||||
// struct ratio_add_impl {
|
||||
// static constexpr auto detail = ratio_add_detail<R1, R2>();
|
||||
// using type = ratio<detail[0], detail[1], detail[2]>;
|
||||
// };
|
||||
}// namespace detail
|
||||
|
||||
|
||||
// ratio_add : not used
|
||||
// template<Ratio R1, Ratio R2>
|
||||
// using ratio_add = detail::ratio_add_impl<R1, R2>::type;
|
||||
|
||||
// ratio_subtract : not used
|
||||
// TODO implement ratio_subtract
|
||||
// template<Ratio R1, Ratio R2>
|
||||
// using ratio_subtract = detail::ratio_subtract_impl<R1, R2>::type;
|
||||
|
||||
// ratio_multiply
|
||||
|
||||
namespace detail {
|
||||
|
||||
static constexpr std::intmax_t safe_multiply(std::intmax_t lhs, std::intmax_t rhs)
|
||||
[[nodiscard]] constexpr ratio inverse(const ratio& r)
|
||||
{
|
||||
constexpr std::intmax_t c = std::uintmax_t(1) << (sizeof(std::intmax_t) * 4);
|
||||
|
||||
const std::intmax_t a0 = detail::abs(lhs) % c;
|
||||
const std::intmax_t a1 = detail::abs(lhs) / c;
|
||||
const std::intmax_t b0 = detail::abs(rhs) % c;
|
||||
const std::intmax_t b1 = detail::abs(rhs) / c;
|
||||
|
||||
Expects(a1 == 0 || b1 == 0); // overflow in multiplication
|
||||
Expects(a0 * b1 + b0 * a1 < (c >> 1)); // overflow in multiplication
|
||||
Expects(b0 * a0 <= INTMAX_MAX); // overflow in multiplication
|
||||
Expects((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0); // overflow in multiplication
|
||||
|
||||
return lhs * rhs;
|
||||
return ratio(r.den, r.num, -r.exp);
|
||||
}
|
||||
|
||||
template<typename R1, typename R2>
|
||||
struct ratio_multiply_impl {
|
||||
private:
|
||||
static constexpr std::intmax_t gcd1 = std::gcd(R1::num, R2::den);
|
||||
static constexpr std::intmax_t gcd2 = std::gcd(R2::num, R1::den);
|
||||
[[nodiscard]] constexpr bool is_integral(const ratio& r)
|
||||
{
|
||||
if(r.exp < 0) {
|
||||
return false;
|
||||
} else {
|
||||
return detail::gcdpow(r.num, r.exp, r.den) == r.den;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr auto norm = detail::normalize(safe_multiply(R1::num / gcd1, R2::num / gcd2),
|
||||
safe_multiply(R1::den / gcd2, R2::den / gcd1),
|
||||
R1::exp + R2::exp);
|
||||
|
||||
static constexpr std::intmax_t norm_num = norm[0];
|
||||
static constexpr std::intmax_t norm_den = norm[1];
|
||||
static constexpr std::intmax_t norm_exp = norm[2];
|
||||
|
||||
public:
|
||||
using type = ratio<norm_num, norm_den, norm_exp>;
|
||||
static constexpr std::intmax_t num = type::num;
|
||||
static constexpr std::intmax_t den = type::den;
|
||||
static constexpr std::intmax_t exp = type::exp;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Ratio R1, Ratio R2>
|
||||
using ratio_multiply = detail::ratio_multiply_impl<R1, R2>::type;
|
||||
|
||||
// ratio_divide
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename R1, typename R2>
|
||||
struct ratio_divide_impl {
|
||||
static_assert(R2::num != 0, "division by 0");
|
||||
using type = ratio_multiply<R1, ratio<R2::den, R2::num, -R2::exp>>;
|
||||
static constexpr std::intmax_t num = type::num;
|
||||
static constexpr std::intmax_t den = type::den;
|
||||
static constexpr std::intmax_t exp = type::exp;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Ratio R1, Ratio R2>
|
||||
using ratio_divide = detail::ratio_divide_impl<R1, R2>::type;
|
||||
|
||||
// ratio_pow
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename R, std::intmax_t N>
|
||||
struct ratio_pow_impl {
|
||||
using type = ratio_multiply<typename ratio_pow_impl<R, N - 1>::type, R>;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct ratio_pow_impl<R, 1> {
|
||||
using type = R;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct ratio_pow_impl<R, 0> {
|
||||
using type = ratio<1>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Ratio R, std::intmax_t N>
|
||||
using ratio_pow = detail::ratio_pow_impl<R, N>::type;
|
||||
|
||||
// ratio_sqrt
|
||||
template<std::intmax_t N>
|
||||
[[nodiscard]] constexpr ratio pow(const ratio& r)
|
||||
{
|
||||
if constexpr(N == 0)
|
||||
return ratio(1);
|
||||
else if constexpr(N == 1)
|
||||
return r;
|
||||
else
|
||||
return pow<N-1>(r) * r;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// sqrt_impl avoids overflow and recursion
|
||||
// from http://www.codecodex.com/wiki/Calculate_an_integer_square_root#C.2B.2B
|
||||
// if v >= place this will fail (so we can't quite use the last bit)
|
||||
static constexpr std::intmax_t sqrt_impl(std::intmax_t v)
|
||||
[[nodiscard]] constexpr std::intmax_t sqrt_impl(std::intmax_t v)
|
||||
{
|
||||
// place = 0x4000 0000 for 32bit
|
||||
// place = 0x4000 0000 0000 0000 for 64bit
|
||||
@ -237,52 +135,34 @@ static constexpr std::intmax_t sqrt_impl(std::intmax_t v)
|
||||
return root;
|
||||
}
|
||||
|
||||
template<Ratio R>
|
||||
constexpr auto make_exp_even()
|
||||
[[nodiscard]] constexpr auto make_exp_even(const ratio& r)
|
||||
{
|
||||
if constexpr (R::exp % 2 == 0)
|
||||
return std::array{R::num, R::den, R::exp}; // already even (incl zero)
|
||||
if(r.exp % 2 == 0)
|
||||
return std::array{r.num, r.den, r.exp}; // already even (incl zero)
|
||||
|
||||
// safely make exp even, so it can be divided by 2 for square root
|
||||
if constexpr (R::exp > 0)
|
||||
return std::array{R::num * 10, R::den, R::exp - 1};
|
||||
if(r.exp > 0)
|
||||
return std::array{r.num * 10, r.den, r.exp - 1};
|
||||
else
|
||||
return std::array{R::num, R::den * 10, R::exp + 1};
|
||||
return std::array{r.num, r.den * 10, r.exp + 1};
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
struct ratio_sqrt_impl {
|
||||
constexpr static auto even = detail::make_exp_even<R>();
|
||||
using type = ratio<detail::sqrt_impl(even[0]), detail::sqrt_impl(even[1]), even[2] / 2>;
|
||||
};
|
||||
|
||||
template<std::intmax_t Den>
|
||||
struct ratio_sqrt_impl<ratio<0, Den>> {
|
||||
using type = ratio<0>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Ratio R>
|
||||
using ratio_sqrt = detail::ratio_sqrt_impl<R>::type;
|
||||
[[nodiscard]] constexpr ratio sqrt(const ratio& r)
|
||||
{
|
||||
if(r.num == 0)
|
||||
return ratio(0);
|
||||
|
||||
const auto even = detail::make_exp_even(r);
|
||||
return ratio(detail::sqrt_impl(even[0]), detail::sqrt_impl(even[1]), even[2] / 2);
|
||||
}
|
||||
|
||||
// common_ratio
|
||||
|
||||
namespace detail {
|
||||
|
||||
// TODO: simplified
|
||||
template<typename R1, typename R2>
|
||||
struct common_ratio_impl {
|
||||
static constexpr auto res = gcd_frac(R1::num, R1::den, R1::exp, R2::num, R2::den, R2::exp);
|
||||
static constexpr std::intmax_t num = res[0];
|
||||
static constexpr std::intmax_t den = res[1];
|
||||
static constexpr std::intmax_t exp = res[2];
|
||||
using type = ratio<num, den, exp>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<Ratio R1, Ratio R2>
|
||||
using common_ratio = detail::common_ratio_impl<R1, R2>::type;
|
||||
[[nodiscard]] constexpr ratio common_ratio(const ratio& r1, const ratio& r2)
|
||||
{
|
||||
const auto res = detail::gcd_frac(r1.num, r1.den, r1.exp, r2.num, r2.den, r2.exp);
|
||||
return ratio(res[0], res[1], res[2]);
|
||||
}
|
||||
|
||||
} // namespace units
|
||||
|
@ -47,16 +47,19 @@ namespace units {
|
||||
* (i.e. all length units are expressed in terms of meter, all mass units are expressed in
|
||||
* terms of gram, ...)
|
||||
*
|
||||
* @tparam U a unit to use as a reference for this dimension
|
||||
* @tparam R a ratio of a reference unit
|
||||
* @tparam U a unit to use as a reference for this dimension
|
||||
*/
|
||||
template<UnitRatio R, typename U>
|
||||
template<ratio R, typename U>
|
||||
requires UnitRatio<R>
|
||||
struct scaled_unit : downcast_base<scaled_unit<R, U>> {
|
||||
using ratio = R;
|
||||
static constexpr ::units::ratio ratio = R;
|
||||
using reference = U;
|
||||
};
|
||||
|
||||
template<Dimension D, UnitRatio R>
|
||||
template<Dimension D, auto R>
|
||||
// template<Dimension D, ratio R> // TODO: GCC crash!!!
|
||||
requires UnitRatio<R>
|
||||
using downcast_unit = downcast<scaled_unit<R, typename dimension_unit<D>::reference>>;
|
||||
|
||||
template<Unit U1, Unit U2>
|
||||
@ -71,7 +74,7 @@ struct same_unit_reference : std::is_same<typename U1::reference, typename U2::r
|
||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||
*/
|
||||
template<typename Child>
|
||||
struct unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
|
||||
struct unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
|
||||
static constexpr bool is_named = false;
|
||||
using prefix_family = no_prefix;
|
||||
};
|
||||
@ -96,7 +99,7 @@ struct unknown_coherent_unit : unit<unknown_coherent_unit> {};
|
||||
* @tparam PF no_prefix or a type of prefix family
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF>
|
||||
struct named_unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
|
||||
struct named_unit : downcast_child<Child, scaled_unit<ratio(1), Child>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@ -116,8 +119,9 @@ struct named_unit : downcast_child<Child, scaled_unit<ratio<1>, Child>> {
|
||||
* @tparam R a scale to apply to U
|
||||
* @tparam U a reference unit to scale
|
||||
*/
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, UnitRatio R, Unit U>
|
||||
struct named_scaled_unit : downcast_child<Child, scaled_unit<ratio_multiply<R, typename U::ratio>, typename U::reference>> {
|
||||
template<typename Child, basic_symbol_text Symbol, PrefixFamily PF, ratio R, Unit U>
|
||||
requires UnitRatio<R>
|
||||
struct named_scaled_unit : downcast_child<Child, scaled_unit<R * U::ratio, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = Symbol;
|
||||
using prefix_family = PF;
|
||||
@ -136,8 +140,7 @@ struct named_scaled_unit : downcast_child<Child, scaled_unit<ratio_multiply<R, t
|
||||
*/
|
||||
template<typename Child, Prefix P, Unit U>
|
||||
requires U::is_named && std::same_as<typename P::prefix_family, typename U::prefix_family>
|
||||
struct prefixed_unit :
|
||||
downcast_child<Child, scaled_unit<ratio_multiply<typename P::ratio, typename U::ratio>, typename U::reference>> {
|
||||
struct prefixed_unit : downcast_child<Child, scaled_unit<P::ratio * U::ratio, typename U::reference>> {
|
||||
static constexpr bool is_named = true;
|
||||
static constexpr auto symbol = P::symbol + U::symbol;
|
||||
using prefix_family = no_prefix;
|
||||
|
@ -115,7 +115,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
||||
{
|
||||
SECTION("in terms of base units")
|
||||
{
|
||||
const length<scaled_unit<ratio<1, 1, 6>, metre>> q(123);
|
||||
const length<scaled_unit<ratio(1, 1, 6), metre>> q(123);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream")
|
||||
@ -136,7 +136,7 @@ TEST_CASE("operator<< on a quantity", "[text][ostream][fmt]")
|
||||
|
||||
SECTION("in terms of derived units")
|
||||
{
|
||||
const energy<scaled_unit<ratio<1, 1, -2>, joule>> q(60);
|
||||
const energy<scaled_unit<ratio(1, 1, -2), joule>> q(60);
|
||||
os << q;
|
||||
|
||||
SECTION("iostream")
|
||||
|
@ -319,7 +319,7 @@ TEST_CASE("fmt::format on synthesized unit symbols", "[text][fmt]")
|
||||
|
||||
SECTION("unknown scaled unit with reference different than the dimension's coherent unit")
|
||||
{
|
||||
CHECK(fmt::format("{}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 × 10⁻³] kg");
|
||||
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio<2, 3>, gram>>(1)) == "1 [2/3 x 10^-3] kg");
|
||||
CHECK(fmt::format("{}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 × 10⁻³] kg");
|
||||
CHECK(fmt::format("{:%Q %Aq}", mass<units::scaled_unit<units::ratio(2, 3), gram>>(1)) == "1 [2/3 x 10^-3] kg");
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ static_assert(10q_cm == 2q_cm_per_s * 5q_s);
|
||||
static_assert(detail::unit_text<dim_speed, centimetre_per_second>() == "cm/s");
|
||||
|
||||
// area
|
||||
static_assert(std::is_same_v<ratio_divide<centimetre::ratio, dimension_unit<dim_length>::ratio>, ratio<1>>);
|
||||
static_assert(centimetre::ratio / dimension_unit<dim_length>::ratio == ratio(1));
|
||||
|
||||
static_assert(1q_cm * 1q_cm == 1q_cm2);
|
||||
static_assert(100q_cm2 / 10q_cm == 10q_cm);
|
||||
|
@ -57,7 +57,7 @@ static_assert(10q_ft == 2q_ft_per_s * 5q_s);
|
||||
static_assert(detail::unit_text<dim_speed, foot_per_second>() == "ft/s");
|
||||
|
||||
// area
|
||||
static_assert(std::is_same_v<ratio_divide<foot::ratio, dimension_unit<dim_length>::ratio>, ratio<1>>);
|
||||
static_assert(foot::ratio / dimension_unit<dim_length>::ratio == ratio(1));
|
||||
|
||||
static_assert(1q_ft * 1q_ft == 1q_ft2);
|
||||
static_assert(100q_ft2 / 10q_ft == 10q_ft);
|
||||
|
@ -209,7 +209,7 @@ static_assert(std::equality_comparable_with<decltype(quantity_point(1q_m)), decl
|
||||
// quantity_cast
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<decltype(quantity_point_cast<scaled_unit<ratio<1>, metre>>(quantity_point(2q_km)))::unit, metre>);
|
||||
std::is_same_v<decltype(quantity_point_cast<scaled_unit<ratio(1), metre>>(quantity_point(2q_km)))::unit, metre>);
|
||||
|
||||
static_assert(quantity_point_cast<quantity_point<dim_length, metre, int>>(quantity_point(2q_km)).relative().count() ==
|
||||
2000);
|
||||
|
@ -39,7 +39,7 @@ using namespace units::physical::si;
|
||||
// constexpr quantity<si::dim_length, second, int> error(0); // should not compile (unit of a different dimension)
|
||||
// constexpr quantity<si::dim_length, metre, quantity<si::dim_length, metre, int>> error(0); // should not compile (quantity used as Rep)
|
||||
// constexpr quantity<metre, si::dim_length, double> error(0); // should not compile (reordered arguments)
|
||||
// constexpr quantity<si::dim_length, scaled_unit<ratio<-1, 1>, metre>, int> error(0); // should not compile (negative unit ratio)
|
||||
// constexpr quantity<si::dim_length, scaled_unit<ratio(-1, 1), metre>, int> error(0); // should not compile (negative unit ratio)
|
||||
|
||||
// member types
|
||||
|
||||
@ -138,23 +138,23 @@ static_assert(std::is_same_v<decltype(1.0 * length<metre, int>()), length<metre,
|
||||
static_assert(
|
||||
std::is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<second, int>()), length<metre, int>>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio<36, 1, 2>, metre>, int>>);
|
||||
std::is_same_v<decltype(speed<metre_per_second, int>() * physical::si::time<hour, int>()), length<scaled_unit<ratio(36, 1, 2), metre>, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre>() * physical::si::time<minute>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio<6, 1, 1>, unknown_coherent_unit>>>);
|
||||
quantity<unknown_dimension<units::exp<dim_length, 1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6, 1, 1), unknown_coherent_unit>>>);
|
||||
static_assert(std::is_same_v<decltype(1 / physical::si::time<second, int>()), frequency<hertz, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio<1, 6, -1>, hertz>, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / physical::si::time<minute, int>()), frequency<scaled_unit<ratio(1, 6, -1), hertz>, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / frequency<hertz, int>()), physical::si::time<second, int>>);
|
||||
static_assert(std::is_same_v<decltype(1 / length<kilometre>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio<1, 1, -3>, unknown_coherent_unit>>>);
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>>, scaled_unit<ratio(1, 1, -3), unknown_coherent_unit>>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() / 1.0), length<metre, double>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() / length<metre, double>()), double>);
|
||||
static_assert(std::is_same_v<decltype(length<kilometre, int>() / length<metre, double>()), double>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(length<metre, int>() / physical::si::time<second, int>()), speed<metre_per_second, int>>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio<1, 6, -1>, metre_per_second>>>);
|
||||
std::is_same_v<decltype(length<metre>() / physical::si::time<minute>()), speed<scaled_unit<ratio(1, 6, -1), metre_per_second>>>);
|
||||
static_assert(std::is_same_v<decltype(physical::si::time<minute>() / length<metre>()),
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio<6 ,1 , 1>, unknown_coherent_unit>>>);
|
||||
quantity<unknown_dimension<units::exp<dim_length, -1>, units::exp<dim_time, 1>>, scaled_unit<ratio(6 ,1 , 1), unknown_coherent_unit>>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() % short(1)), length<metre, int>>);
|
||||
static_assert(std::is_same_v<decltype(length<metre, int>() % length<metre, short>(1)), length<metre, int>>);
|
||||
|
||||
@ -234,7 +234,7 @@ static_assert(std::equality_comparable_with<decltype(1q_m), decltype(1q_ft_us)>)
|
||||
|
||||
// quantity_cast
|
||||
|
||||
static_assert(std::is_same_v<decltype(quantity_cast<scaled_unit<ratio<1>, metre>>(2q_km))::unit, metre>);
|
||||
static_assert(std::is_same_v<decltype(quantity_cast<scaled_unit<ratio(1), metre>>(2q_km))::unit, metre>);
|
||||
|
||||
static_assert(quantity_cast<length<metre, int>>(2q_km).count() == 2000);
|
||||
static_assert(quantity_cast<length<kilometre, int>>(2000q_m).count() == 2);
|
||||
|
@ -1,110 +1,92 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2018 Mateusz Pusz
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include "units/ratio.h"
|
||||
#include "units/ratio.h"
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
|
||||
using namespace units;
|
||||
using namespace units;
|
||||
|
||||
template<Ratio R1, Ratio R2>
|
||||
inline constexpr bool same = R1::num == R2::num && R1::den == R2::den && R1::exp == R2::exp;
|
||||
static_assert(ratio(2, 4) == ratio(1, 2));
|
||||
|
||||
static_assert(same<ratio<2, 4>, ratio<1, 2>>);
|
||||
// basic exponents tests
|
||||
// note use of ::type is required because template params are changed while stamping out template
|
||||
static_assert(ratio(2, 40, 1) == ratio(1, 20, 1));
|
||||
static_assert(ratio(20, 4, -1) == ratio(10, 2, -1));
|
||||
static_assert(ratio(200, 5) == ratio(20'000, 50, -1));
|
||||
|
||||
// basic exponents tests
|
||||
// note use of ::type is required because template params are changed while stamping out template
|
||||
static_assert(std::is_same_v<ratio<2, 40, 1>::type, ratio<1, 20, 1>::type>);
|
||||
static_assert(std::is_same_v<ratio<20, 4, -1>::type, ratio<10, 2, -1>::type>);
|
||||
static_assert(std::is_same_v<ratio<200, 5>::type, ratio<20'000, 50, -1>::type>);
|
||||
static_assert(ratio(1) * ratio(3, 8) == ratio(3, 8));
|
||||
static_assert(ratio(3, 8) * ratio(1) == ratio(3, 8));
|
||||
static_assert(ratio(4) * ratio(1, 8) == ratio(1, 2));
|
||||
static_assert(ratio(4) * ratio(1, 2) == ratio(2));
|
||||
static_assert(ratio(1, 8) * ratio(2) == ratio(1, 4));
|
||||
static_assert(ratio(1, 2) * ratio(8) == ratio(4));
|
||||
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<1>, ratio<3, 8>>, ratio<3, 8>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<3, 8>, ratio<1>>, ratio<3, 8>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 8>>, ratio<1, 2>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<4>, ratio<1, 2>>, ratio<2>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8>, ratio<2>>, ratio<1, 4>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2>, ratio<8>>, ratio<4>>);
|
||||
// multiply with exponents
|
||||
static_assert(ratio(1, 8, 2) * ratio(2, 1, 4) == ratio(1, 4, 6));
|
||||
static_assert(ratio(1, 2, -4) * ratio(8, 1, 3) == ratio(4, 1, -1));
|
||||
|
||||
// multiply with exponents
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 8, 2>, ratio<2, 1, 4>>, ratio<1, 4, 6>>);
|
||||
static_assert(std::is_same_v<ratio_multiply<ratio<1, 2, -4>, ratio<8, 1, 3>>, ratio<4, 1, -1>>);
|
||||
static_assert(ratio(4) / ratio(2) == ratio(2));
|
||||
static_assert(ratio(2) / ratio(8) == ratio(1, 4));
|
||||
static_assert(ratio(1, 8) / ratio(2) == ratio(1, 16));
|
||||
static_assert(ratio(6) / ratio(3) == ratio(2));
|
||||
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<4>, ratio<2>>, ratio<2>>);
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<2>, ratio<8>>, ratio<1, 4>>);
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<1, 8>, ratio<2>>, ratio<1, 16>>);
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<6>, ratio<3>>, ratio<2>>);
|
||||
// divide with exponents
|
||||
static_assert(ratio(1, 8, -6) / ratio(2, 1, -8) == ratio(1, 16, 2));
|
||||
static_assert(ratio(6, 1, 4) / ratio(3) == ratio(2, 1, 4));
|
||||
|
||||
// divide with exponents
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<1, 8, -6>, ratio<2, 1, -8>>, ratio<1, 16, 2>>);
|
||||
static_assert(std::is_same_v<ratio_divide<ratio<6, 1, 4>, ratio<3>>, ratio<2, 1, 4>>);
|
||||
static_assert(pow<0>(ratio(2)) == ratio(1));
|
||||
static_assert(pow<1>(ratio(2)) == ratio(2));
|
||||
static_assert(pow<2>(ratio(2)) == ratio(4));
|
||||
static_assert(pow<3>(ratio(2)) == ratio(8));
|
||||
static_assert(pow<0>(ratio(1, 2)) == ratio(1));
|
||||
static_assert(pow<1>(ratio(1, 2)) == ratio(1, 2));
|
||||
static_assert(pow<2>(ratio(1, 2)) == ratio(1, 4));
|
||||
static_assert(pow<3>(ratio(1, 2)) == ratio(1, 8));
|
||||
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 0>, ratio<1>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 1>, ratio<2>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 2>, ratio<4>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<2>, 3>, ratio<8>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 0>, ratio<1>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 1>, ratio<1, 2>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 2>, ratio<1, 4>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2>, 3>, ratio<1, 8>>);
|
||||
// pow with exponents
|
||||
static_assert(pow<2>(ratio(1, 2, 3)) == ratio(1, 4, 6));
|
||||
static_assert(pow<3>(ratio(1, 2, -6)) == ratio(1, 8, -18));
|
||||
|
||||
// pow with exponents
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, 3>, 2>, ratio<1, 4, 6>>);
|
||||
static_assert(std::is_same_v<ratio_pow<ratio<1, 2, -6>, 3>, ratio<1, 8, -18>>);
|
||||
static_assert(sqrt(ratio(9)) == ratio(3));
|
||||
static_assert(sqrt(ratio(4)) == ratio(2));
|
||||
static_assert(sqrt(ratio(1)) == ratio(1));
|
||||
static_assert(sqrt(ratio(0)) == ratio(0));
|
||||
static_assert(sqrt(ratio(1, 4)) == ratio(1, 2));
|
||||
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<9>>, ratio<3>>);
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<1>>, ratio<1>>);
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<0>>, ratio<0>>);
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<1, 4>>, ratio<1, 2>>);
|
||||
// sqrt with exponents
|
||||
static_assert(sqrt(ratio(9, 1, 2)) == ratio(3, 1, 1));
|
||||
static_assert(sqrt(ratio(4)) == ratio(2));
|
||||
|
||||
// sqrt with exponents
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<9, 1, 2>>, ratio<3, 1, 1>>);
|
||||
static_assert(std::is_same_v<ratio_sqrt<ratio<4>>, ratio<2>>);
|
||||
// common_ratio
|
||||
static_assert(common_ratio(ratio(1), ratio(1000)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(1000), ratio(1)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(1), ratio(1, 1000)) == ratio(1, 1000));
|
||||
static_assert(common_ratio(ratio(1, 1000), ratio(1)) == ratio(1, 1000));
|
||||
static_assert(common_ratio(ratio(100, 1), ratio(10, 1)) == ratio(10, 1));
|
||||
static_assert(common_ratio(ratio(100, 1), ratio(1, 10)) == ratio(1, 10));
|
||||
|
||||
// unused
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 0>, units::ratio<1, 3, 0>>, units::ratio<5, 6, 0>>);
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<1, 2, 1>, units::ratio<1, 3, 1>>, units::ratio<5, 6, 1>>);
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 2>>, units::ratio<37, 56, 2>>);
|
||||
// common ratio with exponents
|
||||
static_assert(common_ratio(ratio(1), ratio(1, 1, 3)) == ratio(1));
|
||||
static_assert(common_ratio(ratio(10, 1, -1), ratio(1, 1, -3)) == ratio(1, 1, -3));
|
||||
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, 2>, units::ratio<2, 7, 1>>, units::ratio<226, 56, 1>>);
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, 1>, units::ratio<3, 8, 2>>, units::ratio<226, 56, 1>>);
|
||||
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<3, 8, -2>, units::ratio<2, 7, -1>>, units::ratio<181, 56, -2>>);
|
||||
// static_assert(std::is_same_v<units::ratio_add<units::ratio<2, 7, -1>, units::ratio<3, 8, -2>>, units::ratio<181, 56, -2>>);
|
||||
|
||||
|
||||
// common_ratio
|
||||
// note use of ::type is required because template params are changed while stamping out template
|
||||
static_assert(std::is_same_v<common_ratio<ratio<1>::type, ratio<1000>>, ratio<1>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<1000>, ratio<1>>::type, ratio<1>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1000>>::type, ratio<1, 1000>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<1, 1000>, ratio<1>>::type, ratio<1, 1000>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<10, 1>>::type, ratio<10, 1>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<100, 1>, ratio<1, 10>>::type, ratio<1, 10>::type>);
|
||||
|
||||
// common ratio with exponents
|
||||
static_assert(std::is_same_v<common_ratio<ratio<1>, ratio<1, 1, 3>>::type, ratio<1>::type>);
|
||||
static_assert(std::is_same_v<common_ratio<ratio<10, 1, -1>, ratio<1, 1, -3>>::type, ratio<1, 1, -3>::type>);
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
@ -237,7 +237,7 @@ static_assert(kilogray::symbol == "kGy");
|
||||
|
||||
// speed
|
||||
|
||||
static_assert(std::is_same_v<decltype(1q_km / 1q_s), speed<scaled_unit<ratio<1, 1, 3>, metre_per_second>, std::int64_t>>);
|
||||
static_assert(std::is_same_v<decltype(1q_km / 1q_s), speed<scaled_unit<ratio(1, 1, 3), metre_per_second>, std::int64_t>>);
|
||||
|
||||
static_assert(10q_m / 5q_s == 2q_m_per_s);
|
||||
static_assert(10 / 5q_s * 1q_m == 2q_m_per_s);
|
||||
|
@ -31,12 +31,12 @@ using namespace units::physical;
|
||||
struct metre : named_unit<metre, "m", si::prefix> {};
|
||||
struct centimetre : prefixed_unit<centimetre, si::centi, metre> {};
|
||||
struct kilometre : prefixed_unit<kilometre, si::kilo, metre> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio<9'144, 1, -4>, metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio<1, 3>, yard> {};
|
||||
struct yard : named_scaled_unit<yard, "yd", no_prefix, ratio(9'144, 1, -4), metre> {};
|
||||
struct foot : named_scaled_unit<foot, "ft", no_prefix, ratio(1, 3), yard> {};
|
||||
struct dim_length : base_dimension<"length", metre> {};
|
||||
|
||||
struct second : named_unit<second, "s", si::prefix> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio<36, 1, 2>, second> {};
|
||||
struct hour : named_scaled_unit<hour, "h", no_prefix, ratio(36, 1, 2), second> {};
|
||||
struct dim_time : base_dimension<"time", second> {};
|
||||
|
||||
struct kelvin : named_unit<kelvin, "K", no_prefix> {};
|
||||
@ -46,11 +46,11 @@ struct metre_per_second : unit<metre_per_second> {};
|
||||
struct dim_speed : derived_dimension<dim_speed, metre_per_second, units::exp<dim_length, 1>, units::exp<dim_time, -1>> {};
|
||||
struct kilometre_per_hour : deduced_unit<kilometre_per_hour, dim_speed, kilometre, hour> {};
|
||||
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1>, metre>>, metre>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<1, 1, -2>, metre>>, centimetre>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio<yard::ratio::num, yard::ratio::den, yard::ratio::exp>, metre>>, yard>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio_multiply<typename yard::ratio, ratio<1, 3>>, metre>>, foot>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio_divide<typename kilometre::ratio, typename hour::ratio>, metre_per_second>>, kilometre_per_hour>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio(1), metre>>, metre>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio(1, 1, -2), metre>>, centimetre>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<ratio(yard::ratio.num, yard::ratio.den, yard::ratio.exp), metre>>, yard>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<yard::ratio * ratio(1, 3), metre>>, foot>);
|
||||
static_assert(std::is_same_v<downcast<scaled_unit<kilometre::ratio / hour::ratio, metre_per_second>>, kilometre_per_hour>);
|
||||
|
||||
static_assert(centimetre::symbol == "cm");
|
||||
static_assert(kilometre::symbol == "km");
|
||||
|
Reference in New Issue
Block a user