/** @file quantity.hpp * * Author: Roland Conybeare **/ #pragma once #include "quantity_ops.hpp" #include "natural_unit.hpp" #include "scaled_unit.hpp" #include "scaled_unit_concept.hpp" namespace xo { namespace qty { /** @class quantity * * @brief represent a scalar quantity with associated units. * * @tparam ScaledUnit 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 * @tparam Repr is a type used to represent a multiple * of @p ScaledUnit. * * Enforce dimensional consistency at compile time. * sizeof(quantity) == sizeof(Repr). * * Unit information is associated with type, not value. * A quantity's runtime state consists of exactly one @p Repr instance: * @code * sizeof(quantity) == sizeof(Repr) * @endcode **/ template < auto ScaledUnit, typename Repr = double> requires (ScaledUnit.is_natural() && ScaledUnit.is_scaled_unit_type()) class quantity { public: /** @defgroup quantity-type-traits quantity type traits **/ ///@{ /** @brief runtime representation for value of this type **/ using repr_type = Repr; /** @brief type used to represent unit information */ using unit_type = decltype(ScaledUnit); /** @brief type used for numerator and denominator in basis-unit scalefactor ratios */ using ratio_int_type = unit_type::ratio_int_type; /** @brief double-width type used for numerator and denominator of intermediate * scalefactor ratios. Used to mitigate loss of precision during computation * of conversion factors between units with widely-differing magnitude **/ using ratio_int2x_type = detail::width2x_t; ///@} public: /** @defgroup quantity-ctors quantity constructors**/ ///@{ /** @brief create a zero amount with dimension @c ScaledUnit **/ constexpr quantity() : scale_{0} {} /** @brief create a quantity representing @p scale @c ScaledUnits **/ explicit constexpr quantity(Repr scale) : scale_{scale} {} /** @brief copy constructor **/ constexpr quantity(const quantity &) = default; ///@} /** @defgroup quantity-constants static quantity constants **/ ///@{ /** @brief Use to distinguish @ref quantity from xquantity instances. * * Useful in c++ template resolution. **/ static constexpr bool always_constexpr_unit = true; ///@} /** @defgroup quantity-access-methods quantity access methods **/ ///@{ /** @brief value of @c scale_ in quantity representing amount (@c scale_ * @c s_unit) **/ constexpr const repr_type & scale() const { return scale_; } /** @brief s_unit in quantity representing amount (@c scale_ * @c s_unit) **/ constexpr const unit_type & unit() const { return s_scaled_unit; } /** @brief true iff this quantity is strictly negative **/ constexpr bool is_negative() const { return scale_ < Repr{0}; } /** @brief true iff this quantity is strictly positive **/ constexpr bool is_positive() const { return scale_ > Repr{0}; } /** @brief true iff this quantity represents a dimensionless value **/ static constexpr bool is_dimensionless() { return s_scaled_unit.is_dimensionless(); } /** abbreviated suffix for quantities with this unit **/ constexpr nu_abbrev_type abbrev() const { return s_scaled_unit.natural_unit_.abbrev(); } ///@} /** @defgroup quantity-arithmetic-support **/ ///@{ /** create unit quantity with same unit as @c this **/ constexpr auto unit_qty() const { return quantity(1); } /** create zero quantity with same unit as @c this **/ constexpr auto zero_qty() const { return quantity(0); } constexpr auto reciprocal() const { return quantity(1.0 / scale_); } ///@} /** @defgroup quantity-unit-conversion **/ ///@{ /** create equivalent quantity using scale representation @p Repr2 instead of @c Repr **/ template constexpr auto with_repr() const { return quantity(scale_); } /** create equivalent quantity expressed as a multiple of @p NaturalUnit2 * instead of @ref s_unit **/ template NaturalUnit2> constexpr auto rescale() const { /* conversion factor from .unit -> unit2*/ auto rr = detail::su_ratio(s_scaled_unit.natural_unit_, NaturalUnit2); if (rr.natural_unit_.is_dimensionless()) { repr_type r_scale = (((rr.outer_scale_sq_ == 1.0) ? 1.0 : ::sqrt(rr.outer_scale_sq_)) * rr.outer_scale_factor_.template convert_to() * this->scale_); return quantity(r_scale); } else { return quantity(std::numeric_limits::quiet_NaN()); } } /** create equivalent quantity expressed as as multiple of @p ScaledUnit2 * instead of @ref s_unit **/ template ScaledUnit2> constexpr auto rescale_ext() const { /* conversion factor from .unit -> unit2*/ auto rr = detail::su_ratio(s_scaled_unit.natural_unit_, ScaledUnit2.natural_unit_); if (rr.natural_unit_.is_dimensionless()) { /* NOTE: test for unit .outer_scale_sq values to get constexpr result with c++23 * and integer dimension powers. * * NOTE: we don't intend to support mixed-unit quantities. * If we change intention, will need to take into account * (s_scaled_unit.outer_scale_factor_, s_scaled_unit.outer_scale_sq_) */ repr_type r_scale = ((((rr.outer_scale_sq_ == 1.0) && (ScaledUnit2.outer_scale_sq_ == 1.0)) ? 1.0 : ::sqrt(rr.outer_scale_sq_ / ScaledUnit2.outer_scale_sq_)) * rr.outer_scale_factor_.template convert_to() * this->scale_ / ScaledUnit2.outer_scale_factor_.template convert_to()); return quantity(r_scale); } else { return quantity(std::numeric_limits::quiet_NaN()); } } ///@} /** @addtogroup quantity-arithmetic-support **/ ///@{ /** 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 requires std::is_arithmetic_v constexpr auto scale_by(Dimensionless x) const { using r_repr_type = std::common_type_t; return quantity(x * this->scale_); } /** create quantity representing this quantity divided by dimensionless value @p x * * @pre x must be an arithmetic type such as @c int or @c double **/ template requires std::is_arithmetic_v constexpr auto divide_by(Dimensionless x) const { using r_repr_type = std::common_type_t; return quantity(this->scale_ / x); } /** create quantity representing dimensionless value @p x divided by this quantity * * @pre x must be an arithmetic type such as @c int or @c double **/ template requires std::is_arithmetic_v constexpr auto divide_into(Dimensionless x) const { using r_repr_type = std::common_type_t; return quantity (static_cast(x) / this->scale_); } ///@} /** @defgroup quantity-comparison-support **/ ///@{ /** compare two @c quantity instances, under three-way comparison **/ template static constexpr auto compare(const quantity &x, const Quantity2 & y) { quantity y2 = y.template rescale_ext(); return x.scale() <=> y2.scale(); } ///@} /** @defgroup quantity-operators **/ ///@{ /** unary negation; preserves unit information **/ quantity operator-() const { return quantity(-scale_); } /** add @p y in-place, converting units if necessary **/ template constexpr quantity & operator+=(const Quantity2 & y) { quantity y2 = y.template rescale_ext(); this->scale_ += y2.scale(); return *this; } /** subtract @p y in-place, converting units if necessary **/ template constexpr quantity & operator-=(const Quantity2 & y) { quantity y2 = y.template rescale_ext(); this->scale_ -= y2.scale(); return *this; } /** multiply @p y in-place. y must be dimensionless **/ template requires std::is_arithmetic_v constexpr quantity & operator*=(Dimensionless y) { this->scale_ *= y; return *this; } /** divide @p y in-place. y must be dimensionless **/ template requires std::is_arithmetic_v constexpr quantity & operator/=(Dimensionless y) { this->scale_ /= y; return *this; } ///@} /** @defgroup quantity-assignment quantity assignment operators **/ ///@{ /** assignment from quantity with identical units **/ constexpr quantity & operator=(const quantity & x) { this->scale_ = x.scale_; return *this; } /** assignment from quantity with compatible units **/ template requires(quantity_concept && Q2::always_constexpr_unit) constexpr quantity & operator=(const Q2 & x) { auto x2 = x.template rescale_ext(); this->scale_ = x2.scale(); return *this; } ///@} /** @defgroup quantity-unit-conversion **/ ///@{ /** */ template requires(quantity_concept && Q2::always_constexpr_unit) constexpr operator Q2() const { return this->template rescale_ext().template with_repr(); } /** 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 s_scaled_unit = ScaledUnit; ///@} /** @defgroup quantity-instance-vars **/ ///@{ /** 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 constexpr auto rescale(const Quantity & x, const scaled_unit & su) { return x.template rescale(); } ///@} namespace detail { struct quantity_util { /* parallel implementation to xquantity multiply, * but return type will have dimension computed at compile-time */ template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) static constexpr auto multiply(Q1 x, Q2 y) { using r_repr_type = std::common_type_t; using r_int_type = std::common_type_t; using r_int2x_type = std::common_type_t; constexpr auto rr = detail::su_product(x.unit().natural_unit_, y.unit().natural_unit_); r_repr_type r_scale = (((rr.outer_scale_sq_ == 1.0) ? 1.0 : ::sqrt(rr.outer_scale_sq_)) * rr.outer_scale_factor_.template convert_to() * static_cast(x.scale()) * static_cast(y.scale())); return quantity(rr.natural_unit_), r_repr_type>(r_scale); } template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) static constexpr auto divide(Q1 x, Q2 y) { using r_repr_type = std::common_type_t; using r_int_type = std::common_type_t; using r_int2x_type = std::common_type_t; constexpr auto rr = detail::su_ratio(x.unit().natural_unit_, y.unit().natural_unit_); r_repr_type r_scale = (((rr.outer_scale_sq_ == 1.0) ? 1.0 : ::sqrt(rr.outer_scale_sq_)) * rr.outer_scale_factor_.template convert_to() * static_cast(x.scale()) / static_cast(y.scale())); return quantity(rr.natural_unit_), r_repr_type>(r_scale); } template requires(quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) static constexpr auto add(Q1 x, Q2 y) { using r_repr_type = std::common_type_t; using r_int_type = std::common_type_t; using r_int2x_type = std::common_type_t; /* conversion to get y in same units as x: multiply by y/x */ auto rr = detail::su_ratio(y.unit().natural_unit_, x.unit().natural_unit_); if (rr.natural_unit_.is_dimensionless()) { r_repr_type r_scale = (static_cast(x.scale()) + (::sqrt(rr.outer_scale_sq_) * rr.outer_scale_factor_.template convert_to() * static_cast(y.scale()))); return quantity(r_scale); } else { /* units don't match! */ return quantity(std::numeric_limits::quiet_NaN()); } } template requires(quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) static constexpr auto subtract(Q1 x, Q2 y) { using r_repr_type = std::common_type_t; using r_int_type = std::common_type_t; using r_int2x_type = std::common_type_t; /* conversion to get y in same units as x: multiply by y/x */ auto rr = detail::su_ratio(y.unit(), x.unit()); if (rr.natural_unit_.is_dimensionless()) { r_repr_type r_scale = (static_cast(x.scale()) - (::sqrt(rr.outer_scale_sq_) * rr.outer_scale_factor_.template convert_to() * static_cast(y.scale()))); return quantity(r_scale); } else { /* units don't match! */ return quantity(std::numeric_limits::quiet_NaN()); } } }; } /*namespace detail*/ template requires(quantity_concept && Q1::always_constexpr_unit) constexpr auto with_units(const Q1 & x) { return x.template rescale_ext(); } template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) constexpr auto with_units_from(const Q1 & x, const Q2 & /*y*/) { return x.template rescale_ext(); } template requires (quantity_concept && Q1::always_constexpr_unit) constexpr auto with_repr(const Q1 & x) { return x.template with_repr(); } /** @addtogroup quantity-operators **/ ///@{ /** note: won't have constexpr result w/ fractional dimension until c++26 (when @c sqrt(), @c pow() are constexpr) **/ template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) constexpr auto operator* (const Q1 & x, const Q2 & y) { return detail::quantity_util::multiply(x, y); } /** note: does not require unit scaling, so constexpr with c++23 **/ template requires std::is_arithmetic_v && quantity_concept constexpr auto operator* (const Quantity & x, Dimensionless y) { return x.scale_by(y); } /** note: does not require unit scaling, so constexpr with c++23 **/ template requires std::is_arithmetic_v && quantity_concept constexpr auto operator* (Dimensionless x, const Quantity & y) { return y.scale_by(x); } /** divide quantity @p x by quantity @p y. * * note: won't have constexpr result w/ fractional dimension until c++26 (when @c sqrt(), @c pow() are constexpr) **/ template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) constexpr auto operator/ (const Q1 & x, const Q2 & y) { return detail::quantity_util::divide(x, y); } /** divide quantity @p x by dimensionless value @p y **/ template requires std::is_arithmetic_v && quantity_concept constexpr auto operator/ (const Quantity & x, Dimensionless y) { return x.divide_by(y); } /** divide dimensionless value @p x by quantity @p y **/ template requires std::is_arithmetic_v && quantity_concept constexpr auto operator/ (Dimensionless x, const Quantity & y) { return y.divide_into(x); } /** add quantity @p y to quantity @p x. Result will have the same units as @p x. * Representation will be the widest of {@c x::repr_type, @c y::repr_type}. * * note: won't have constexpr result w/ fractional dimension until c++26 (when @c sqrt(), @c pow() are constexpr) * * @pre @p x and @p y expected to have consistent dimensions **/ template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) constexpr auto operator+ (const Q1 & x, const Q2 & y) { return detail::quantity_util::add(x, y); } /** subtract an arithmetic value from a dimensionless quantity **/ template requires (quantity_concept && Quantity::is_dimensionless() && std::is_arithmetic_v) constexpr auto operator+ (const Quantity & x, Dimensionless y) { using repr_type = std::common_type_t; auto xp = static_cast(x.scale()); auto yp = static_cast(y); return xp + yp; } /** subtract a dimensionless quantity from an arithmetic value **/ template requires (std::is_arithmetic_v && quantity_concept && Quantity::is_dimensionless()) constexpr auto operator+ (Dimensionless x, const Quantity & y) { using repr_type = std::common_type_t; auto xp = static_cast(x); auto yp = static_cast(y.scale()); return xp + yp; } /** subtract quantity @p y from quantity @p x. Result will have the same units as @p x. * Representation will be the widest of {@c x::repr_type, @c y::repr_type} * * note: won't have constexpr result w/ fractional dimension until c++26 (when @c sqrt(), @c pow() are constexpr) * * @pre @p x and @p y expected to have consistent dimensions **/ template requires (quantity_concept && quantity_concept && Q1::always_constexpr_unit && Q2::always_constexpr_unit) constexpr auto operator- (const Q1 & x, const Q2 & y) { return detail::quantity_util::subtract(x, y); } /** subtract an arithmetic value from a dimensionless quantity **/ template requires (quantity_concept && Quantity::is_dimensionless() && std::is_arithmetic_v) constexpr auto operator- (const Quantity & x, Dimensionless y) { using repr_type = std::common_type_t; auto xp = static_cast(x.scale()); auto yp = static_cast(y); return xp - yp; } /** subtract a dimensionless quantity from an arithmetic value **/ template requires (std::is_arithmetic_v && quantity_concept && Quantity::is_dimensionless()) constexpr auto operator- (Dimensionless x, const Quantity & y) { using repr_type = std::common_type_t; auto xp = static_cast(x); auto yp = static_cast(y.scale()); return xp - yp; } ///@} namespace qty { // ----- mass ----- /** create quantity representing @p x picograms of mass, with compile-time unit representation **/ template inline constexpr auto picograms(Repr x) { return quantity(x); } /** create quantity representing @p x nanograms of mass, with compile-time unit representation **/ template inline constexpr auto nanograms(Repr x) { return quantity(x); } /** create quantity representing @p x micrograms of mass, with compile-time unit representation **/ template inline constexpr auto micrograms(Repr x) { return quantity(x); } /** create quantity representing @p x milligrams of mass, with compile-time unit representation **/ template inline constexpr auto milligrams(Repr x) { return quantity(x); } /** create quantity representing @p x grams of mass, with compile-time unit representation **/ template inline constexpr auto grams(Repr x) { return quantity(x); } /** create quantity representing @p x kilograms of mass, with compile-time unit representation **/ template inline constexpr auto kilograms(Repr x) { return quantity(x); } /** create quantity representing @p x tonnes of mass, with compile-time unit representation **/ template inline constexpr auto tonnes(Repr x) { return quantity(x); } /** create quantity representing @p x kilotonnes of mass, with compile-time unit representation **/ template inline constexpr auto kilotonnes(Repr x) { return quantity(x); } /** create quantity representing @p x megatonnes of mass, with compile-time unit representation **/ template inline constexpr auto megatonnes(Repr x) { return quantity(x); } /** create quantity representing @p x gigatonnes of mass, with compile-time unit representation **/ template inline constexpr auto gigatonnes(Repr x) { return quantity(x); } } namespace qty { // ----- mass constants ---- /** a quantity representing 1 picogram of mass, with compile-time unit representation **/ static constexpr auto picogram = picograms(1); /** a quantity representing 1 nanogram of mass, with compile-time unit representation **/ static constexpr auto nanogram = nanograms(1); /** a quantity representing 1 microgram of mass, with compile-time unit representation **/ static constexpr auto microgram = micrograms(1); /** a quantity representing 1 milligram of mass, with compile-time unit representation **/ static constexpr auto milligram = milligrams(1); /** a quantity representing 1 gram of mass, with compile-time unit representation **/ static constexpr auto gram = grams(1); /** a quantity representing 1 kilogram of mass, with compile-time unit representation **/ static constexpr auto kilogram = kilograms(1); /** a quantity representing 1 metric tonne of mass, with compile-time unit representation **/ static constexpr auto tonne = tonnes(1); /** a quantity representing 1 metric kilotonne of mass, with compile-time unit representation **/ static constexpr auto kilotonne = kilotonnes(1); /** a quantity representing 1 metric megatonne of mass, with compile-time unit representation **/ static constexpr auto megatonne = megatonnes(1); /** a quantity representing 1 metric gigatonne of mass, with compile-time unit representation **/ static constexpr auto gigatonne = gigatonnes(1); } /*namespace qty*/ namespace qty { // ----- distance ----- /** create quantity representing @p x picometers of distance, with compile-time unit operations **/ template inline constexpr auto picometers(Repr x) { return quantity(x); } /** create quantity representing @p x nanometers of distance, with compile-time unit operations **/ template inline constexpr auto nanometers(Repr x) { return quantity(x); } /** create quantity representing @p x micrometers of distance, with compile-time unit operations **/ template inline constexpr auto micrometers(Repr x) { return quantity(x); } /** create quantity representing @p x millimeters of distance, with compile-time unit operations **/ template inline constexpr auto millimeters(Repr x) { return quantity(x); } /** create quantity representing @p x meters of distance, with compile-time unit operations **/ template inline constexpr auto meters(Repr x) { return quantity(x); } /** create quantity representing @p x kilometers of distance, with compile-time unit operations **/ template inline constexpr auto kilometers(Repr x) { return quantity(x); } /** create quantity representing @p x megameters of distance, with compile-time unit operations **/ template inline constexpr auto megameters(Repr x) { return quantity(x); } /** create quantity representing @p x gigameters of distance, * with compile-time unit operations **/ template inline constexpr auto gigameters(Repr x) { return quantity(x); } /** create quantity representing @p x light-seconds of distance, * with compile-time unit operations. **/ template inline constexpr auto lightseconds(Repr x) { return quantity(x); } /** create quantity representing @p x astronomical units of distance, * with compile-time unit representation **/ template inline constexpr auto astronomicalunits(Repr x) { return quantity(x); } /** create quantity representing @p x inches of distance, with compile-time unit representation **/ template inline constexpr auto inches(Repr x) { return quantity(x); } /** create quantity representing @p x feet of distance, with compile-time unit representation **/ template inline constexpr auto feet(Repr x) { return quantity(x); } /** create quantity representing @p x yards of distance, with compile-time unit representation **/ template inline constexpr auto yards(Repr x) { return quantity(x); } /** create quantity representing @p x statute miles of distance, with compile-time unit representation **/ template inline constexpr auto miles(Repr x) { return quantity(x); } } namespace qty { // ----- distance constants ----- /** a quantity representing 1 picometer of distance, with compile-time unit representation **/ static constexpr auto picometer = picometers(1); /** a quantity representing 1 nanometer of distance, with compile-time unit representation **/ static constexpr auto nanometer = nanometers(1); /** a quantity representing 1 micrometer of distance, with compile-time unit representation **/ static constexpr auto micrometer = micrometers(1); /** a quantity representing 1 millimeter of distance, with compile-time unit representation **/ static constexpr auto millimeter = millimeters(1); /** a quantity representing 1 meter of distance, with compile-time unit representation **/ static constexpr auto meter = meters(1); /** a quantity representing 1 kilometer of distance, with compile-time unit representation **/ static constexpr auto kilometer = kilometers(1); /** a quantity representing 1 megameter of distance, with compile-time unit representation **/ static constexpr auto megameter = megameters(1); /** a quantity representing 1 gigameter of distance, with compile-time unit representation **/ static constexpr auto gigameter = gigameters(1); /** a quantity representing exactly 1 lightsecond of distance, * with compile-time unit representation **/ static constexpr auto lightsecond = lightseconds(1); /** a quantity representing exactly 1 astronomical unit of distance, * with compile-time unit representation **/ static constexpr auto astronomicalunit = astronomicalunits(1); /** a quantity representing 1 inch of distance, with compile-time unit operations **/ static constexpr auto inch = inches(1); /** a quantity representing 1 foot of distance, with compile-time unit operations **/ static constexpr auto foot = feet(1); /** a quantity representing 1 yard of distance, with compile-time unit operations **/ static constexpr auto yard = yards(1); /** a quantity representing 1 mile of distance, with compile-time unit operations **/ static constexpr auto mile = miles(1); } /*namespace qty*/ namespace qty { // ----- time ----- /** create quantity representing @p x picoseconds of time, with compile-time unit operations **/ template inline constexpr auto picoseconds(Repr x) { return quantity(x); } /** create quantity representing @p x nanoseconds of time, with compile-time unit operations **/ template inline constexpr auto nanoseconds(Repr x) { return quantity(x); } /** create quantity representing @p x microseconds of time, with compile-time unit operations **/ template inline constexpr auto microseconds(Repr x) { return quantity(x); } /** create quantity representing @p x milliseconds of time, with compile-time unit operations **/ template inline constexpr auto milliseconds(Repr x) { return quantity(x); } /** create quantity representing @p x seconds of time, with compile-time unit operations **/ template inline constexpr auto seconds(Repr x) { return quantity(x); } /** create quantity representing @p x minutes of time, with compile-time unit operations **/ template inline constexpr auto minutes(Repr x) { return quantity(x); } /** create quantity representing @p x hours of time, with compile-time unit operations **/ template inline constexpr auto hours(Repr x) { return quantity(x); } /** create quantity representing @p x exactly-24-hour days of time, with compile-time unit operations **/ template inline constexpr auto days(Repr x) { return quantity(x); } /** creeate quantity representing @p x weeks of time, * with compile-time unit operations. Each week has exactly 7 24-hour days. **/ template inline constexpr auto weeks(Repr x) { return quantity(x); } /** create quantity representing @p x months of time, * with compile-time unit operations. Each month has exactly 30 24-hour days **/ template inline constexpr auto months(Repr x) { return quantity(x); } /** create quantity representing @p x years of time, * with compile-time unit operations. Each year has exactly 365.25 24-hour days **/ template inline constexpr auto years(Repr x) { return quantity(x); } /** create quantity representing @p x '250-day years' of time. * 250 represents approximate number of business days in a calendar year. **/ template inline constexpr auto year250s(Repr x) { return quantity(x); } /** create quantity representing @p x '360-day years' of time **/ template inline constexpr auto year360s(Repr x) { return quantity(x); } /** create quantity representing @p x '365-day years' of time **/ template inline constexpr auto year365s(Repr x) { return quantity(x); } } namespace qty { // ----- time constants ---- /** a quantity representing 1 picosecond of time, with compile-time unit representation **/ static constexpr auto picosecond = picoseconds(1L); /** a quantity representing 1 nanosecond of time, with compile-time unit representation **/ static constexpr auto nanosecond = nanoseconds(1L); /** a quantity representing 1 microsecond of time, with compile-time unit representation **/ static constexpr auto microsecond = microseconds(1L); /** a quantity representing 1 millisecond of time, with compile-time unit representation **/ static constexpr auto millisecond = milliseconds(1L); /** a quantity representing 1 second of time, with compile-time unit representation **/ static constexpr auto second = seconds(1L); /** a quantity representing 1 minute of time, with compile-time unit representation **/ static constexpr auto minute = minutes(1L); /** a quantity representing 1 hour of time, with compile-time unit representation **/ static constexpr auto hour = hours(1L); /** a quantity representing 1 day of time (exactly 24 hours), with compile-time unit representation **/ static constexpr auto day = days(1L); /** a quantity representing 1 week of time (7 24-hour days), with compile-time unit representation **/ static constexpr auto week = weeks(1L); /** a quantity representing 1 month of time (30 24-hour days), with compile-time unit representation **/ static constexpr auto month = months(1L); /** a quantity representing 1 year of time (365.25 24-hour days), with compile-time unit representation **/ static constexpr auto year = years(1L); /** a quantity representing 1 250-day year of time, with compile-time unit representation **/ static constexpr auto year250 = year250s(1L); /** a quantity representing 1 360-day year of time, with compile-time unit representation **/ static constexpr auto year360 = year360s(1L); /** a quantity representing 1 365-day year of time, with compile-time unit representation **/ static constexpr auto year365 = year365s(1L); } /*namespace qty*/ namespace type { template using picoseconds = quantity; template using nanoseconds = quantity; template using microseconds = quantity; template using milliseconds = quantity; template using seconds = quantity; template using minutes = quantity; template using hours = quantity; template using days = quantity; template using weeks = quantity; template using months = quantity; template using years = quantity; template using years250 = quantity; template using years360 = quantity; template using years365 = quantity; } /*namespace type*/ namespace qty { // ----- currency ----- /** create quantity representing @p x units of currency, with compile-time unit representation **/ template inline constexpr auto currency(Repr x) { return quantity(x); } } namespace qty { // ----- volatility ----- /* variance expressed has dimension 1/t; * volatility ~ sqrt(variance), has dimension 1/sqrt(t) */ /** create quantity representing @p x units of 30-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_30d(Repr x) { return quantity(x); } /** create quantity representing @p x units of 250-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_250d(Repr x) { return quantity(x); } /** create quantity representing @p x units of 360-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_360d(Repr x) { return quantity(x); } /** create quantity representing @p x units of 365-day volatility, with compile-time unit representation **/ template inline constexpr auto volatility_365d(Repr x) { return quantity(x); } } /*namespace qty*/ /* reminder: see [quantity_ops.hpp] for operator* etc */ } /*namespace qty*/ } /*namespace xo*/ /** end quantity.hpp **/