795 lines
26 KiB
C++
795 lines
26 KiB
C++
/* @file quantity.test.cpp */
|
|
|
|
#include "xo/unit/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>
|
|
|
|
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 = true;
|
|
|
|
// 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)*/
|
|
|
|
|
|
|
|
} /*namespace ut*/
|
|
} /*namespace xo*/
|
|
|
|
/* end quantity.test.cpp */
|