xo-unit: kitchen-sink doc + build improvements + 1 bug fix

This commit is contained in:
Roland Conybeare 2024-05-22 15:16:17 -04:00
commit 412a0ba163
45 changed files with 1712 additions and 472 deletions

View file

@ -16,13 +16,18 @@ namespace xo {
/** @class basis_unit
* @brief A dimensionless multiple of a single natively-specified basis dimension
*
* For example "3600 minutes" or "1e-6 grams"
* For example "3600 minutes" or "1e-6 grams".
*
* Members are public so that a @c basis_unit instance qualifies as a 'structural type',
* and therefore may be used as a non-type template parameter.
**/
struct basis_unit {
public:
/** @defgroup basis-unit-constructors basis_unit constructors **/
///@{
/** sentinel basis unit: invalid dimension and zero scalefactor **/
constexpr basis_unit() = default;
/** basis unit representing multiple @p scalefactor of native dimension @p **/
constexpr basis_unit(dimension native_dim,
const scalefactor_ratio_type & scalefactor)
: native_dim_{native_dim},
@ -32,22 +37,27 @@ namespace xo {
/** @defgroup basis-unit-access-methods basis_unit access methods **/
///@{
/** get @c native_dim member **/
constexpr dimension native_dim() const { return native_dim_; }
/** get @c scalefactor member **/
constexpr const scalefactor_ratio_type & scalefactor() const { return scalefactor_; }
///@}
public: /* public so instance can be a non-type template parameter (a structural type) */
/** @defgroup basis-unit-instance-vars basis_unit instance variables **/
///@{
/** @brief identifies a native unit, e.g. time (in seconds) **/
/** @brief identifies a native unit, e.g. time **/
dimension native_dim_ = dimension::invalid;
/** @brief this unit defined as multiple scalefactor times native unit **/
scalefactor_ratio_type scalefactor_;
scalefactor_ratio_type scalefactor_ = {};
///@}
};
/** @defgroup basis-unit-comparison-support basis_unit comparisons **/
///@{
/** @c true iff basis units are equal;
* both native dimension and scalefactor must be equal
**/
inline constexpr bool
operator==(const basis_unit & x, const basis_unit & y)
{
@ -55,6 +65,7 @@ namespace xo {
&& (x.scalefactor_ == y.scalefactor_));
}
/** @c true iff bass units are not equal **/
inline constexpr bool
operator!=(const basis_unit & x, const basis_unit & y)
{
@ -64,6 +75,7 @@ namespace xo {
///@}
namespace detail {
/** @brief namespace for basis-unit constants and helpers **/
namespace bu {
// ----- mass -----
@ -73,15 +85,25 @@ namespace xo {
/** @defgroup basis-unit-mass-units basis_unit mass units **/
///@{
/** basis unit of 10^-12 grams **/
constexpr basis_unit picogram = mass_unit( 1, 1000000000000);
/** basis unit of 10^-9 grams **/
constexpr basis_unit nanogram = mass_unit( 1, 1000000000);
/** basis unit of 10^-6 grams **/
constexpr basis_unit microgram = mass_unit( 1, 1000000);
/** basis unit of 10^-3 grams **/
constexpr basis_unit milligram = mass_unit( 1, 1000);
/** basis unit of 1 gram **/
constexpr basis_unit gram = mass_unit( 1, 1);
/** basis unit of 10^3 grams **/
constexpr basis_unit kilogram = mass_unit( 1000, 1);
/** basis unit of 10^6 grams = 10^3 kilograms **/
constexpr basis_unit tonne = mass_unit( 1000000, 1);
/** basis unit of 10^9 grams = 10^6 kilograms = 10^3 tonnes **/
constexpr basis_unit kilotonne = mass_unit( 1000000000, 1);
/** basis unit of 10^12 grams = 10^9 kilograms = 10^6 tonnes **/
constexpr basis_unit megatonne = mass_unit( 1000000000000, 1);
/** basis unit of 10^15 grams = 10^12 kilograms = 10^9 tonnes **/
constexpr basis_unit gigatonne = mass_unit(1000000000000000, 1);
///@}
@ -94,26 +116,44 @@ namespace xo {
/** @defgroup basis-unit-distance-units basis_unit distance units **/
///@{
/* US spelling */
/** basis unit of 10^-12 meters **/
constexpr basis_unit picometer = distance_unit( 1, 1000000000000);
/** basis unit of 10^-9 meters **/
constexpr basis_unit nanometer = distance_unit( 1, 1000000000);
/** basis unit of 10^-6 meters **/
constexpr basis_unit micrometer = distance_unit( 1, 1000000);
/** basis unit of 10^-3 meters **/
constexpr basis_unit millimeter = distance_unit( 1, 1000);
/** basis unit of 1 meter **/
constexpr basis_unit meter = distance_unit( 1, 1);
/** basis unit of 10^3 meters **/
constexpr basis_unit kilometer = distance_unit( 1000, 1);
/** basis unit of 10^6 meters (for form's sake -- not commonly used) **/
constexpr basis_unit megameter = distance_unit( 1000000, 1);
/** basis unit of 10^9 meters (for form's sake -- not commonly used) **/
constexpr basis_unit gigameter = distance_unit( 1000000000, 1);
/** basis unit of 1 light-second = distance light travels in a vacuum in 1 second **/
constexpr basis_unit lightsecond = distance_unit( 299792458, 1);
/** basis unit of 1 astronomical unit, representing approximate radius of earth orbit. **/
constexpr basis_unit astronomicalunit = distance_unit( 149597870700, 1);
/* Int'l spelling */
/** international spelling for picometer **/
constexpr basis_unit picometre = picometer;
/** international spelling for nanometer **/
constexpr basis_unit nanometre = nanometer;
/** international spelling for micrometer **/
constexpr basis_unit micrometre = micrometer;
/** international spelling for millimeter **/
constexpr basis_unit millimetre = millimeter;
/** international spelling for meter **/
constexpr basis_unit metre = meter;
/** international spelling for kilometer **/
constexpr basis_unit kilometre = kilometer;
/** international spelling for megameter **/
constexpr basis_unit megametre = megameter;
/** international spelling for gigameter **/
constexpr basis_unit gigametre = gigameter;
/** @brief basis-unit representing 1 inch; defined as exactly 1/12 feet **/
@ -134,22 +174,37 @@ namespace xo {
/** @defgroup basis-unit-time-units basis_unit time units **/
///@{
/** basis unit of 10^-12 seconds **/
constexpr basis_unit picosecond = time_unit( 1, 1000000000000);
/** basis unit of 10^-9 seconds **/
constexpr basis_unit nanosecond = time_unit( 1, 1000000000);
/** basis unit of 10^-6 seconds **/
constexpr basis_unit microsecond = time_unit( 1, 1000000);
/** basis unit of 10^-3 seconds **/
constexpr basis_unit millisecond = time_unit( 1, 1000);
/** basis unit of 1 second **/
constexpr basis_unit second = time_unit( 1, 1);
/** basis unit of 1 minute = 60 seconds **/
constexpr basis_unit minute = time_unit( 60, 1);
/** basis unit of 1 hour = 3600 seconds **/
constexpr basis_unit hour = time_unit( 3600, 1);
/** basis unit of 1 day = exactly 24 hours **/
constexpr basis_unit day = time_unit( 24*3600, 1);
/** basis unit of 1 week = exactly 7 days **/
constexpr basis_unit week = time_unit( 7*24*3600, 1);
/** basis unit of 1 month = exactly 30 days **/
constexpr basis_unit month = time_unit( 30*24*3600, 1);
/** basis unit of 1 year, defined as 365.25 days **/
constexpr basis_unit year = time_unit( (365*24+6)*3600, 1);
/* alt conventions used in finance */
/** basis unit of 1 year365 = exactly 365 days **/
constexpr basis_unit year365 = time_unit( 365*24*3600, 1);
/** basis unit of 1 year360 = exactly 360 days **/
constexpr basis_unit year360 = time_unit( 360*24*3600, 1);
/* 250 = approx number of trading days in a calendar year */
/** basis unit of 1 year250 = exactly 250 days.
* Approximate number of business days in one year
**/
constexpr basis_unit year250 = time_unit( 250*24*3600, 1);
//constexpr basis_unit century = time_unit( 100L*(365*24+6)*3600, 1);
@ -165,7 +220,7 @@ namespace xo {
return basis_unit(dimension::currency, scalefactor_ratio_type(num, den));
}
/* pseudounit -- placeholder for any actual currency amount */
/** pseudounit -- placeholder for any actual currency amount **/
constexpr basis_unit currency = currency_unit(1, 1);
// ----- price -----
@ -174,7 +229,7 @@ namespace xo {
return basis_unit(dimension::price, scalefactor_ratio_type(num, den));
}
/* psuedounit -- context-dependent interpretation */
/** psuedounit -- context-dependent interpretation for a screen price **/
constexpr basis_unit price = price_unit(1, 1);
///@}
} /*namespace bu*/

View file

@ -41,7 +41,7 @@ namespace xo {
}
}
/** @brief construct suffix abbreviation for a basis-power-unit **/
/** construct suffix abbreviation for a basis-power-unit **/
static constexpr bpu_abbrev_type
bpu_abbrev(dim native_dim,
const scalefactor_ratio_type & scalefactor,
@ -67,23 +67,29 @@ namespace xo {
public:
/** @defgroup bpu-ctors bpu constructors **/
///@{
/** default constructor. creates dimensionless bpu,
* representing zero'th power of sentinel basis unit
**/
constexpr bpu() = default;
/** construct @c bpu representing exponent @p power of basis unit @p bu **/
constexpr bpu(const basis_unit & bu,
const power_ratio_type & power)
: bu_{bu},
power_{power}
{}
/** construct @c bpu representing exponent @p power of @c basis_unit(native_dim,scalefactor) **/
constexpr bpu(dim native_dim,
const scalefactor_ratio_type & scalefactor,
const power_ratio_type & power)
: bu_(native_dim, scalefactor),
power_{power}
{}
///@}
/** construct bpu representing basis unit @p bu, i.e. with unit exponent **/
static constexpr bpu<Int> unit_power(const basis_unit & bu) {
return bpu<Int>(bu, power_ratio_type(1,1));
}
///@}
/** @defgroup bpu-access-methods bpu access methods **/
///@{
@ -99,7 +105,7 @@ namespace xo {
/** @defgroup bpu-methods **/
///@{
/** @brief abbreviation for this dimension
/** abbreviation for this dimension
*
* @code
* bpu<int64_t>(dim::time,
@ -114,7 +120,7 @@ namespace xo {
power_);
}
/** @brief for bpu @c x, @c x.reciprocal() represents dimension of @c 1/x
/** for bpu @c x, @c x.reciprocal() represents dimension of @c 1/x
*
* Example:
* @code
@ -129,7 +135,7 @@ namespace xo {
return bpu<Int>(bu_.native_dim(), bu_.scalefactor(), power_.negate());
}
/** @brief construct bpu representing the same unit, but using @c Int2 to represent exponenct **/
/** construct bpu representing the same unit, but using @c Int2 to represent exponenct **/
template <typename Int2>
constexpr bpu<Int2> to_repr() const {
return bpu<Int2>(this->native_dim(),
@ -141,21 +147,29 @@ namespace xo {
public: /* need public members so that a basis_unit instance can be a non-type template parameter (a structural type) */
/** @defgroup bpu-instance-vars **/
///@{
/** @brief this bpu represent a power of this basis unit **/
/** this @c bpu represent a power of basis unit @c bu.
*
* Public to avoid disqualifying @c bpu as a 'structural type'.
**/
struct basis_unit bu_;
/** @brief this unit represents basis dimension (bu) taken to this power **/
power_ratio_type power_;
/** this unit represents basis dimension (bu) taken to this power
*
* Public to avoid disqualifying @c bpu as a 'structural type'.
**/
power_ratio_type power_ = {};
///@}
};
/** @defgroup bpu-comparison **/
///@{
/** @brief compare bpus @p x and @p y for equality **/
/** @brief compare bpus @p x and @p y for equality
*
* Equality requires that both basis unit and power are equal
**/
template <typename Int>
inline constexpr bool
operator==(const bpu<Int> & x, const bpu<Int> & y) {
return ((x.native_dim() == y.native_dim())
&& (x.scalefactor() == y.scalefactor())
return ((x.bu() == y.bu())
&& (x.power_ == y.power_));
}
@ -163,8 +177,7 @@ namespace xo {
template <typename Int>
inline constexpr bool
operator!=(const bpu<Int> & x, const bpu<Int> & y) {
return ((x.native_dim() != y.native_dim())
|| (x.scalefactor() != y.scalefactor())
return ((x.bu() != y.bu())
|| (x.power_ != y.power_));
}
///@}

View file

@ -31,9 +31,7 @@ namespace xo {
p_target->push_back(bpu0);
push_bpu_array(p_target, args...);
}
}
namespace detail {
template <typename Int>
struct nu_maker {
template <typename... Ts>
@ -52,40 +50,61 @@ namespace xo {
* 1. Quantities are represented as a multiple of a natural unit
* 2. Each bpu in the array represents a power of a basis dimension, e.g. "meter" or "second^2".
* 3. Each bpu in an array has a different dimension id.
* For example dim::time, if present, appears once.
* For example @c dim::time, if present, appears once.
* 4. Basis dimensions can appear in any order.
* Order used for constructing abbreviations: will get @c "kg.m" or @c "m.kg"
* depending on the orderin of @c dim::distance and @c dim::mass in @c bpu_v_
* depending on the ordering of @c dim::distance and @c dim::mass in @c bpu_v_
*
* @c Int supplies representation for numerator and denominator in basis-unit scale factors.
**/
template <typename Int>
class natural_unit {
public:
/** @defgroup natural-unit-type-traits natural unit type traits **/
///@{
/** @brief representation for numerator and denominator of scalefactor ratios **/
using ratio_int_type = Int;
///@}
public:
/** @addtogroup natural-unit-ctors **/
///@{
/** construct dimensionless unit **/
constexpr natural_unit() : n_bpu_{0} {}
/** construct unit representing basis unit @p bu with exponent @p power **/
static constexpr natural_unit from_bu(basis_unit bu,
power_ratio_type power = power_ratio_type(1)) {
return detail::nu_maker<Int>::make_nu(bpu<Int>(bu, power));
}
///@}
/** @addtogroup natural-unit-access-methods **/
///@{
/** always true. @see scaled_unit::is_natural **/
/** always true. Provided for symmetry with @c xo::qty::scaled_unit::is_natural **/
constexpr bool is_natural() const { return true; }
/** get member @c n_bpu **/
constexpr std::size_t n_bpu() const { return n_bpu_; }
/** true if this unit has no dimension **/
constexpr bool is_dimensionless() const { return n_bpu_ == 0; }
/** get address of member @c bpu_v **/
constexpr bpu<Int> * bpu_v() const { return bpu_v_; }
///@}
/** @defgroup natural-unit-methods **/
///@{
/** construct reciprocal of this unit.
*
* For example reciprocal of a newton (abbreviation @c "kg.m.s^-2") is
* a unit with abbreviation @c "kg^-1.m^-1.s^2"
**/
constexpr natural_unit reciprocal() const {
natural_unit retval;
@ -95,6 +114,12 @@ namespace xo {
return retval;
}
/** abbreviation for this unit.
*
* Apply as suffix when printing quantities involving this unit.
*
* For example @c "mm" for millimeters, or @c "ns" for nanoseconds
**/
constexpr nu_abbrev_type abbrev() const {
nu_abbrev_type retval;
@ -107,7 +132,7 @@ namespace xo {
return retval;
}
/** @brief remove bpu at position @p p **/
/** remove bpu at position @p p **/
constexpr void remove_bpu(size_t p) {
for (std::size_t i = p; i+1 < n_bpu_; ++i)
bpu_v_[i] = bpu_v_[i+1];
@ -115,20 +140,44 @@ namespace xo {
--n_bpu_;
}
/** append @p bpu to this unit in-place
*
* Require @c bpu.native_dim does not match any existing member of @ref bpu_v_
**/
constexpr void push_back(const bpu<Int> & bpu) {
if (n_bpu_ < n_dim)
bpu_v_[n_bpu_++] = bpu;
}
///@}
/** @addtogroup natural-unit-access-methods **/
///@{
/** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/
constexpr bpu<Int> lookup_dim(dimension d) const {
for (std::size_t i = 0, n = n_bpu(); i<n; ++i) {
if (d == bpu_v_[i].native_dim())
return bpu_v_[i];
}
/** not found, return sentinel **/
return bpu<Int>(d, scalefactor_ratio_type(0), power_ratio_type(0));
}
/** get element @p i of @ref bpu_v_ **/
constexpr bpu<Int> & operator[](std::size_t i) { return bpu_v_[i]; }
/** get element @p i of @ref bpu_v_ (const version) **/
constexpr const bpu<Int> & operator[](std::size_t i) const { return bpu_v_[i]; }
///@}
/** @defgroup natural-unit-conversion-methods **/
///@{
/** convert to equivalent unit using scalefactor representation @p Int2 instead of
* @ref ratio_int_type
**/
template <typename Int2>
constexpr natural_unit<Int2> to_repr() const {
natural_unit<Int2> retval;
@ -139,38 +188,58 @@ namespace xo {
return retval;
}
///@}
public: /* public members so instance can be non-type template parameter (is a structural type) */
/** @defgroup natural-unit-instance-vars **/
///@{
/** @brief the number of occupied slots in @c bpu_v_ **/
/** the number of occupied slots in @c bpu_v_ **/
std::size_t n_bpu_;
/** @brief storage for basis power units **/
/** storage for basis power units **/
bpu<Int> bpu_v_[n_dim];
///@}
};
/** @defgroup natural-unit-comparison-functions natural-unit comparison functions **/
///@{
/** compare natural units @p x, @p y for equality. **/
template <typename Int>
constexpr bool
operator==(const natural_unit<Int> & x, const natural_unit<Int> & y) {
operator==(const natural_unit<Int> & x,
const natural_unit<Int> & y)
{
if (x.n_bpu() != y.n_bpu())
return false;
for (std::size_t i = 0, n = x.n_bpu(); i<n; ++i)
if (x[i] != y[i])
/* does x contain any dimension that isn't present in y? */
for (std::size_t i = 0, n = x.n_bpu(); i<n; ++i) {
const bpu<Int> & xi = x[i];
if (xi != y.lookup_dim(xi.native_dim()))
return false;
}
/* if all bpu's x[i] match something from y, then x,y must be equal
* since they each have the same number of bpu's
*/
return true;
}
/** compare natural units @p x, @p y for inequality **/
template <typename Int>
constexpr bool
operator!=(const natural_unit<Int> & x, const natural_unit<Int> & y) {
operator!=(const natural_unit<Int> & x,
const natural_unit<Int> & y) {
return !(x == y);
}
///@}
namespace detail {
/**
* Given bpu ~ (b.u)^p:
@ -387,6 +456,11 @@ namespace xo {
} /*namespace detail*/
/** @brief namespace for constants representing basis natural units
*
* Application code will typically use parallel scaled-unit constants
* (see the 'u' namespace in 'scaled_unit.hpp')
**/
namespace nu {
constexpr auto dimensionless = natural_unit<std::int64_t>();
@ -445,7 +519,8 @@ namespace xo {
constexpr auto volatility_30d = natural_unit<std::int64_t>::from_bu(detail::bu::month, power_ratio_type(-1,2));
constexpr auto volatility_250d = natural_unit<std::int64_t>::from_bu(detail::bu::year250, power_ratio_type(-1,2));
constexpr auto volatility_360d = natural_unit<std::int64_t>::from_bu(detail::bu::year360, power_ratio_type(-1,2));
constexpr auto volatility_365d = natural_unit<std::int64_t>::from_bu(detail::bu::year365, power_ratio_type(-1,2)); } /*namespace nu*/
constexpr auto volatility_365d = natural_unit<std::int64_t>::from_bu(detail::bu::year365, power_ratio_type(-1,2));
} /*namespace nu*/
} /*namespace qty*/
} /*namespace xo*/

View file

@ -15,7 +15,7 @@ namespace xo {
*
* @brief represent a scalar quantity with associated units.
*
* - @p NaturalUnit is a non-type template parameter
* - @p NaturalUnit is a non-type template paramoeter
* identifying a unit used for this quantity.
* In *xo-unit* it will be an instance of @c natural_unit
* - @p Repr is a type used to represent a multiple
@ -93,19 +93,19 @@ namespace xo {
}
///@}
/** @defgroup quantity-unit-conversion **/
///@{
/** create equivalent quantity using scale representation @p Repr2 instead of @c Repr **/
template <typename Repr2>
constexpr
auto with_repr() const {
return quantity<s_scaled_unit, Repr2>(scale_);
}
/** @defgroup quantity-unit-conversion **/
///@{
/* parallel implementation to Quantity<Repr, Int>::rescale(),
* except that NaturalUnit2 is a compile-time-only template-argument
*
* NOTE: constexpr as long as no fractional units involved.
*/
/** create equivalent quantity expressed as a multiple of @p NaturalUnit2
* instead of @ref s_unit
**/
template <natural_unit<ratio_int_type> NaturalUnit2>
constexpr
auto rescale() const {
@ -126,6 +126,9 @@ namespace xo {
}
}
/** create equivalent quantity expressed as as multiple of @p ScaledUnit2
* instead of @ref s_unit
**/
template <scaled_unit<ratio_int_type> ScaledUnit2>
constexpr
auto rescale_ext() const {
@ -156,6 +159,10 @@ namespace xo {
}
///@}
/** create quantity representing this amount multiplied by dimensionless value @p x
*
* @pre x must be an arithmetic type such as @c int or @c double
**/
template <typename Dimensionless>
requires std::is_arithmetic_v<Dimensionless>
constexpr auto scale_by(Dimensionless x) const {
@ -173,7 +180,7 @@ namespace xo {
/** @defgroup quantity-comparison-support **/
///@{
/* parallel implementation to Quantity<Repr, Int> */
/** compare two @c quantity instances, under three-way comparison **/
template <typename Quantity2>
static constexpr
auto compare(const quantity &x, const Quantity2 & y) {
@ -189,19 +196,21 @@ namespace xo {
// operator*=
// operator/=
/** **/
constexpr nu_abbrev_type abbrev() const {
return s_scaled_unit.natural_unit_.abbrev();
}
/** @defgroup quantity-assignment quantity assignment operators **/
///@{
/** @brief assignment from quantity with identical units **/
/** assignment from quantity with identical units **/
quantity & operator=(const quantity & x) {
this->scale_ = x.scale_;
return *this;
}
/** @brief assignment from quantity with compatible units **/
/** assignment from quantity with compatible units **/
template <typename Q2>
requires(quantity_concept<Q2>
&& Q2::always_constexpr_unit)
@ -212,44 +221,68 @@ namespace xo {
return *this;
}
///@}
/** @defgroup quantity-unit-conversion **/
///@{
/** */
template <typename Q2>
requires(quantity_concept<Q2>
&& Q2::always_constexpr_unit)
constexpr operator Q2() const {
return this->template rescale_ext<Q2::s_scaled_unit>().template with_repr<typename Q2::repr_type>();
}
///@}
/** For dimensionless quantities: convert to underlying scale value
*
* Not present for dimensioned quantities.
**/
constexpr operator Repr() const
requires (ScaledUnit.is_dimensionless())
{
return scale_;
}
///@}
public: /* need public members so that instance can be a non-type template parameter (is a structural type) */
/** @defgroup quantity-static-vars **/
///@{
/** @brief unit for quantity of this type. Determined at compile-time **/
static constexpr scaled_unit<ratio_int_type> s_scaled_unit = ScaledUnit;
///@}
/** @defgroup quantity-instance-vars **/
///@{
/** @brief quantity represents this multiple of @ref s_scaled_unit **/
/** quantity represents this multiple of @ref s_scaled_unit
*
* Public to avoid disqualifying @c quantity as a 'structural type';
* prerequisite for using a @c quantity instance as a non-type template parameter
**/
Repr scale_ = Repr{};
///@}
};
///@{
/**
*
**/
template <typename Quantity, typename Int, typename Int2x>
constexpr auto
rescale(const Quantity & x, const scaled_unit<Int, Int2x> & su) {
rescale(const Quantity & x,
const scaled_unit<Int, Int2x> & su) {
return x.template rescale<su>();
}
///@}
namespace detail {
struct quantity_util {
/* parallel implementation to xquantity<Repr, Int> multiply,
@ -451,29 +484,49 @@ namespace xo {
namespace qty {
// ----- mass -----
/** create quantity representing @p x picograms of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto picograms(Repr x) { return quantity<u::picogram, Repr>(x); }
/** create quantity representing @p x nanograms of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto nanograms(Repr x) { return quantity<u::nanogram, Repr>(x); }
/** create quantity representing @p x micrograms of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto micrograms(Repr x) { return quantity<u::microgram, Repr>(x); }
/** create quantity representing @p x milligrams of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto milligrams(Repr x) { return quantity<u::milligram, Repr>(x); }
/** create quantity representing @p x grams of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto grams(Repr x) { return quantity<u::gram, Repr>(x); }
/** @brief create a quantity representing @p x kilograms of mass, with compile-time unit representation **/
/** create quantity representing @p x kilograms of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto kilograms(Repr x) { return quantity<u::kilogram, Repr>(x); }
/** create quantity representing @p x tonnes of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto tonnes(Repr x) { return quantity<u::tonne, Repr>(x); }
/** create quantity representing @p x kilotonnes of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto kilotonnes(Repr x) { return quantity<u::kilotonne, Repr>(x); }
/** create quantity representing @p x megatonnes of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto megatonnes(Repr x) { return quantity<u::megatonne, Repr>(x); }
/** create quantity representing @p x gigatonnes of mass, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto gigatonnes(Repr x) { return quantity<u::gigatonne, Repr>(x); }
}
namespace qty {
// ----- mass constants ----
/** @brief a quantity representing 1 picogram of mass, with compile-time unit representation **/
static constexpr auto picogram = picograms(1);
@ -496,46 +549,74 @@ namespace xo {
namespace qty {
// ----- distance -----
/** create quantity representing @p x picometers of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto picometers(Repr x) { return quantity<u::picometer, Repr>(x); }
/** create quantity representing @p x nanometers of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto nanometers(Repr x) { return quantity<u::nanometer, Repr>(x); }
/** create quantity representing @p x micrometers of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto micrometers(Repr x) { return quantity<u::micrometer, Repr>(x); }
/** create quantity representing @p x millimeters of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto millimeters(Repr x) { return quantity<u::millimeter, Repr>(x); }
/** create quantity representing @p x meters of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto meters(Repr x) { return quantity<u::meter, Repr>(x); }
/** create quantity representing @p x kilometers of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto kilometers(Repr x) { return quantity<u::kilometer, Repr>(x); }
/** create quantity representing @p x megameters of distance, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto megameters(Repr x) { return quantity<u::megameter, Repr>(x); }
/** create quantity representing @p x gigameters of distance,
* with compile-time unit operations
**/
template <typename Repr>
inline constexpr auto gigameters(Repr x) { return quantity<u::gigameter, Repr>(x); }
/** create quantity representing @p x light-seconds of distance,
* with compile-time unit operations.
**/
template <typename Repr>
inline constexpr auto lightseconds(Repr x) { return quantity<u::lightsecond, Repr>(x); }
/** create quantity representing @p x astronomical units of distance,
* with compile-time unit representation
**/
template <typename Repr>
inline constexpr auto astronomicalunits(Repr x) { return quantity<u::astronomicalunit, Repr>(x); }
/** @brief create quantity representing @p x inches of distance, with compile-time unit representation **/
/** create quantity representing @p x inches of distance, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto inches(Repr x) { return quantity<u::inch, Repr>(x); }
/** @brief create quantity representing @p x feet of distance, with compile-time unit representation **/
/** create quantity representing @p x feet of distance, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto feet(Repr x) { return quantity<u::foot, Repr>(x); }
/** @brief create quantity representing @p x yards of distance, with compile-time unit representation **/
/** create quantity representing @p x yards of distance, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto yards(Repr x) { return quantity<u::yard, Repr>(x); }
/** @brief create quantity representing @p x statute miles of distance, with compile-time unit representation **/
/** create quantity representing @p x statute miles of distance, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto miles(Repr x) { return quantity<u::mile, Repr>(x); }
}
/** @brief a quantity representing 1 picometer of distance, with compile-time unit representation **/
namespace qty {
// ----- distance constants -----
/** a quantity representing 1 picometer of distance, with compile-time unit representation **/
static constexpr auto picometer = picometers(1);
/** @brief a quantity representing 1 nanometer of distance, with compile-time unit representation **/
/** a quantity representing 1 nanometer of distance, with compile-time unit representation **/
static constexpr auto nanometer = nanometers(1);
/** @brief a quantity representing 1 micrometer of distance, with compile-time unit representation **/
/** a quantity representing 1 micrometer of distance, with compile-time unit representation **/
static constexpr auto micrometer = micrometers(1);
/** @brief a quantity representing 1 millimeter of distance, with compile-time unit representation **/
static constexpr auto millimeter = millimeters(1);
@ -558,52 +639,83 @@ namespace xo {
namespace qty {
// ----- time -----
/** create quantity representing @p x picoseconds of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto picoseconds(Repr x) { return quantity<u::picosecond, Repr>(x); }
/** create quantity representing @p x nanoseconds of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto nanoseconds(Repr x) { return quantity<u::nanosecond, Repr>(x); }
/** create quantity representing @p x microseconds of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto microseconds(Repr x) { return quantity<u::microsecond, Repr>(x); }
/** create quantity representing @p x milliseconds of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto milliseconds(Repr x) { return quantity<u::millisecond, Repr>(x); }
/** @brief create quantity representing @p x seconds of time, with compile-time unit representation **/
/** create quantity representing @p x seconds of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto seconds(Repr x) { return quantity<u::second, Repr>(x); }
/** @brief create quantity representing @p x minutes of time, with compile-time unit representation **/
/** create quantity representing @p x minutes of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto minutes(Repr x) { return quantity<u::minute, Repr>(x); }
/** @brief create quantity representing @p x hours of time, with compile-time unit representation **/
/** create quantity representing @p x hours of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto hours(Repr x) { return quantity<u::hour, Repr>(x); }
/** @brief create quantity representing @p x days of time, with compile-time unit representation **/
/** create quantity representing @p x exactly-24-hour days of time, with compile-time unit operations **/
template <typename Repr>
inline constexpr auto days(Repr x) { return quantity<u::day, Repr>(x); }
/** creeate quantity representing @p x weeks of time,
* with compile-time unit operations. Each week has exactly 7 24-hour days.
**/
template <typename Repr>
inline constexpr auto weeks(Repr x) { return quantity<u::week, Repr>(x); }
/** create quantity representing @p x months of time,
* with compile-time unit operations. Each month has exactly 30 24-hour days
**/
template <typename Repr>
inline constexpr auto months(Repr x) { return quantity<u::month, Repr>(x); }
/** create quantity representing @p x years of time,
* with compile-time unit operations. Each year has exactly 365.25 24-hour days
**/
template <typename Repr>
inline constexpr auto years(Repr x) { return quantity<u::year, Repr>(x); }
/** create quantity representing @p x '250-day years' of time.
* 250 represents approximate number of business days in a calendar year.
**/
template <typename Repr>
inline constexpr auto year250s(Repr x) { return quantity<u::year250, Repr>(x); }
/** create quantity representing @p x '360-day years' of time **/
template <typename Repr>
inline constexpr auto year360s(Repr x) { return quantity<u::year360, Repr>(x); }
/** create quantity representing @p x '365-day years' of time **/
template <typename Repr>
inline constexpr auto year365s(Repr x) { return quantity<u::year365, Repr>(x); }
}
namespace qty {
// ----- time constants ----
/** @brief a quantity representing 1 second of time, with compile-time unit representation **/
static constexpr auto second = seconds(1);
/** @brief a quantity representing 1 minute of time, with compile-time unit representation **/
static constexpr auto minute = minutes(1);
/** @brief a quantity representing 1 hour of time, with compile-time unit representation **/
static constexpr auto hour = hours(1);
/** @brief a quantity representing 1 day of time (exactly 24 hours), with compile-time unit representation **/
static constexpr auto day = days(1);
} /*namespace qty*/
@ -615,12 +727,19 @@ namespace xo {
* volatility ~ sqrt(variance), has dimension 1/sqrt(t)
*/
/** create quantity representing @p x units of 30-day volatility, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto volatility_30d(Repr x) { return quantity<u::volatility_30d, Repr>(x); }
/** create quantity representing @p x units of 250-day volatility, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto volatility_250d(Repr x) { return quantity<u::volatility_250d, Repr>(x); }
/** create quantity representing @p x units of 360-day volatility, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto volatility_360d(Repr x) { return quantity<u::volatility_360d, Repr>(x); }
/** create quantity representing @p x units of 365-day volatility, with compile-time unit representation **/
template <typename Repr>
inline constexpr auto volatility_365d(Repr x) { return quantity<u::volatility_365d, Repr>(x); }
} /*namespace qty*/

View file

@ -15,8 +15,22 @@ namespace xo {
template < typename Int,
typename OuterScale = ratio::ratio<Int> >
struct scaled_unit {
/** @defgroup scaled-unit-type-traits scaled-unit type traits **/
///@{
/** type for representing individual basis-unit scalefactors **/
using ratio_int_type = typename natural_unit<Int>::ratio_int_type;
///@}
public:
/** @defgroup scaled-unit-ctors scaled-unit constructors **/
///@{
/** create scaled unit representing a multiple
* @p outer_scale_factor * @p sqrt(outer_scale_sq)
* of natural unit @p nat_unit
**/
constexpr scaled_unit(const natural_unit<Int> & nat_unit,
OuterScale outer_scale_factor,
double outer_scale_sq)
@ -25,33 +39,72 @@ namespace xo {
outer_scale_sq_{outer_scale_sq}
{}
///@}
/** @defgroup scaled-unit-access-methods scaled-unit access methods **/
///@{
/** always true for scaled_unit **/
constexpr bool is_scaled_unit_type() const { return true; }
/** true iff scaled unit can be faithfully represented by a @ref natural_unit **/
constexpr bool is_natural() const {
return (outer_scale_factor_ == OuterScale(1) && (outer_scale_sq_ == 1.0));
}
/** true if this scaled unit has no dimension **/
constexpr bool is_dimensionless() const { return natural_unit_.is_dimensionless(); }
/** get number of distinct native dimensions present.
* e.g. for unit Newton = 1 kg.m.s^-2, n_bpu would be 3,
* with {mass, distance, time} present.
* Note that this value does not count exponents
**/
constexpr std::size_t n_bpu() const { return natural_unit_.n_bpu(); }
///@}
/** @defgroup scaled-unit-general-methods scaled-unit access methods **/
///@{
/** return reciprocal of this unit. **/
constexpr scaled_unit reciprocal() const {
return scaled_unit(natural_unit_.reciprocal(),
1 / outer_scale_factor_,
1.0 / outer_scale_sq_);
}
/** @brief true iff scaled unit can be faithfully represented by a @ref natural_unit **/
constexpr bool is_natural() const {
return (outer_scale_factor_ == OuterScale(1) && (outer_scale_sq_ == 1.0));
/** get bpu for dimension @p d. if d isn't present, construct bpu with 0 power **/
constexpr bpu<Int> lookup_dim(dimension d) const {
return natural_unit_.lookup_dim(d);
}
constexpr bool is_dimensionless() const { return natural_unit_.is_dimensionless(); }
constexpr std::size_t n_bpu() const { return natural_unit_.n_bpu(); }
/** return @p i'th bpu associated with this unit **/
constexpr bpu<Int> & operator[](std::size_t i) { return natural_unit_[i]; }
/** return @p i'th bpu associated with this unit (const version) **/
constexpr const bpu<Int> & operator[](std::size_t i) const { return natural_unit_[i]; }
public: /* need public members so that a scaled_unit instance can be a non-type template parameter (a structural type) */
///@}
natural_unit<Int> natural_unit_;
public: /* public members so scaled_unit instance can be a non-type template parameter (a structural type) */
/** @defgroup scaled-unit-instance-vars **/
///@{
/** scale factor multiplying @ref natural_unit_ **/
OuterScale outer_scale_factor_;
/** squared scale factor multiplying @ref natural_unit_ **/
double outer_scale_sq_;
/** natural unit term in this scaled unit **/
natural_unit<Int> natural_unit_;
///@}
};
namespace detail {
/** promote natural unit to scaled unit (with unit outer scalefactors) **/
template <typename Int>
constexpr auto su_promote(const natural_unit<Int> & bpuv) {
return scaled_unit<Int>(bpuv,
@ -71,60 +124,154 @@ namespace xo {
su_from_bu(const basis_unit & bu,
const power_ratio_type & power = power_ratio_type(1))
{
return detail::su_promote<std::int64_t>(natural_unit<std::int64_t>::from_bu(bu, power));
return detail::su_promote(natural_unit<std::int64_t>::from_bu(bu, power));
}
/** @defgroup scaled-unit-dimensionless scaled-unit dimensionless constant **/
///@{
/** dimensionless unit; equivalent to 1 **/
constexpr auto dimensionless = detail::su_promote<std::int64_t>(nu::dimensionless);
///@}
// ----- mass units -----
/** @defgroup scaled-unit-mass scaled-unit mass units **/
///@{
/** unit of 10^-12 grams **/
constexpr auto picogram = su_from_bu(detail::bu::picogram);
/** unit of 10^-9 grams **/
constexpr auto nanogram = su_from_bu(detail::bu::nanogram);
/** unit of 10^-6 grams **/
constexpr auto microgram = su_from_bu(detail::bu::microgram);
/** unit of 10^-3 grams **/
constexpr auto milligram = su_from_bu(detail::bu::milligram);
/** unit of 1 gram **/
constexpr auto gram = su_from_bu(detail::bu::gram);
/** unit of 10^3 grams **/
constexpr auto kilogram = su_from_bu(detail::bu::kilogram);
/** unit of 1 metric tonne = 10^3 kg **/
constexpr auto tonne = su_from_bu(detail::bu::tonne);
/** unit of 10^3 tonnes = 10^6 kg **/
constexpr auto kilotonne = su_from_bu(detail::bu::kilotonne);
/** unit of 10^6 tonnes = 10^9 kg **/
constexpr auto megatonne = su_from_bu(detail::bu::megatonne);
/** unit of 10^9 tonnes = 10^12 kg **/
constexpr auto gigatonne = su_from_bu(detail::bu::gigatonne);
///@}
// ----- distance units -----
/** @defgroup scaled-unit-distance scaled-unit distance units **/
///@{
/** unit of 10^-12 meters **/
constexpr auto picometer = su_from_bu(detail::bu::picometer);
/** unit of 10^-9 meters **/
constexpr auto nanometer = su_from_bu(detail::bu::nanometer);
/** unit of 10^-6 meters **/
constexpr auto micrometer = su_from_bu(detail::bu::micrometer);
/** unit of 10^-3 meters **/
constexpr auto millimeter = su_from_bu(detail::bu::millimeter);
/** unit of 1 meter **/
constexpr auto meter = su_from_bu(detail::bu::meter);
/** unit of 10^3 meters **/
constexpr auto kilometer = su_from_bu(detail::bu::kilometer);
/** unit of 10^6 meters (not commonly used) **/
constexpr auto megameter = su_from_bu(detail::bu::megameter);
/** unit of 10^9 meters (not commonly used) **/
constexpr auto gigameter = su_from_bu(detail::bu::gigameter);
/** unit of 1 light-second = distance light travels in a vacuum in 1 second **/
constexpr auto lightsecond = su_from_bu(detail::bu::lightsecond);
/** unit of 1 astronomical unit, for approximate radius of earth orbit **/
constexpr auto astronomicalunit = su_from_bu(detail::bu::astronomicalunit);
/** unit of 1 inch = 1/12 feet **/
constexpr auto inch = su_from_bu(detail::bu::inch);
/** unit of 1 foot = 0.3048 meters **/
constexpr auto foot = su_from_bu(detail::bu::foot);
/** unit of 1 yard = 3 feet **/
constexpr auto yard = su_from_bu(detail::bu::yard);
/** unit of 1 mile = 1760 yards **/
constexpr auto mile = su_from_bu(detail::bu::mile);
///@}
// ----- time units -----
/** @defgroup scaled-unit-time scaled-unit time units **/
///@{
/** unit of 1 picosecond = 10^-12 seconds **/
constexpr auto picosecond = su_from_bu(detail::bu::picosecond);
/** unit of 1 nanosecond = 10^-9 seconds **/
constexpr auto nanosecond = su_from_bu(detail::bu::nanosecond);
/** unit of 1 microseccond = 10^-6 seconds **/
constexpr auto microsecond = su_from_bu(detail::bu::microsecond);
/** unit of 1 millisecond = 10^-3 seconds **/
constexpr auto millisecond = su_from_bu(detail::bu::millisecond);
/** unit of 1 second **/
constexpr auto second = su_from_bu(detail::bu::second);
/** unit of 1 minute **/
constexpr auto minute = su_from_bu(detail::bu::minute);
/** unit of 1 hour **/
constexpr auto hour = su_from_bu(detail::bu::hour);
/** unit for a 24-hour day **/
constexpr auto day = su_from_bu(detail::bu::day);
/** unit for a week comprising exactly 7 24-hour days **/
constexpr auto week = su_from_bu(detail::bu::week);
/** unit for a 30-day month **/
constexpr auto month = su_from_bu(detail::bu::month);
/** unit for a year containing exactly 365.25 24-hour days **/
constexpr auto year = su_from_bu(detail::bu::year);
/** unit for a 'year' containing exactly 250 24-hour days.
* (approximates the number of business days in a year)
**/
constexpr auto year250 = su_from_bu(detail::bu::year250);
/** unit for a 'year' containing exactly 360 24-hour days **/
constexpr auto year360 = su_from_bu(detail::bu::year360);
/** unit for a 'year' containing exactly 365 24-hour days **/
constexpr auto year365 = su_from_bu(detail::bu::year365);
///@}
/** @defgroup scaled-unit-misc scaled-unit miscellaneous units **/
///@{
// ----- currency -----
/** generic currency unit **/
constexpr auto currency = su_from_bu(detail::bu::currency);
// ----- price - ---
/** generic price unit **/
constexpr auto price = su_from_bu(detail::bu::price);
///@}
// ----- volatility units -----
/** @defgroup scaled-unit-volatility scaled-unit volatility units **/
///@{
/** volatility, in 30-day units **/
constexpr auto volatility_30d = su_from_bu(detail::bu::month,
power_ratio_type(-1,2));
/** volatility, in 250-day 'annual' units **/
constexpr auto volatility_250d = su_from_bu(detail::bu::year250,
power_ratio_type(-1,2));
/** volatility, in 360-day 'annual' units **/
constexpr auto volatility_360d = su_from_bu(detail::bu::year360,
power_ratio_type(-1,2));
/** volatility, in 365-day 'annual' units **/
constexpr auto volatility_365d = su_from_bu(detail::bu::year365,
power_ratio_type(-1,2));
///@}
}
namespace detail {
@ -197,6 +344,13 @@ namespace xo {
}
}
/** @defgroup scaled-unit-operators **/
///@{
/** Multiply scaled_unit instances @p x_unit and @p y_unit.
* Result is a scaled_unit for the product dimension.
* For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit.
**/
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
@ -214,30 +368,10 @@ namespace xo {
rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
}
#ifdef OBSOLETE
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
operator* (const scaled_unit<Int> & x_unit,
const natural_unit<Int> & y_unit)
{
auto y_unit2 = detail::make_unit_rescale_result<Int>(y_unit);
return x_unit * y_unit2;
}
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
operator* (const natural_unit<Int> & x_unit,
const scaled_unit<Int> & y_unit)
{
auto x_unit2 = detail::make_unit_rescale_result<Int>(x_unit);
return x_unit2 * y_unit;
}
#endif
/** Divide scaled_unit instances @p x_unit by @p y_unit.
* Result is a scaled_unit for the quotient dimension.
* For each basis dimension, result will prioritize scale from @p x_unit ahead of @p y_unit.
**/
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
@ -255,29 +389,7 @@ namespace xo {
rr.outer_scale_sq_ * x_unit.outer_scale_sq_ * y_unit.outer_scale_sq_));
}
#ifdef OBSOLETE
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
operator/ (const scaled_unit<Int> & x_unit,
const natural_unit<Int> & y_unit)
{
auto y_unit2 = detail::make_unit_rescale_result<Int>(y_unit);
return x_unit / y_unit2;
}
template <typename Int,
typename Int2x = detail::width2x_t<Int>>
inline constexpr scaled_unit<Int>
operator/ (const natural_unit<Int> & x_unit,
const scaled_unit<Int> & y_unit)
{
auto x_unit2 = detail::make_unit_rescale_result<Int>(x_unit);
return x_unit2 / y_unit;
}
#endif
///@}
} /*namespace qty*/
} /*namespace xo*/

View file

@ -48,6 +48,16 @@ namespace xo {
constexpr xquantity(Repr scale,
const natural_unit<Int> & unit)
: scale_{scale}, unit_{unit} {}
constexpr xquantity(Repr scale,
const scaled_unit<Int> & unit)
:
scale_(scale
* unit.outer_scale_factor_.template convert_to<double>()
* ((unit.outer_scale_sq_ == 1.0)
? 1.0
: ::sqrt(unit.outer_scale_sq_))
),
unit_{unit.natural_unit_} {}
static constexpr bool always_constexpr_unit = false;