xo-umbrella2/xo-unit/utest/mpl_quantity.test.cpp
Roland Conybeare d1fa15f248 Add 'xo-unit/' from commit 'b531e382c2'
git-subtree-dir: xo-unit
git-subtree-mainline: e9ee6992ca
git-subtree-split: b531e382c2
2025-05-10 21:29:43 -05:00

862 lines
28 KiB
C++

/* @file quantity.test.cpp */
#include "xo/unit/mpl/quantity.hpp"
#include "xo/reflect/Reflect.hpp"
//#include <xo/randomgen/random_seed.hpp>
//#include <xo/randomgen/xoshiro256.hpp>
#include <xo/indentlog/scope.hpp>
#include <xo/indentlog/print/tag.hpp>
#include <catch2/catch.hpp>
#include <compare>
namespace xo {
using xo::unit::quantity;
using xo::unit::qty::kilograms;
using xo::unit::qty::meters;
using xo::unit::qty::kilometers;
using xo::unit::qty::milliseconds;
using xo::unit::qty::seconds;
using xo::unit::qty::minutes;
using xo::unit::qty::hours;
using xo::unit::qty::volatility30d;
using xo::unit::qty::volatility250d;
using xo::unit::unit_find_bpu_t;
using xo::unit::unit_conversion_factor_t;
using xo::unit::unit_cartesian_product_t;
using xo::unit::unit_cartesian_product;
using xo::unit::unit_invert_t;
using xo::unit::unit_abbrev_v;
using xo::unit::same_dimension_v;
using xo::unit::dim;
using xo::unit::from_ratio;
using xo::unit::stringliteral_from_ratio;
using xo::unit::ratio2str_aux;
using xo::unit::cstr_from_ratio;
using xo::reflect::Reflect;
namespace units = xo::unit::units;
namespace ut {
/* use 'testcase' snippet to add test cases here */
TEST_CASE("quantity", "[quantity]") {
//constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
//scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.quantity"), xtag("foo", foo), ...);
//log && log("(A)", xtag("foo", foo));
quantity<units::second, int64_t> t = seconds(1L);
REQUIRE(t.scale() == 1);
static_assert(t.basis_power<dim::time> == 1);
static_assert(t.basis_power<dim::mass> == 0);
} /*TEST_CASE(quantity)*/
TEST_CASE("add1", "[quantity]") {
constexpr bool c_debug_flag = false;
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add1"));
quantity<units::second, int64_t> t1 = seconds(1);
quantity<units::second, int64_t> t2 = seconds(2);
static_assert(std::same_as<decltype(t1)::unit_type, units::second>);
static_assert(std::same_as<decltype(t2)::unit_type, units::second>);
auto sum = t1 + t2;
CHECK(strcmp(sum.unit_cstr(), "s") == 0);
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
static_assert(t1.basis_power<dim::time> == 1);
static_assert(t2.basis_power<dim::time> == 1);
REQUIRE(sum.scale() == 3);
} /*TEST_CASE(add1)*/
TEST_CASE("add2", "[quantity]") {
constexpr bool c_debug_flag = false;
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add2"));
quantity<units::second, int64_t> t1 = seconds(1);
{
CHECK(strcmp(t1.unit_cstr(), "s") == 0);
CHECK(t1.scale() == 1);
}
auto m2 = minutes(2);
{
static_assert(m2.basis_power<dim::time> == 1);
log && log(xtag("m2.scale", m2.scale()), xtag("m2.unit", m2.unit_cstr()));
CHECK(m2.scale() == 2);
CHECK(strcmp(m2.unit_cstr(), "min") == 0);
}
{
auto m2_sec = m2.in_units_of<units::second, int64_t>();
static_assert(std::same_as<decltype(m2_sec), int64_t>);
log && log(XTAG(m2_sec));
CHECK(m2_sec == 120);
}
quantity<units::second, int64_t> t2 = m2;
{
auto sum = t1 + t2;
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
static_assert(sum.basis_power<dim::time> == 1);
log && log(xtag("t1.unit", t1.unit_cstr()), xtag("t2.unit", t2.unit_cstr()));
log && log(xtag("sum.unit", sum.unit_cstr()));
CHECK(strcmp(t2.unit_cstr(), "s") == 0);
CHECK(strcmp(sum.unit_cstr(), "s") == 0);
CHECK(sum.scale() == 121);
}
} /*TEST_CASE(add2)*/
TEST_CASE("add3", "[quantity]") {
quantity<units::second, int64_t> t1 = seconds(1);
quantity<units::minute, int64_t> t2 = minutes(2);
/* sum will take unit from lhs argument to + */
auto sum = t1 + t2;
static_assert(sum.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(sum)::unit_type, units::second>);
REQUIRE(sum.scale() == 121);
} /*TEST_CASE(add3)*/
TEST_CASE("add4", "[quantity]") {
constexpr bool c_debug_flag = false;
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add4"));
using u_kgps_result = unit_cartesian_product<units::kilogram, unit_invert_t<units::second>>;
using u_kgps = u_kgps_result::exact_unit_type;
using u_gpm_result = unit_cartesian_product<units::gram, unit_invert_t<units::minute>>;
using u_gpm = u_gpm_result::exact_unit_type;
{
static_assert(u_kgps_result::c_scalefactor_inexact == 1.0);
static_assert(std::same_as<unit_find_bpu_t<u_kgps, dim::mass>::power_type, std::ratio<1>>);
static_assert(std::same_as<unit_find_bpu_t<u_kgps, dim::time>::power_type, std::ratio<-1>>);
static_assert(std::same_as<unit_find_bpu_t<u_gpm, dim::mass>::power_type, std::ratio<1>>);
static_assert(std::same_as<unit_find_bpu_t<u_gpm, dim::time>::power_type, std::ratio<-1>>);
log && log(xtag("u_kgps", unit_abbrev_v<u_kgps>.c_str()));
log && log(xtag("u_gpm", unit_abbrev_v<u_gpm>.c_str()));
CHECK(strcmp(unit_abbrev_v<u_kgps>.c_str(), "kg.s^-1") == 0);
CHECK(strcmp(unit_abbrev_v<u_gpm>.c_str(), "g.min^-1") == 0);
static_assert(same_dimension_v<u_kgps, u_gpm>);
}
using convert_type = unit_conversion_factor_t<u_kgps, u_gpm>;
{
log && log(xtag("u_kgps->u_gpm", cstr_from_ratio<convert_type>()));
CHECK(strcmp(cstr_from_ratio<convert_type>(), "60000") == 0);
CHECK(from_ratio<int64_t, convert_type>() == 60000);
}
/* note: in practice probably write
* kilograms(0.1) / seconds(1);
* but
* 1. don't want to exercise quantity {*,/} here;
* 2. want to force unit representation
*/
auto q1 = quantity<u_kgps, double>::promote(0.1);
auto q2 = quantity<u_gpm, double>();
{
q2 = q1;
static_assert(q1.basis_power<dim::mass> == 1);
static_assert(q1.basis_power<dim::time> == -1);
static_assert(q2.basis_power<dim::mass> == 1);
static_assert(q2.basis_power<dim::time> == -1);
log && log(XTAG(q1), XTAG(q2));
CHECK(strcmp(q1.unit_cstr(), "kg.s^-1") == 0);
CHECK(q1.scale() == 0.1);
CHECK(strcmp(q2.unit_cstr(), "g.min^-1") == 0);
CHECK(q2.scale() == 6000.0);
}
} /*TEST_CASE(add4)*/
TEST_CASE("add5", "[quantity][fractional_dimension]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.add5"));
//log && log("(A)", xtag("foo", foo));
auto vol_250d = volatility250d(0.2);
{
log && log(xtag("vol_250d", vol_250d));
CHECK(strcmp(vol_250d.unit_cstr(), "yr250^-(1/2)") == 0);
CHECK(vol_250d.scale() == 0.2);
}
/* scaling factor from 30-day vol to 250-day vol is sqrt(250/30) ~ 2.88675
* so 0.1 -> 0.288675
*/
auto vol_30d = volatility30d(0.1);
{
log && log(xtag("vol_30d", vol_30d));
CHECK(strcmp(vol_30d.unit_cstr(), "mo^-(1/2)") == 0);
CHECK(vol_30d.scale() == Approx(0.1).epsilon(1e-6));
}
/* conversion from monthly vol to (250-day) annual vol */
using u_vol250d = units::volatility_250d;
{
quantity<u_vol250d, double> q = vol_30d;
log && log(xtag("q", q));
CHECK(strcmp(q.unit_cstr(), "yr250^-(1/2)") == 0);
CHECK(q.scale() == Approx(0.288675).epsilon(1e-6));
}
{
auto sum = vol_250d + vol_30d;
static_assert(sum.basis_power<dim::time, double> == -0.5);
log && log(XTAG(sum));
CHECK(strcmp(sum.unit_cstr(), "yr250^-(1/2)") == 0);
/* 0.1mo^-(1/2) ~ 0.288675yr250^-(1/2) */
CHECK(sum.scale() == Approx(0.4886751).epsilon(1e-6));
}
} /*TEST_CASE(add5)*/
TEST_CASE("mult1", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.mult1"));
//log && log("(A)", xtag("foo", foo));
auto q0 = milliseconds(5);
auto q1 = seconds(60);
auto q2 = minutes(1);
{
auto r = q0 * q1;
static_assert(r.basis_power<dim::time> == 2);
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0*q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* taking unit from LHS */
REQUIRE(strcmp(r.unit_cstr(), "ms^2") == 0);
REQUIRE(r.scale() == 300000);
}
{
auto r = q1 * q2;
static_assert(r.basis_power<dim::time> == 2);
log && log(xtag("q1", q1), xtag("q2", q2), xtag("q1*q2", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* taking unit from LHS */
REQUIRE(strcmp(r.unit_cstr(), "s^2") == 0);
REQUIRE(r.scale() == 3600);
}
{
auto r = q2 * q1;
static_assert(r.basis_power<dim::time> == 2);
log && log(xtag("q1", q1), xtag("q2", q2), xtag("r=q2*q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* taking unit from LHS */
CHECK(strcmp(r.unit_cstr(), "min^2") == 0);
CHECK(r.scale() == 1);
}
{
auto r = q2 * 60;
static_assert(r.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(r)::repr_type, int>);
log && log(xtag("q2*60", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
CHECK(strcmp(r.unit_cstr(), "min") == 0);
CHECK(r.scale() == 60);
}
{
auto r = q2 * 60U;
static_assert(r.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(r)::repr_type, uint32_t>);
log && log(xtag("q2*60U", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
CHECK(strcmp(r.unit_cstr(), "min") == 0);
CHECK(r.scale() == 60U);
}
{
auto r = (q2 * 60.5);
static_assert(r.basis_power<dim::time> == 1);
/* verify dimension */
static_assert(std::same_as<decltype(r)::repr_type, double>);
log && log(xtag("q2*60.5", q2*60.5));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
REQUIRE(strcmp(r.unit_cstr(), "min") == 0);
REQUIRE(r.scale() == 60.5);
}
{
log && log(xtag("q2*60.5f", q2*60.5f));
auto r = (q2 * 60.5f);
/* verify dimension */
static_assert(r.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(r)::repr_type, float>);
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
REQUIRE(strcmp(r.unit_cstr(), "min") == 0);
REQUIRE(r.scale() == 60.5f);
}
{
auto r = 60 * q2;
static_assert(r.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(r)::repr_type, int>);
log && log(xtag("60*q2", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
CHECK(strcmp(r.unit_cstr(), "min") == 0);
CHECK(r.scale() == 60);
}
{
log && log(xtag("60.5*q2", 60.5*q2));
auto r = 60.5 * q2;
static_assert(r.basis_power<dim::time> == 1);
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
static_assert(std::same_as<decltype(r)::repr_type, double>);
/* preserve units of existing quantity */
CHECK(strcmp(r.unit_cstr(), "min") == 0);
CHECK(r.scale() == 60.5);
}
{
log && log(xtag("60.5f*q2", 60.5f*q2));
auto r = 60.5f * q2;
static_assert(r.basis_power<dim::time> == 1);
static_assert(std::same_as<decltype(r)::repr_type, float>);
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* preserve units of existing quantity */
CHECK(strcmp(r.unit_cstr(), "min") == 0);
CHECK(r.scale() == 60.5);
}
} /*TEST_CASE(mult1)*/
TEST_CASE("div1", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div1"));
//log && log("(A)", xtag("foo", foo));
auto q0 = milliseconds(5);
auto q1 = milliseconds(10);
{
/* repr_type adopts argument to milliseconds() */
static_assert(std::same_as<decltype(q0)::repr_type, int>);
static_assert(std::same_as<decltype(q1)::repr_type, int>);
auto r = q0/q1;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimensionless + no type promotion */
static_assert(std::same_as<decltype(r), int>);
/* verify scale (truncate)*/
REQUIRE(r == 0);
}
auto q0p = milliseconds(5.0);
{
static_assert(std::same_as<decltype(q0p)::repr_type, double>);
auto r = q0p/q1;
static_assert(std::same_as<decltype(r), double>);
log && log(XTAG(q0p), xtag("q0p/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(std::same_as<decltype(r), double>);
/* verify scale */
REQUIRE(r == 0.5);
}
auto r1 = 1.0 / q0;
{
log && log(XTAG(q0), xtag("r1=1.0/q0", r1));
/* verify dimension */
static_assert(r1.basis_power<dim::time> == -1);
/* verify scale */
REQUIRE(r1.scale() == 0.2);
}
} /*TEST_CASE(div1)*/
TEST_CASE("div2", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div2"));
auto q0 = milliseconds(5);
auto q1 = milliseconds(20.0);
{
auto r = q0/q1;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(std::same_as<decltype(r), double>);
/* verify scale */
REQUIRE(r == 0.25);
}
{
auto r = q1/q0;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q1/q0", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(std::same_as<decltype(r), double>);
/* verify scale */
REQUIRE(r == 4.0);
}
{
auto r = q0/(q1*q1);
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/(q1*q1)", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(r.basis_power<dim::time> == -1);
/* verify scale */
REQUIRE(r.scale() == 0.0125);
}
{
auto r = (q0*q0)/q1;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("(q0*q0)/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(r.basis_power<dim::time> == 1);
/* verify scale */
REQUIRE(r.scale() == 1.25);
}
} /*TEST_CASE(div2)*/
TEST_CASE("div3", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div3"));
auto q0 = milliseconds(5);
auto q1 = milliseconds(20.0);
{
auto r = q0/q1;
log && log(XTAG(q0), XTAG(q1), xtag("q0/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(std::same_as<decltype(r), double>);
/* verify scale */
REQUIRE(r == 0.25);
}
{
auto r = q1/q0;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q1/q0", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(std::same_as<decltype(r), double>);
/* verify scale */
REQUIRE(r == 4.0);
}
{
auto r = q0/(q1*q1);
log && log(xtag("q0", q0), xtag("q1", q1), xtag("q0/(q1*q1)", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(r.basis_power<dim::time> == -1);
/* verify scale */
REQUIRE(r.scale() == 0.0125);
}
{
auto r = (q0*q0)/q1;
log && log(xtag("q0", q0), xtag("q1", q1), xtag("(q0*q0)/q1", r));
log && log(xtag("r.type", Reflect::require<decltype(r)>()->canonical_name()));
/* verify dimension */
static_assert(r.basis_power<dim::time> == 1);
/* verify scale */
REQUIRE(r.scale() == 1.25);
}
} /*TEST_CASE(div3)*/
TEST_CASE("div4", "[quantity]") {
/* test with exact scalefactor */
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div4"));
//log && log("(A)", xtag("foo", foo));
auto q1 = milliseconds(1);
auto q2 = minutes(1);
auto r = q1 / q2.with_repr<double>();
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
* so q1/q2 ~ 0.6928
*/
log && log(XTAG(q1), XTAG(q2), xtag("q1/q2", r));
/* verify dimensionless result */
static_assert(std::same_as<decltype(r), double>);
/* verify scale of result */
CHECK(r == Approx(0.00001666667).epsilon(1e-6));
} /*TEST_CASE(div4)*/
TEST_CASE("div5", "[quantity]") {
/* test with inexact scalefactor */
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.div5"));
//log && log("(A)", xtag("foo", foo));
auto q1 = volatility250d(0.2);
auto q2 = volatility30d(0.1);
auto r = q1/q2;
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
* so q1/q2 ~ 0.6928
*/
log && log(XTAG(q1), XTAG(q2), XTAG(q1/q2));
/* verify dimensionless result */
static_assert(std::same_as<decltype(r), double>);
/* verify scale of result */
CHECK(r == Approx(0.692820323).epsilon(1e-6));
} /*TEST_CASE(div5)*/
TEST_CASE("muldiv5", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.muldiv5"));
//log && log("(A)", xtag("foo", foo));
auto t = milliseconds(10);
auto m = kilograms(2.5);
auto a = m / (t * t);
/* 0.1/sqrt(30dy) ~ 0.288675/sqrt(250dy),
* so q1/q2 ~ 0.6928
*/
log && log(XTAG(m), XTAG(t), xtag("a=m.t^-2", a));
/* verify dimensions of result + sticky units */
CHECK(strcmp(t.unit_cstr(), "ms") == 0);
CHECK(strcmp(m.unit_cstr(), "kg") == 0);
CHECK(strcmp(a.unit_cstr(), "kg.ms^-2") == 0);
CHECK(a.scale() == 0.025);
/* verify scale of result */
//CHECK(r == Approx(0.692820323).epsilon(1e-6));
} /*TEST_CASE(muldiv5)*/
TEST_CASE("rescale", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.rescale"));
//log && log("(A)", xtag("foo", foo));
auto q = kilograms(150.0) / minutes(1); /* 150.0kg.min^-1 */
CHECK(strcmp(q.unit_cstr(), "kg.min^-1") == 0);
CHECK(q.scale() == 150.0);
log && log(XTAG(q));
namespace u = xo::unit::units;
auto q1 = q.with_basis_unit<u::millisecond>(); /* 0.0025kg.ms^-1 */
CHECK(strcmp(q1.unit_cstr(), "kg.ms^-1") == 0);
CHECK(q1.scale() == 0.0025);
log && log(XTAG(q1));
auto q2 = q1.with_basis_unit<u::gram>(); /* 2.5g.ms^-1 */
CHECK(strcmp(q2.unit_cstr(), "g.ms^-1") == 0);
CHECK(q2.scale() == 2.5);
log && log(XTAG(q2));
auto q3 = q2.with_basis_unit<u::second>(); /* 2500g.s^-1 */
CHECK(strcmp(q3.unit_cstr(), "g.s^-1") == 0);
CHECK(q3.scale() == 2500.0);
log && log(XTAG(q3));
} /*TEST_CASE(rescale)*/
TEST_CASE("rescale2", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.rescale2"));
//log && log("(A)", xtag("foo", foo));
namespace u = xo::unit::unit_qty;
auto q1 = kilometers(150.0) / u::hour;
auto q2 = q1.with_units_from(u::meter / u::second);
log && log(XTAG(q1), XTAG(q2));
} /*TEST_CASE(rescale2)*/
TEST_CASE("compare1", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.compare1"));
//log && log("(A)", xtag("foo", foo));
namespace u = xo::unit::unit_qty;
auto q1 = kilometers(150.0) / u::hour;
auto q2 = kilometers(100.0) / u::hour;
CHECK(is_gt(q1 <=> q2));
CHECK(is_eq(q1 <=> q1));
CHECK(is_lt(q2 <=> q1));
CHECK(q1 == q1);
CHECK(q1 != q2);
CHECK(q1 >= q1);
CHECK(q1 <= q1);
CHECK(q1 > q2);
CHECK(q1 >= q2);
CHECK(q2 < q1);
CHECK(q2 <= q1);
log && log(XTAG(q1), XTAG(q2), XTAG(is_gt(q1<=>q2)));
} /*TEST_CASE(compare1)*/
TEST_CASE("compare2", "[quantity]") {
constexpr bool c_debug_flag = false;
// can get bits from /dev/random by uncommenting the 2nd line below
//uint64_t seed = xxx;
//rng::Seed<xoshio256ss> seed;
//auto rng = xo::rng::xoshiro256ss(seed);
scope log(XO_DEBUG2(c_debug_flag, "TEST_CASE.compare2"));
//log && log("(A)", xtag("foo", foo));
namespace u = xo::unit::unit_qty;
auto q1 = kilometers(150.0) / u::hour;
auto q2 = meters(30.0) / u::second;
CHECK(is_gt(q1 <=> q2));
CHECK(is_eq(q1 <=> q1));
CHECK(is_lt(q2 <=> q1));
CHECK(q1 == q1);
CHECK(q1 != q2);
CHECK(q1 >= q1);
CHECK(q1 <= q1);
CHECK(q1 > q2);
CHECK(q1 >= q2);
CHECK(q2 < q1);
CHECK(q2 <= q1);
log && log(XTAG(q1), XTAG(q2), XTAG(is_gt(q1<=>q2)));
} /*TEST_CASE(compare2)*/
} /*namespace ut*/
} /*namespace xo*/
/* end quantity.test.cpp */