diff --git a/docs/api_reference/src/quantities.tex b/docs/api_reference/src/quantities.tex index f02db94638..8a52b66cbe 100644 --- a/docs/api_reference/src/quantities.tex +++ b/docs/api_reference/src/quantities.tex @@ -445,6 +445,12 @@ consteval @\libconcept{Reference}@ auto get_common_reference(R1 r1, R2 r2, Rest... rest) requires @\seebelownc@; +// \ref{qty.ref.math}, math + +template<@\libconcept{Representation}@ Rep, @\libconcept{Reference}@ R> + requires requires { std::numeric_limits::epsilon(); } +constexpr quantity epsilon(R r) noexcept; // hosted + // \ref{qty.rep}, representation enum class @\libglobal{quantity_character}@ { scalar, complex, vector, tensor }; @@ -550,6 +556,86 @@ requires @\seebelownc@ constexpr @\libconcept{Quantity}@ auto quantity_cast(@\seebelownc@ q); +// \ref{qty.math}, math + +template + requires @\seebelownc@ +constexpr quantity abs(const quantity& q) noexcept; + +template + requires @\seebelownc@ +constexpr quantity(R), Rep> pow(const quantity& q) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr quantity sqrt(const quantity& q) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr quantity cbrt(const quantity& q) noexcept; // hosted + +template<@\libconcept{ReferenceOf}@ auto R, typename Rep> + requires @\seebelownc@ +constexpr quantity exp(const quantity& q); // hosted + +template + requires @\seebelownc@ +constexpr bool isfinite(const quantity& a) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr bool isinf(const quantity& a) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr bool isnan(const quantity& a) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr @\seebelownc@ fma(const quantity& a, const quantity& x, // hosted + const quantity& b) noexcept; + +template + requires @\seebelownc@ +constexpr @\libconcept{QuantityOf}@ auto fmod(const quantity& x, // hosted + const quantity& y) noexcept; + +template + requires @\seebelownc@ +constexpr @\libconcept{QuantityOf}@ auto remainder(const quantity& x, // hosted + const quantity& y) noexcept; + +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> floor( // hosted + const quantity& q) noexcept + requires @\seebelownc@; + +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> ceil( // hosted + const quantity& q) noexcept + requires @\seebelownc@; + +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> round( // hosted + const quantity& q) noexcept + requires @\seebelownc@; + +template +constexpr @\libconcept{QuantityOf}@ auto inverse( // hosted + const quantity& q) + requires @\seebelownc@; + +template + requires @\seebelownc@ +constexpr @\libconcept{QuantityOf}@ auto hypot( // hosted + const quantity& x, const quantity& y) noexcept; + +template + requires @\seebelownc@ +constexpr @\libconcept{QuantityOf}@ auto hypot( // hosted + const quantity& x, const quantity& y, + const quantity& z) noexcept; + } // \ref{qty.common.type}, \tcode{std::common_type} specializations @@ -568,6 +654,103 @@ namespace mp_units { +// \ref{qty.rand}, random + +// \ref{qty.rand.uni.int}, class template \tcode{uniform_int_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct uniform_int_distribution; // hosted + +// \ref{qty.rand.uni.real}, class template \tcode{uniform_real_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct uniform_real_distribution; // hosted + +// \ref{qty.rand.bern.bin}, class template \tcode{binomial_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct binomial_distribution; // hosted + +// \ref{qty.rand.bern.negbin}, class template \tcode{negative_binomial_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct negative_binomial_distribution; // hosted + +// \ref{qty.rand.bern.geo}, class template \tcode{geometric_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct geometric_distribution; // hosted + +// \ref{qty.rand.pois.poisson}, class template \tcode{poisson_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct poisson_distribution; // hosted + +// \ref{qty.rand.pois.exp}, class template \tcode{exponential_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct exponential_distribution; // hosted + +// \ref{qty.rand.pois.gamma}, class template \tcode{gamma_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct gamma_distribution; // hosted + +// \ref{qty.rand.pois.weibull}, class template \tcode{weibull_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct weibull_distribution; // hosted + +// \ref{qty.rand.pois.extreme}, class template \tcode{extreme_value_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct extreme_value_distribution; // hosted + +// \ref{qty.rand.norm.normal}, class template \tcode{normal_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct normal_distribution; // hosted + +// \ref{qty.rand.norm.lognormal}, class template \tcode{lognormal_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct lognormal_distribution; // hosted + +// \ref{qty.rand.norm.chisq}, class template \tcode{chi_squared_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct chi_squared_distribution; // hosted + +// \ref{qty.rand.norm.cauchy}, class template \tcode{cauchy_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct cauchy_distribution; // hosted + +// \ref{qty.rand.norm.f}, class template \tcode{fisher_f_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct fisher_f_distribution; // hosted + +// \ref{qty.rand.norm.t}, class template \tcode{student_t_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct student_t_distribution; // hosted + +// \ref{qty.rand.samp.discrite}, class template \tcode{discrete_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct discrete_distribution; // hosted + +// \ref{qty.rand.samp.pconst}, class template \tcode{piecewise_constant_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +class piecewise_constant_distribution; // hosted + +// \ref{qty.rand.samp.plinear}, class template \tcode{piecewise_linear_distribution} +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +class piecewise_linear_distribution; // hosted + // \ref{qty.pt}, quantity point // \ref{qty.pt.orig}, point origin @@ -663,6 +846,25 @@ requires @\seebelownc@ constexpr @\libconcept{QuantityPoint}@ auto quantity_cast(@\seebelownc@ qp); +// \ref{qty.pt.math}, math + +template + requires requires(quantity q) { isfinite(q); } +constexpr bool isfinite(const quantity_point& a) noexcept; // hosted + +template + requires requires(quantity q) { isinf(q); } +constexpr bool isinf(const quantity_point& a) noexcept; // hosted + +template + requires requires(quantity q) { isnan(q); } +constexpr bool isnan(const quantity_point& a) noexcept; // hosted + +template + requires @\seebelownc@ +constexpr @\seebelownc@ fma(const quantity& a, const quantity& x, // hosted + const quantity_point& b) noexcept; + } \end{codeblock} @@ -1526,6 +1728,128 @@ \rSec3[qty.dim.sym.fmt]{Symbol formatting} +\begin{itemdecl} +template +constexpr auto @\exposidnc{get-symbol-exponent}@(const fixed_string& sign, @\exposidnc{ratio}@ r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\exposidnc{num-to-txt}(x)} be an expression equal to +an instantiation of \tcode{symbo_text} with the symbol text of \tcode{x} in base 10. + +\pnum +\effects +Determines \tcode{txt} as follows: +\begin{itemize} +\item +If \tcode{r.den != 1} is \tcode{true}, let \tcode{txt} be +\begin{codeblock} +symbol_text("^") + symbol_text(sign) + symbol_text("(") + @\exposidnc{num-to-txt}@(r.num) + + symbol_text("/") + @\exposidnc{num-to-txt}@(r.den) + symbol_text(")") +\end{codeblock} +\item +Otherwise, let \tcode{txt} be an instantiation of \tcode{symbol_text} such that: +\begin{itemize} +\item +\tcode{txt.portable()} equals +\begin{codeblock} +"^" + sign + @\exposidnc{num-to-txt}@(Num).portable() +\end{codeblock} +\item +\tcode{txt.utf8()} equals \tcode{txt.portable()} after replacing its elements according to \tref{qty.exp.portable.to.utf8}. +\end{itemize} +\end{itemize} + +\pnum +\returns +\tcode{txt}. + +\begin{simpletypetable} +{UTF-8 exponent transformation} +{qty.exp.portable.to.utf8} +{lr} +\topline +\lhdr{Input value} & \rhdr{Replacement value} \\ \capsep +\tcode{'\caret'} & None (erased) \\ +\tcode{'-'} & \unicode{207b}{SUPERSCRIPT MINUS} \\ +\tcode{'0'} & \unicode{2070}{SUPERSCRIPT ZERO} \\ +\tcode{'1'} & \unicode{00b9}{SUPERSCRIPT ONE} \\ +\tcode{'2'} & \unicode{00b2}{SUPERSCRIPT TWO} \\ +\tcode{'3'} & \unicode{00b3}{SUPERSCRIPT THREE} \\ +\tcode{'4'} & \unicode{2074}{SUPERSCRIPT FOUR} \\ +\tcode{'5'} & \unicode{2075}{SUPERSCRIPT FIVE} \\ +\tcode{'6'} & \unicode{2076}{SUPERSCRIPT SIX} \\ +\tcode{'7'} & \unicode{2077}{SUPERSCRIPT SEVEN} \\ +\tcode{'8'} & \unicode{2078}{SUPERSCRIPT EIGHT} \\ +\tcode{'9'} & \unicode{2079}{SUPERSCRIPT NINE} \\ +\end{simpletypetable} +\end{itemdescr} + +\begin{itemdecl} +template Out> +constexpr Out @\exposidnc{copy-symbol-text}@(const symbol_text& txt, // \expos + character_set char_set, Out out); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Copies \tcode{txt} to \tcode{out} according to \tcode{char_set} as follows: +\begin{itemize} +\item +If \tcode{char_set == character_set::utf8} is \tcode{true}, then: +\begin{itemize} +\item +If \tcode{std::is_same_v} is \tcode{true}, equivalent to: +\begin{codeblock} +out = std::ranges::copy(txt.utf8(), out) +\end{codeblock} +\item +Otherwise, if \tcode{std::is_same_v} is \tcode{true}, then: +\begin{itemize} +\item +If +\begin{codeblock} +std::text_encoding::literal().mib() != std::text_encoding::id::UTF8 +\end{codeblock} +is \tcode{true}, equivalent to: +\begin{codeblock} +out = std::ranges::copy(txt.portable(), out) +\end{codeblock} +\item +Otherwise, equivalent to: +\begin{codeblock} +for (const char8_t ch : txt.utf8()) *out++ = static_cast(ch); +\end{codeblock} +\end{itemize} +\item +Otherwise, no effect. +\begin{note} +UTF-8 text can't be copied to \tcode{CharT} output. +\end{note} +\end{itemize} +\item +Otherwise, if \tcode{std::is_same_v} is \tcode{true}, equivalent to: +\begin{codeblock} +out = std::ranges::copy(txt.portable(), out) +\end{codeblock} +\item +Otherwise, no effect. +\begin{note} +Portable text can't be copied to \tcode{CharT} output. +\end{note} +\end{itemize} + +\pnum +\returns +\tcode{out}. + +\pnum +\throws +\tcode{std::invalid_argument} if there is no effect. +\end{itemdescr} + \indexlibrarymember{dimension_symbol_to}{Dimension} \begin{itemdecl} template Out, @\libconcept{Dimension}@ D> @@ -1533,13 +1857,51 @@ \end{itemdecl} \begin{itemdescr} +\pnum +Let \tcode{E} be the type of the dimension whose symbol text is being copied. + \pnum \effects -TBD. +Copies the symbol text of the dimension \tcode{D} to \tcode{out} according to \tcode{fmt} as follows: +\begin{itemize} +\item +If +\tcode{\exposidnc{is-derived-from-specialization-of}()} +is \tcode{true}, +let \tcode{Nums} and \tcode{Dens} +be packs denoting the template arguments of +\tcode{D::\exposidnc{nums}} and \tcode{D::\exposidnc{dens}}, respectively. +\begin{itemize} +\item +If \tcode{sizeof...(Nums) == 0 \&\& sizeof...(Dens) == 0} is \tcode{true}, +equivalent to \tcode{*out++ = '1'}. +\item +Otherwise, copies the symbol text of the numerators \tcode{(..., void(Nums))}, in that order, as follows. +Then, copies the symbol text of the denominators \tcode{(..., void(Dens))}, in that order, as follows. +\end{itemize} +\item +If \tcode{E} is a specialization of \tcode{power}, +copies the symbol text of \tcode{E::\exposidnc{factor}}, as follows. +Then, copies the symbol text of $\tcode{E::\exposidnc{exponent}} \neq 1$, determined as follows: +\begin{itemize} +\item +If \tcode{E} is a denominator, let \tcode{sign} be \tcode{"-"}. +Otherwise, let \tcode{sign} be \tcode{""}. +\item +Let \tcode{txt} be equivalent to \tcode{\exposidnc{get-symbol-exponent}(sign, E::\exposidnc{exponent})}. +\end{itemize} +\item +If \tcode{E::\exposid{symbol}} is a valid expression, let \tcode{txt} be that. +\item +Each time \tcode{txt} is determined, equivalent to: +\begin{codeblock} +out = @\exposidnc{copy-symbol-text}@(txt, fmt.char_set, out) +\end{codeblock} +\end{itemize} \pnum \returns -TBD. +\tcode{out}. \end{itemdescr} \indexlibrarymember{dimension_symbol}{Dimension} @@ -1550,11 +1912,33 @@ \begin{itemdescr} \pnum -\effects -Equivalent to: +\returns +A value \tcode{sv} such that +\range{sv.data()}{sv.data() + sv.size()} has static storage duration and +the following assertion holds: \begin{codeblock} -TBD. +std::basic_string s; +dimension_symbol_to(std::back_inserter(s), D{}, fmt); +assert(sv == s); +\end{codeblock} + +\pnum +\begin{example} +\begin{codeblock} +import mp_units; + +using namespace mp_units; + +static_assert(dimension_symbol(dimension_one) == "1"); +static_assert(dimension_symbol(isq::dim_length) == "L"); +static_assert(dimension_symbol(isq::dim_thermodynamic_temperature) == "\u0398"); +static_assert( + dimension_symbol<{character_set::portable}>(isq::dim_thermodynamic_temperature) == "O"); +static_assert(dimension_symbol(isq::speed.dimension) == "LT\u207B\u00B9"); +static_assert(dimension_symbol<{character_set::portable}>(isq::speed.dimension) == "LT^-1"); +static_assert(dimension_symbol(pow<1, 2>(isq::dim_length)) == "L^(1/2)"); \end{codeblock} +\end{example} \end{itemdescr} \rSec2[qty.spec]{Quantity specification} @@ -2343,6 +2727,10 @@ template friend consteval auto @\exposidnc{common-magnitude}@(@\exposidnc{unit-magnitude}@, // \expos @\exposidnc{unit-magnitude}@); + + template Out> + friend constexpr Out @\exposidnc{magnitude-symbol}@(Out out, @\exposidnc{unit-magnitude}@, // \expos + const unit_symbol_formatting& fmt); }; } @@ -2516,6 +2904,23 @@ by only positive powers relative to \tcode{C}. \end{itemdescr} +\indexlibrarymemberexpos{UnitMagnitude}{magnitude-symbol} +\begin{itemdecl} +template Out> +friend constexpr Out @\exposidnc{magnitude-symbol}@(Out out, @\exposidnc{unit-magnitude}@, // \expos + const unit_symbol_formatting& fmt); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +TBD. + +\pnum +\returns +\tcode{out}. +\end{itemdescr} + \rSec3[qty.unit.traits]{Traits} \indexlibraryglobal{space_before_unit_symbol} @@ -3309,26 +3714,38 @@ \rSec3[qty.unit.sym.fmt]{Symbol formatting} -\indexlibrarymember{unit_symbol_to}{Unit} \begin{itemdecl} -template Out, @\libconcept{Unit}@ U> -constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {}); +template Out> +constexpr Out @\exposidnc{copy-separator}@(Out out, const unit_symbol_formatting& fmt); // \expos \end{itemdecl} \begin{itemdescr} \pnum \effects -TBD. +Equivalent to: +\begin{codeblock} +if (fmt.separator == unit_symbol_separator::half_high_dot) { + const std::string_view dot = "\u22C5" /* @\unicode{22c5}{DOT OPERATOR}@ */; + out = std::ranges::copy(dot, out); +} else { + *out++ = ' '; +} +return out; +\end{codeblock} \pnum -\returns -TBD. +\throws +\tcode{std::invalid_argument} if +\tcode{fmt.separator == unit_symbol_separator::half_high_dot \&\& fmt.char_set != character_set::utf8} +is \tcode{true}. +\begin{note} +\tcode{unit_symbol_separator::half_high_dot} can be only used with \tcode{character_set::utf8}. +\end{note} \end{itemdescr} -\indexlibrarymember{unit_symbol}{Unit} \begin{itemdecl} -template -consteval std::string_view unit_symbol(U); +template +consteval @\libconcept{Unit}@ auto @\exposidnc{get-common-unit-in}@(common_unit, U u); // \expos \end{itemdecl} \begin{itemdescr} @@ -3336,41 +3753,255 @@ \effects Equivalent to: \begin{codeblock} -TBD. +auto get_magnitude = [&]() { + if constexpr (requires { common_unit::@\exposidnc{mag}@; }) + return common_unit::@\exposidnc{mag}@; + else + return mag<1>; +}; +constexpr auto canonical_u = get_canonical_unit(u); +constexpr @\libconcept{UnitMagnitude}@ auto cmag = get_magnitude() / canonical_u.mag; +if constexpr (cmag == mag<1>) + return u; +else + return scaled_unit{}; \end{codeblock} \end{itemdescr} -\rSec2[qty.ref.concepts]{Concepts} - -\begin{itemdecl} -template -concept @\deflibconcept{Reference}@ = @\libconcept{AssociatedUnit}@ || (@\exposidnc{is-specialization-of}@()); -\end{itemdecl} - -A type \tcode{T} that satisfies \tcode{Reference} -represents the reference of a quantity\irefiev{112-01-01}. - +\indexlibrarymember{unit_symbol_to}{Unit} \begin{itemdecl} -template -concept @\deflibconcept{ReferenceOf}@ = @\libconcept{Reference}@ && @\libconcept{QuantitySpecOf}@; +template Out, @\libconcept{Unit}@ U> +constexpr Out unit_symbol_to(Out out, U u, const unit_symbol_formatting& fmt = {}); \end{itemdecl} -\rSec2[qty.ref.syn]{Class template \tcode{reference}} +\begin{itemdescr} +\pnum +Let \tcode{E} be the type of the unit whose symbol text is being copied. -\indexlibrarymember{operator*}{reference} -\indexlibrarymember{operator*}{AssociatedUnit} -\indexlibrarymember{operator/}{reference} -\indexlibrarymember{operator/}{AssociatedUnit} -\indexlibrarymember{inverse}{reference} -\indexlibrarymember{pow}{reference} -\indexlibrarymember{sqrt}{reference} -\indexlibrarymember{cbrt}{reference} +\pnum +\effects +Copies the symbol text of the unit \tcode{U} to \tcode{out} according to \tcode{fmt} as follows: +\begin{itemize} +\item +If \tcode{E} is of the form \tcode{common_unit}, then: +\begin{itemize} +\item +Let \tcode{copy_unit(x)} be equivalent to +copying the symbol text of \begin{codeblock} -namespace mp_units { - -template<@\libconcept{QuantitySpec}@ auto Q, @\libconcept{Unit}@ auto U> -using @\exposidnc{reference-t}@ = reference; // \expos - +@\exposidnc{get-common-unit-in}@(common_unit{}, x) +\end{codeblock} +as follows. +\item +Equivalent to: +\begin{codeblock} +out = std::ranges::copy(std::string_view("EQUIV{"), out); +copy_unit(First{}); +(..., + (out = std::ranges::copy(std::string_view(", "), out), copy_unit(Tail{}))); +*out++ = '}'; +\end{codeblock} +\end{itemize} +\item +If \tcode{E} is of the form \tcode{scaled_unit}, then: +\begin{itemize} +\item +First, equivalent to: +\begin{codeblock} +*out++ = '('; +out = @\exposidnc{magnitude-symbol}@(out, M, fmt); // see \ref{qty.unit.mag.utils} +if constexpr (space_before_unit_symbol::@\exposidnc{reference-unit}@>) + *out++ = ' '; +\end{codeblock} +\item +Then, copies the symbol text of \tcode{E::\exposidnc{reference-unit}} as follows. +\item +Then, equivalent to \tcode{*out++ = ')'}. +\end{itemize} +\item +If +\tcode{\exposidnc{is-derived-from-specialization-of}()} +is \tcode{true}, +let \tcode{Nums} and \tcode{Dens} +be packs denoting the template arguments of +\tcode{U::\exposidnc{nums}} and \tcode{U::\exposidnc{dens}}, respectively. +\begin{itemize} +\item +If \tcode{sizeof...(Nums) == 0 \&\& sizeof...(Dens) == 0} is \tcode{true}, +no effect. +\item +Otherwise, performs the following algorithm. +To intersperse separators between steps +is to evaluate an expression equivalent to +\tcode{\exposidnc{copy-separator}(out, fmt)}. +First, copies the symbol text of the numerators \tcode{(..., void(Nums))}, in that order, as follows, with separators interspersed in-between. +Then, equivalent to: +\begin{codeblock} +using enum unit_symbol_solidus; +if (fmt.solidus == always || + (fmt.solidus == one_denominator && sizeof...(Dens) == 1)) { + if constexpr (sizeof...(Nums) == 0) *out++ = '1'; + *out++ = '/'; + if (sizeof...(Dens) > 1) *out++ = '('; +} else if constexpr (sizeof...(Nums) > 0) { + out = @\exposidnc{copy-separator}@(out, fmt); +} +\end{codeblock} +Then, copies the symbol text of the denominators \tcode{(..., void(Dens))}, in that order, as follows, with separators interspersed in-between. +Then, equivalent to: +\begin{codeblock} +using enum unit_symbol_solidus; +if (fmt.solidus == always && sizeof...(Dens) > 1) *out++ = ')'; +\end{codeblock} +\end{itemize} +\item +If \tcode{E} is a specialization of \tcode{power}, +copies the symbol text of \tcode{E::\exposidnc{factor}}, as follows. +Then, copies the symbol text of $\tcode{E::\exposidnc{exponent}} \neq 1$, determined as follows: +\begin{itemize} +\item +If \tcode{E} is part of a denominator, let \tcode{sign} be \tcode{"-"}. +Otherwise, let \tcode{sign} be \tcode{""}. +\item +Let \tcode{txt} be equivalent to \tcode{\exposidnc{get-symbol-exponent}(sign, E::\exposidnc{exponent})} (see \ref{qty.dim.sym.fmt}). +\end{itemize} +\item +If \tcode{E::\exposid{symbol}} is a valid expression, let \tcode{txt} be that. +\item +Each time \tcode{txt} is determined, equivalent to: +\begin{codeblock} +out = @\exposidnc{copy-symbol-text}@(txt, fmt.char_set, out) // see \ref{qty.dim.sym.fmt} +\end{codeblock} +\end{itemize} + +\pnum +\returns +\tcode{out}. +\end{itemdescr} + +\indexlibrarymember{unit_symbol}{Unit} +\begin{itemdecl} +template +consteval std::string_view unit_symbol(U); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A value \tcode{sv} such that +\range{sv.data()}{sv.data() + sv.size()} has static storage duration and +the following assertion holds: +\begin{codeblock} +std::basic_string s; +unit_symbol_to(std::back_inserter(s), U{}, fmt); +assert(sv == s); +\end{codeblock} + +\pnum +\begin{example} +\begin{codeblock} +import mp_units; + +using namespace mp_units; +using enum character_set; +using enum unit_symbol_solidus; +using enum unit_symbol_separator; + +static_assert(unit_symbol(metre) == "m"); +static_assert(unit_symbol(degree_Celsius) == "\u2103"); +static_assert(unit_symbol<{.char_set = portable}>(degree_Celsius) == "`C"); +static_assert(unit_symbol(kilogram) == "kg"); + +static_assert(unit_symbol(mag<100> * metre) == "(100 m)"); +static_assert(unit_symbol(mag<1000> * metre) == "(10\u00B3 m)"); +static_assert(unit_symbol<{.char_set = portable}>(mag<1000> * metre) == "(10^3 m)"); +static_assert(unit_symbol(mag<6000> * metre) == "(6 \u00D7 10\u00B3 m)"); +static_assert(unit_symbol(mag<10600> * metre) == "(10600 m)"); +static_assert(unit_symbol(mag_ratio<1, 18> * metre / second) == "(1/18 m)/s"); +static_assert(unit_symbol(mag_ratio<1, 18> * (metre / second)) == "(1/18 m/s)"); + +static_assert(unit_symbol(mag<\u03C0> * one) == "(\u03C0)"); +static_assert(unit_symbol(mag<\u03C0> * metre) == "(\u03C0 m)"); +static_assert(unit_symbol(mag<2> * mag<\u03C0> * metre) == "(2 \u03C0 m)"); +static_assert(unit_symbol<{.separator = half_high_dot}>(mag<2> * mag<\u03C0> * metre) == + "(2\u22C5\u03C0 m)"); +static_assert(unit_symbol(mag<1> / mag<\u03C0> * one) == "(1/\u03C0)"); +static_assert(unit_symbol(mag<1> / mag<\u03C0> * one) == + "(\u03C0\u207B\u00B9)"); +static_assert(unit_symbol( + mag<1> / mag<\u03C0> * one) == "(pi^-1)"); + +static_assert(unit_symbol(mag<1> / (mag<2> * mag<\u03C0>)*metre) == + "(2\u207B\u00B9 \u03C0\u207B\u00B9 m)"); +static_assert(unit_symbol(mag<1> / (mag<2> * mag<\u03C0>)*metre) == + "(1/(2 \u03C0) m)"); +static_assert(unit_symbol(mag_ratio<1, 2> * mag<\u03C0> * metre) == "(\u03C0/2 m)"); +static_assert(unit_symbol(mag_power<\u03C0, 2> * one) == "(\u03C0\u00B2)"); +static_assert(unit_symbol(mag_power<\u03C0, 1, 2> * one) == "(\u03C0^(1/2))"); + +static_assert(unit_symbol(get_common_unit(kilo, mile)) == + "EQUIV{(1/25146 mi), (1/15625 km)}"); + +static_assert(unit_symbol(kilo * metre) == "km m"); +static_assert(unit_symbol(kilo * metre) == + "km\u22C5m"); +static_assert(unit_symbol(metre / metre) == ""); +static_assert(unit_symbol(kilo / metre) == "km/m"); +static_assert(unit_symbol(kilo / metre) == + "km m\u207B\u00B9"); +static_assert(unit_symbol(kilo / + metre) == "km m^-1"); +static_assert(unit_symbol(metre / second) == "m/s"); +static_assert(unit_symbol(metre / second) == "m s\u207B\u00B9"); +static_assert(unit_symbol(metre / + second) == + "m\u22C5s\u207B\u00B9"); +static_assert(unit_symbol( + kilogram * metre / square(second)) == "kg\u22C5m\u22C5s\u207B\u00B2"); +static_assert(unit_symbol(one / metre / square(second)) == + "1/(m s\u00B2)"); +static_assert(unit_symbol(pow<1, 2>(metre / second)) == "m^(1/2)/s^(1/2)"); +static_assert(unit_symbol(pow<1, 2>(metre / second)) == + "m^(1/2) s^-(1/2)"); +static_assert(unit_symbol(litre / (mag<100> * kilo)) == "L/(100 km)"); +static_assert(unit_symbol((mag<10> * metre) / (mag<20> * second)) == "(10 m)/(20 s)"); +static_assert(unit_symbol(pow<2>(mag<3600> * second)) == "(3600 s)\u00B2"); +\end{codeblock} +Some of the assertions depend on the implementation-defined total order of types. +\end{example} +\end{itemdescr} + +\rSec2[qty.ref.concepts]{Concepts} + +\begin{itemdecl} +template +concept @\deflibconcept{Reference}@ = @\libconcept{AssociatedUnit}@ || (@\exposidnc{is-specialization-of}@()); +\end{itemdecl} + +A type \tcode{T} that satisfies \tcode{Reference} +represents the reference of a quantity\irefiev{112-01-01}. + +\begin{itemdecl} +template +concept @\deflibconcept{ReferenceOf}@ = @\libconcept{Reference}@ && @\libconcept{QuantitySpecOf}@; +\end{itemdecl} + +\rSec2[qty.ref.syn]{Class template \tcode{reference}} + +\indexlibrarymember{operator*}{reference} +\indexlibrarymember{operator*}{AssociatedUnit} +\indexlibrarymember{operator/}{reference} +\indexlibrarymember{operator/}{AssociatedUnit} +\indexlibrarymember{inverse}{reference} +\indexlibrarymember{pow}{reference} +\indexlibrarymember{sqrt}{reference} +\indexlibrarymember{cbrt}{reference} +\begin{codeblock} +namespace mp_units { + +template<@\libconcept{QuantitySpec}@ auto Q, @\libconcept{Unit}@ auto U> +using @\exposidnc{reference-t}@ = reference; // \expos + template<@\libconcept{QuantitySpec}@ Q, @\libconcept{Unit}@ U> struct @\libglobal{reference}@ { // \ref{qty.ref.ops}, operations @@ -3675,6 +4306,39 @@ \end{codeblock} \end{itemdescr} +\rSec2[qty.ref.utils]{Utilities} + +\indexlibrarymemberexpos{Reference}{clone-reference-with} +\indexlibrarymemberexpos{AssociatedUnit}{clone-reference-with} +\begin{itemdecl} +template +consteval decltype(To) @\exposidnc{clone-reference-with}@(From); +template +consteval reference @\exposidnc{clone-reference-with}@(reference); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{\{\}}. +\end{itemdescr} + +\rSec2[qty.ref.math]{Math} + +\indexlibrarymember{epsilon}{Reference} +\begin{itemdecl} +template<@\libconcept{Representation}@ Rep, @\libconcept{Reference}@ R> + requires requires { std::numeric_limits::epsilon(); } +constexpr quantity epsilon(R r) noexcept; // hosted +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return \{static_cast(std::numeric_limits::epsilon()), r\};} +\end{itemdescr} + \rSec1[qty.rep]{Representation} \rSec2[qty.rep.general]{General} @@ -5416,127 +6080,1493 @@ \end{codeblock} \end{itemdescr} -\rSec2[qty.common.type]{\tcode{std::common_type} specializations} +\rSec2[qty.math]{Math} -\begin{codeblock} -template - requires requires { - { mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference; - typename std::common_type_t; - requires mp_units::@\libconcept{RepresentationOf}@, - mp_units::get_common_quantity_spec(Q1::quantity_spec, - Q2::quantity_spec)>; - } -struct @\libspec{std::common_type}{quantity}@ { - using type = mp_units::quantity>; -}; +\indexlibrarymember{abs}{quantity} +\begin{itemdecl} +template + requires requires(Rep v) { abs(v); } || requires(Rep v) { std::abs(v); } +constexpr quantity abs(const quantity& q) noexcept; +\end{itemdecl} -template - requires(Q::unit == mp_units::one) && requires { - typename mp_units::quantity>; - } -struct @\libspec{std::common_type}{quantity}@ { - using type = mp_units::quantity>; -}; +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using std::abs; +return {static_cast(abs(q.numerical_value_ref_in(q.unit))), R}; \end{codeblock} +\end{itemdescr} -\rSec1[qty.pt]{Quantity point} - -\rSec2[qty.pt.general]{General} +\indexlibrarymember{pow}{quantity} +\begin{itemdecl} +template + requires (Den != 0) && requires(Rep v) { + representation_values::one(); + requires requires { pow(v, 1.0); } || requires { std::pow(v, 1.0); }; + } +constexpr quantity(R), Rep> pow(const quantity& q) noexcept; // hosted +\end{itemdecl} +\begin{itemdescr} \pnum -Subclause \ref{qty.pt} describes the class template \tcode{quantity_point} -that represents the value of a quantity\irefiev{112-01-28} -that is an element of an affine space\irefiev{102-03-02,102-04-01}. - -\rSec2[qty.pt.orig]{Point origin} +\effects +Equivalent to: +\begin{codeblock} +if constexpr (Num == 0) { + return quantity(R), Rep>::one(); +} else if constexpr (Num == Den) { + return q; +} else { + using std::pow; + return {static_cast(pow(q.numerical_value_ref_in(q.unit), + static_cast(Num) / static_cast(Den))), + pow(R)}; +} +\end{codeblock} +\end{itemdescr} -\rSec3[qty.pt.orig.general]{General} +\indexlibrarymember{sqrt}{quantity} +\begin{itemdecl} +template + requires requires(Rep v) { sqrt(v); } || requires(Rep v) { std::sqrt(v); } +constexpr quantity sqrt(const quantity& q) noexcept; // hosted +\end{itemdecl} +\begin{itemdescr} \pnum -This subclause specifies the components -for defining the origin of an affine space. -An \defn{origin} is a point from which measurements\irefiev{112-04-01} take place. - -\rSec3[qty.pt.orig.concepts]{Concepts} +\effects +Equivalent to: +\begin{codeblock} +using std::sqrt; +return {static_cast(sqrt(q.numerical_value_ref_in(q.unit))), sqrt(R)}; +\end{codeblock} +\end{itemdescr} +\indexlibrarymember{cbrt}{quantity} \begin{itemdecl} -template -concept @\deflibconcept{PointOrigin}@ = @\exposconceptnc{SymbolicConstant}@ && std::@\stdconcept{derived_from}@; - -template -concept @\deflibconcept{PointOriginFor}@ = @\libconcept{PointOrigin}@ && @\libconcept{QuantitySpecOf}@; - -template -concept @\defexposconceptnc{SameAbsolutePointOriginAs}@ = // \expos - @\libconcept{PointOrigin}@ && @\libconcept{PointOrigin}@ && @\exposidnc{same-absolute-point-origins}@(T{}, V); +template + requires requires(Rep v) { cbrt(v); } || requires(Rep v) { std::cbrt(v); } +constexpr quantity cbrt(const quantity& q) noexcept; // hosted \end{itemdecl} -\rSec3[qty.pt.orig.types]{Types} - -\rSec4[qty.abs.pt.orig]{Absolute} - +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace mp_units { - -template<@\libconcept{QuantitySpec}@ auto QS> -struct @\libglobal{absolute_point_origin}@ : @\exposidnc{point-origin-interface}@ { - static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = QS; // \expos -}; - -} +using std::cbrt; +return {static_cast(cbrt(q.numerical_value_ref_in(q.unit))), cbrt(R)}; \end{codeblock} +\end{itemdescr} -\pnum -An \defnadj{absolute}{origin} is an origin -chosen by convention and not defined in terms of another origin. -A specialization of \tcode{absolute_point_origin} is used as a base type when defining an absolute origin. -\tcode{QS} is the quantity the origin represents. - -\rSec4[qty.rel.pt.orig]{Relative} +\indexlibrarymember{exp}{quantity} +\begin{itemdecl} +template<@\libconcept{ReferenceOf}@ auto R, typename Rep> + requires requires(Rep v) { exp(v); } || requires(Rep v) { std::exp(v); } +constexpr quantity exp(const quantity& q); // hosted +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace mp_units { - -template<@\libconcept{QuantityPoint}@ auto QP> -struct @\libglobal{relative_point_origin}@ : @\exposidnc{point-origin-interface}@ { - static constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{quantity-point}@ = QP; // \expos - static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = @\seebelownc@; // \expos - static constexpr @\libconcept{PointOrigin}@ auto @\exposidnc{absolute-point-origin}@ = // \expos - QP.absolute_point_origin; -}; - -} +using std::exp; +return value_cast( + quantity{static_cast(exp(q.force_numerical_value_in(q.unit))), + @\exposidnc{clone-reference-with}@(R)}); \end{codeblock} +\end{itemdescr} -\pnum -A \defnadj{relative}{origin} is an origin -of a subspace\irefiev{102-03-03}. -A specialization of \tcode{relative_point_origin} is used as a base type when defining a relative origin \placeholder{O}. -\placeholder{O} is offset from \tcode{QP.absolute_point_origin} by \tcode{QP.quantity_from_zero()}. +\indexlibrarymember{isfinite}{quantity} +\begin{itemdecl} +template + requires requires(Rep v) { isfinite(v); } || requires(Rep v) { std::isfinite(v); } +constexpr bool isfinite(const quantity& a) noexcept; // hosted +\end{itemdecl} +\begin{itemdescr} \pnum -The member \exposid{quantity-spec} is equal to -\tcode{QP.point_origin.\exposidnc{quantity-spec}} if +\effects +Equivalent to: \begin{codeblock} -@\exposconceptnc{QuantityKindSpec}@ +using std::isfinite; +return isfinite(a.numerical_value_ref_in(a.unit)); \end{codeblock} -is satisfied, and -to \tcode{QP.\exposidnc{quantity-spec}} otherwise. +\end{itemdescr} -\rSec4[qty.zeroth.pt.orig]{Zeroth} +\indexlibrarymember{isinf}{quantity} +\begin{itemdecl} +template + requires requires(Rep v) { isinf(v); } || requires(Rep v) { std::isinf(v); } +constexpr bool isinf(const quantity& a) noexcept; // hosted +\end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to: \begin{codeblock} -namespace mp_units { - -template<@\libconcept{QuantitySpec}@ auto QS> -struct @\libglobal{zeroth_point_origin_}@ final : absolute_point_origin {}; - -} +using std::isinf; +return isinf(a.numerical_value_ref_in(a.unit)); \end{codeblock} +\end{itemdescr} -\pnum +\indexlibrarymember{isnan}{quantity} +\begin{itemdecl} +template + requires requires(Rep v) { isnan(v); } || requires(Rep v) { std::isnan(v); } +constexpr bool isnan(const quantity& a) noexcept; // hosted +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using std::isnan; +return isnan(a.numerical_value_ref_in(a.unit)); +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{fma}{quantity} +\begin{itemdecl} +template + requires + requires { + get_common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S), + get_quantity_spec(T)); + } && (equivalent(get_unit(R) * get_unit(S), get_unit(T))) && + requires(Rep1 v1, Rep2 v2, Rep3 v3) { + requires requires { fma(v1, v2, v3); } || requires { std::fma(v1, v2, v3); }; + } +constexpr @\libconcept{QuantityOf}@ auto +fma(const quantity& a, const quantity& x, // hosted + const quantity& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using std::fma; +return quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), + b.numerical_value_ref_in(b.unit)), + get_common_reference(R * S, T)}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{fmod}{quantity} +\begin{itemdecl} +template + requires requires(Rep1 v1, Rep2 v2) { + get_common_reference(R1, R2); + requires requires { fmod(v1, v2); } || requires { std::fmod(v1, v2); }; + } +constexpr @\libconcept{QuantityOf}@ auto fmod(const quantity& x, // hosted + const quantity& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +constexpr auto ref = get_common_reference(R1, R2); +constexpr auto unit = get_unit(ref); +using std::fmod; +return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{remainder}{quantity} +\begin{itemdecl} +template + requires requires(Rep1 v1, Rep2 v2) { + get_common_reference(R1, R2); + requires requires { remainder(v1, v2); } || requires { std::remainder(v1, v2); }; + } +constexpr @\libconcept{QuantityOf}@ auto remainder(const quantity& x, // hosted + const quantity& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +constexpr auto ref = get_common_reference(R1, R2); +constexpr auto unit = get_unit(ref); +using std::remainder; +return quantity{remainder(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{floor}{quantity} +\begin{itemdecl} +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> floor( // hosted + const quantity& q) noexcept + requires((!treat_as_floating_point) || requires(Rep v) { floor(v); } || + requires(Rep v) { std::floor(v); }) && + (equivalent(To, get_unit(R)) || requires { + q.force_in(To); + representation_values::one(); + }); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +const auto handle_signed_results = [&](const T& res) { + if (res > q) { + return res - T::one(); + } + return res; +}; +if constexpr (treat_as_floating_point) { + using std::floor; + if constexpr (equivalent(To, get_unit(R))) { + return {static_cast(floor(q.numerical_value_ref_in(q.unit))), + @\exposidnc{clone-reference-with}@(R)}; + } else { + return handle_signed_results( + quantity{static_cast(floor(q.force_numerical_value_in(To))), + @\exposidnc{clone-reference-with}@(R)}); + } +} else { + if constexpr (equivalent(To, get_unit(R))) { + return q.force_in(To); + } else { + return handle_signed_results(q.force_in(To)); + } +} +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{ceil}{quantity} +\begin{itemdecl} +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> ceil( // hosted + const quantity& q) noexcept + requires((!treat_as_floating_point) || requires(Rep v) { ceil(v); } || + requires(Rep v) { std::ceil(v); }) && + (equivalent(To, get_unit(R)) || requires { + q.force_in(To); + representation_values::one(); + }); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +const auto handle_signed_results = [&](const T& res) { + if (res < q) { + return res + T::one(); + } + return res; +}; +if constexpr (treat_as_floating_point) { + using std::ceil; + if constexpr (equivalent(To, get_unit(R))) { + return {static_cast(ceil(q.numerical_value_ref_in(q.unit))), + @\exposidnc{clone-reference-with}@(R)}; + } else { + return handle_signed_results(quantity{ + static_cast(ceil(q.force_numerical_value_in(To))), @\exposidnc{clone-reference-with}@(R)}); + } +} else { + if constexpr (equivalent(To, get_unit(R))) { + return q.force_in(To); + } else { + return handle_signed_results(q.force_in(To)); + } +} +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{round}{quantity} +\begin{itemdecl} +template<@\libconcept{Unit}@ auto To, auto R, typename Rep> +constexpr quantity<@\exposidnc{clone-reference-with}@(R), Rep> round( // hosted + const quantity& q) noexcept + requires((!treat_as_floating_point) || requires(Rep v) { round(v); } || + requires(Rep v) { std::round(v); }) && + (equivalent(To, get_unit(R)) || requires { + ::mp_units::floor(q); + representation_values::one(); + }); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +if constexpr (equivalent(To, get_unit(R))) { + if constexpr (treat_as_floating_point) { + using std::round; + return {static_cast(round(q.numerical_value_ref_in(q.unit))), + @\exposidnc{clone-reference-with}@(R)}; + } else { + return q.force_in(To); + } +} else { + const auto res_low = mp_units::floor(q); + const auto res_high = res_low + res_low.one(); + const auto diff0 = q - res_low; + const auto diff1 = res_high - q; + if (diff0 == diff1) { + if (static_cast(res_low.numerical_value_ref_in(To)) & 1) { + return res_high; + } + return res_low; + } + if (diff0 < diff1) { + return res_low; + } + return res_high; +} +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{inverse}{quantity} +\begin{itemdecl} +template +constexpr @\libconcept{QuantityOf}@ auto inverse( // hosted + const quantity& q) + requires requires { + representation_values::one(); + value_cast(1 / q); + }; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +return (representation_values::one() * one).force_in(To * quantity::unit) / q; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{hypot}{quantity} +\begin{itemdecl} +template + requires requires(Rep1 v1, Rep2 v2) { + get_common_reference(R1, R2); + requires requires { hypot(v1, v2); } || requires { std::hypot(v1, v2); }; + } +constexpr @\libconcept{QuantityOf}@ auto hypot( // hosted + const quantity& x, const quantity& y) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +constexpr auto ref = get_common_reference(R1, R2); +constexpr auto unit = get_unit(ref); +using std::hypot; +return quantity{hypot(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref}; +\end{codeblock} +\end{itemdescr} + +\indexlibrarymember{hypot}{quantity} +\begin{itemdecl} +template + requires requires(Rep1 v1, Rep2 v2, Rep3 v3) { + get_common_reference(R1, R2, R3); + requires requires { hypot(v1, v2, v3); } || requires { std::hypot(v1, v2, v3); }; + } +constexpr @\libconcept{QuantityOf}@ auto hypot( // hosted + const quantity& x, const quantity& y, + const quantity& z) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +constexpr auto ref = get_common_reference(R1, R2); +constexpr auto unit = get_unit(ref); +using std::hypot; +return quantity{ + hypot(x.numerical_value_in(unit), y.numerical_value_in(unit), z.numerical_value_in(unit)), + ref}; +\end{codeblock} +\end{itemdescr} + +\rSec2[qty.common.type]{\tcode{std::common_type} specializations} + +\begin{codeblock} +template + requires requires { + { mp_units::get_common_reference(Q1::reference, Q2::reference) } -> mp_units::Reference; + typename std::common_type_t; + requires mp_units::@\libconcept{RepresentationOf}@, + mp_units::get_common_quantity_spec(Q1::quantity_spec, + Q2::quantity_spec)>; + } +struct @\libspec{std::common_type}{quantity}@ { + using type = mp_units::quantity>; +}; + +template + requires(Q::unit == mp_units::one) && requires { + typename mp_units::quantity>; + } +struct @\libspec{std::common_type}{quantity}@ { + using type = mp_units::quantity>; +}; +\end{codeblock} + +\rSec2[qty.rand]{Random} + +\rSec3[qty.rand.req]{Requirements} + +% Local command to index names as members of all random number distribution types. +\newcommand{\indexrand}[1]{% +\indexlibrarymemberx{uniform_int_distribution}{#1}% +\indexlibrarymemberx{uniform_real_distribution}{#1}% +\indexlibrarymemberx{binomial_distribution}{#1}% +\indexlibrarymemberx{negative_binomial_distribution}{#1}% +\indexlibrarymemberx{geometric_distribution}{#1}% +\indexlibrarymemberx{poisson_distribution}{#1}% +\indexlibrarymemberx{exponential_distribution}{#1}% +\indexlibrarymemberx{gamma_distribution}{#1}% +\indexlibrarymemberx{weibull_distribution}{#1}% +\indexlibrarymemberx{extreme_value_distribution}{#1}% +\indexlibrarymemberx{normal_distribution}{#1}% +\indexlibrarymemberx{lognormal_distribution}{#1}% +\indexlibrarymemberx{chi_squared_distribution}{#1}% +\indexlibrarymemberx{cauchy_distribution}{#1}% +\indexlibrarymemberx{fisher_f_distribution}{#1}% +\indexlibrarymemberx{student_t_distribution}{#1}% +\indexlibrarymemberx{discrete_distribution}{#1}% +\indexlibrarymemberx{piecewise_constant_distribution}{#1}% +\indexlibrarymemberx{piecewise_linear_distribution}{#1}% +} + +\pnum +A class \tcode{D} +instantiated from a class template described in subclause \ref{qty.rand} +meets the following requirements. +In this subclase, +\begin{itemize} +\item +\tcode{d} is a value of \tcode{D}, and \tcode{x} is a (possibly const) value of \tcode{D}, +\item +\tcode{args} denotes an \fakegrammarterm{expression-list}, +\item +$\tcode{param}_i$ denotes the $i_{th}$ function parameter, and +\item +$\tcode{unwrapped_param}_i$ denotes \tcode{$\tcode{param}_i$.numerical_value_ref_in(Q::unit)} +if $\tcode{param}_i$ is an lvalue reference to \tcode{const Q}, and +$\tcode{param}_i$ otherwise. +\end{itemize} + +\begin{itemdecl} +D u; +D u = D(); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Default-initializes the \tcode{base} subobject. +\end{itemdescr} + +\begin{itemdecl} +D(args) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +$\tcode{unwrapped_param}_0, \ldots, \tcode{unwrapped_param}_n$. +\end{itemdescr} + +\indexrand{operator()}% +\begin{itemdecl} +d(g) +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return base::operator()(g) * Q::reference;} +\end{itemdescr} + +\indexrand{min}% +\indexrand{max}% +\indexlibrarymemberx{uniform_int_distribution}{a} +\indexlibrarymemberx{uniform_int_distribution}{b} +\indexlibrarymemberx{uniform_real_distribution}{a} +\indexlibrarymemberx{uniform_real_distribution}{b} +\indexlibrarymemberx{binomial_distribution}{t} +\indexlibrarymemberx{negative_binomial_distribution}{k} +\indexlibrarymemberx{extreme_value_distribution}{a} +\indexlibrarymemberx{normal_distribution}{mean} +\indexlibrarymemberx{normal_distribution}{stddev} +\indexlibrarymemberx{lognormal_distribution}{m} +\indexlibrarymemberx{lognormal_distribution}{s} +\indexlibrarymemberx{cauchy_distribution}{a} +\indexlibrarymemberx{cauchy_distribution}{b} +\begin{itemdecl} +x.@\placeholdernc{f}@() +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +For all other \placeholder{f}, +unless otherwise specified, +equivalent to: +\tcode{return base::\placeholdernc{f}() * Q::reference;} +\end{itemdescr} + +\rSec3[qty.rand.uni]{Uniform distributions} + +\rSec4[qty.rand.uni.int]{Class template \tcode{uniform_int_distribution}} + +\indexlibraryglobal{uniform_int_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct uniform_int_distribution // hosted + : public std::uniform_int_distribution { + using rep = Q::rep; + using base = std::uniform_int_distribution; + + uniform_int_distribution(); + uniform_int_distribution(const Q& a, const Q& b); + + template + Q operator()(Generator& g); + + Q a() const; + Q b() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.uni.real]{Class template \tcode{uniform_real_distribution}} + +\indexlibraryglobal{uniform_real_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct uniform_real_distribution // hosted + : public std::uniform_real_distribution { + using rep = Q::rep; + using base = std::uniform_real_distribution; + + uniform_real_distribution(); + uniform_real_distribution(const Q& a, const Q& b); + + template + Q operator()(Generator& g); + + Q a() const; + Q b() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec3[qty.rand.bern]{Bernoulli distributions} + +\rSec4[qty.rand.bern.bin]{Class template \tcode{binomial_distribution}} + +\indexlibraryglobal{binomial_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct binomial_distribution // hosted + : public std::binomial_distribution { + using rep = Q::rep; + using base = std::binomial_distribution; + + binomial_distribution(); + binomial_distribution(const Q& t, double p); + + template + Q operator()(Generator& g); + + Q t() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.bern.negbin]{Class template \tcode{negative_binomial_distribution}} + +\indexlibraryglobal{negative_binomial_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct negative_binomial_distribution // hosted + : public std::negative_binomial_distribution { + using rep = Q::rep; + using base = std::negative_binomial_distribution; + + negative_binomial_distribution(); + negative_binomial_distribution(const Q& k, double p); + + template + Q operator()(Generator& g); + + Q k() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +% Should this come before the above, like in the C++ standard? +\rSec4[qty.rand.bern.geo]{Class template \tcode{geometric_distribution}} + +\indexlibraryglobal{geometric_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct geometric_distribution // hosted + : public std::geometric_distribution { + using rep = Q::rep; + using base = std::geometric_distribution; + + geometric_distribution(); + explicit geometric_distribution(double p); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec3[qty.rand.pois]{Poisson distrubutions} + +\rSec4[qty.rand.pois.poisson]{Class template \tcode{poisson_distribution}} + +\indexlibraryglobal{poisson_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct poisson_distribution // hosted + : public std::poisson_distribution { + using rep = Q::rep; + using base = std::poisson_distribution; + + poisson_distribution(); + explicit poisson_distribution(double p); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.pois.exp]{Class template \tcode{exponential_distribution}} + +\indexlibraryglobal{exponential_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct exponential_distribution // hosted + : public std::exponential_distribution { + using rep = Q::rep; + using base = std::exponential_distribution; + + exponential_distribution(); + explicit exponential_distribution(const rep& lambda); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.pois.gamma]{Class template \tcode{gamma_distribution}} + +\indexlibraryglobal{gamma_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct gamma_distribution // hosted + : public std::gamma_distribution { + using rep = Q::rep; + using base = std::gamma_distribution; + + gamma_distribution(); + gamma_distribution(const rep& alpha, const rep& beta); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.pois.weibull]{Class template \tcode{weibull_distribution}} + +\indexlibraryglobal{weibull_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct weibull_distribution // hosted + : public std::weibull_distribution { + using rep = Q::rep; + using base = std::weibull_distribution; + + weibull_distribution(); + weibull_distribution(const rep& a, const rep& b); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.pois.extreme]{Class template \tcode{extreme_value_distribution}} + +\indexlibraryglobal{extreme_value_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct extreme_value_distribution // hosted + : public std::extreme_value_distribution { + using rep = Q::rep; + using base = std::extreme_value_distribution; + + extreme_value_distribution(); + extreme_value_distribution(const Q& a, const rep& b); + + template + Q operator()(Generator& g); + + Q a() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\indexlibrarymemberx{extreme_value_distribution}{operator()} +\begin{itemdecl} +template +Q operator()(Generator& g); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return Q(base::operator()(g));} +\end{itemdescr} + +\rSec3[qty.rand.norm]{Normal distributions} + +\rSec4[qty.rand.norm.normal]{Class template \tcode{normal_distribution}} + +\indexlibraryglobal{normal_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct normal_distribution // hosted + : public std::normal_distribution { + using rep = Q::rep; + using base = std::normal_distribution; + + normal_distribution(); + normal_distribution(const Q& mean, const Q& stddev); + + template + Q operator()(Generator& g); + + Q mean() const; + Q stddev() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\indexlibrarymemberx{normal_distribution}{operator()} +\begin{itemdecl} +template +Q operator()(Generator& g); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return Q(base::operator()(g));} +\end{itemdescr} + +\rSec4[qty.rand.norm.lognormal]{Class template \tcode{lognormal_distribution}} + +\indexlibraryglobal{lognormal_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct lognormal_distribution // hosted + : public std::lognormal_distribution { + using rep = Q::rep; + using base = std::lognormal_distribution; + + lognormal_distribution(); + lognormal_distribution(const Q& m, const Q& s); + + template + Q operator()(Generator& g); + + Q m() const; + Q s() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.norm.chisq]{Class template \tcode{chi_squared_distribution}} + +\indexlibraryglobal{chi_squared_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct chi_squared_distribution // hosted + : public std::chi_squared_distribution { + using rep = Q::rep; + using base = std::chi_squared_distribution; + + chi_squared_distribution(); + explicit chi_squared_distribution(const rep& n); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.norm.cauchy]{Class template \tcode{cauchy_distribution}} + +\indexlibraryglobal{cauchy_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct cauchy_distribution // hosted + : public std::cauchy_distribution { + using rep = Q::rep; + using base = std::cauchy_distribution; + + cauchy_distribution(); + cauchy_distribution(const Q& a, const Q& b); + + template + Q operator()(Generator& g); + + Q a() const; + Q b() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.norm.f]{Class template \tcode{fisher_f_distribution}} + +\indexlibraryglobal{fisher_f_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct fisher_f_distribution // hosted + : public std::fisher_f_distribution { + using rep = Q::rep; + using base = std::fisher_f_distribution; + + fisher_f_distribution(); + fisher_f_distribution(const rep& m, const rep& n); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.norm.t]{Class template \tcode{student_t_distribution}} + +\indexlibraryglobal{student_t_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +struct student_t_distribution // hosted + : public std::student_t_distribution { + using rep = Q::rep; + using base = std::student_t_distribution; + + student_t_distribution(); + explicit student_t_distribution(const rep& n); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec3[qty.rand.samp]{Sampling distributions} + +\rSec4[qty.rand.samp.discrite]{Class template \tcode{discrete_distribution}} + +\indexlibraryglobal{discrete_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{integral}@ +struct discrete_distribution // hosted + : public std::discrete_distribution { + using rep = Q::rep; + using base = std::discrete_distribution; + + discrete_distribution(); + + template + discrete_distribution(InputIt first, InputIt last); + + discrete_distribution(std::initializer_list weights); + + template + discrete_distribution(std::size_t count, double xmin, double xmax, UnaryOperation unary_op); + + template + Q operator()(Generator& g); + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\rSec4[qty.rand.samp.utils]{Utilities} + +\pnum +The following exposition-only function templates are used in the following subclauses. + +\begin{itemdecl} +template +std::vector @\exposidnc{i-qty-to-rep}@(InputIt first, InputIt last); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +std::vector intervals_rep; +intervals_rep.reserve(static_cast(std::distance(first, last))); +for (InputIt itr = first; itr != last; ++itr) { + intervals_rep.push_back(itr->numerical_value_ref_in(Q::unit)); +} +return intervals_rep; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template +std::vector @\exposidnc{bl-qty-to-rep}@(std::initializer_list& bl); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +std::vector bl_rep; +bl_rep.reserve(bl.size()); +for (const Q& qty : bl) { + bl_rep.push_back(qty.numerical_value_ref_in(Q::unit)); +} +return bl_rep; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template +std::vector @\exposidnc{fw-bl-pwc}@(std::initializer_list& bl, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using rep = Q::rep; +std::vector w_bl; +w_bl.reserve(bl.size()); +for (const Q& qty : bl) { + w_bl.push_back(fw(qty)); +} +std::vector weights; +weights.reserve(bl.size()); +for (std::size_t i = 0; i < bl.size() - 1; ++i) { + weights.push_back(w_bl[i] + w_bl[i + 1]); +} +weights.push_back(0); +return weights; +\end{codeblock} +\end{itemdescr} + +\begin{itemdecl} +template +std::vector @\exposidnc{fw-bl-pwl}@(std::initializer_list& bl, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +std::vector weights; +weights.reserve(bl.size()); +for (const Q& qty : bl) { + weights.push_back(fw(qty)); +} +return weights; +\end{codeblock} +\end{itemdescr} + +\rSec4[qty.rand.samp.pconst]{Class template \tcode{piecewise_constant_distribution}} + +\indexlibraryglobal{piecewise_constant_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +class piecewise_constant_distribution // hosted + : public std::piecewise_constant_distribution { + using rep = Q::rep; + using base = std::piecewise_constant_distribution; + + template + piecewise_constant_distribution(const std::vector& i, InputIt first_w); + + piecewise_constant_distribution(const std::vector& bl, const std::vector& weights); + +public: + piecewise_constant_distribution(); + + template + piecewise_constant_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w); + + template + piecewise_constant_distribution(std::initializer_list bl, UnaryOperation fw); + + template + piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, + UnaryOperation fw); + + template + Q operator()(Generator& g); + + std::vector intervals() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\indexlibraryctor{piecewise_constant_distribution} +\begin{itemdecl} +template +piecewise_constant_distribution(const std::vector& i, InputIt first_w); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(i.cbegin(), i.cend(), first_w) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_constant_distribution} +\begin{itemdecl} +piecewise_constant_distribution(const std::vector& bl, const std::vector& weights); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(bl.cbegin(), bl.cend(), weights.cbegin()) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_constant_distribution} +\begin{itemdecl} +template +piecewise_constant_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +piecewise_constant_distribution(@\exposidnc{i-qty-to-rep}@(first_i, last_i), first_w) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_constant_distribution} +\begin{itemdecl} +template +piecewise_constant_distribution(std::initializer_list bl, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +piecewise_constant_distribution(@\exposidnc{bl-qty-to-rep}@(bl), @\exposidnc{fw-bl-pwc}@(bl, fw)) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_constant_distribution} +\begin{itemdecl} +template +piecewise_constant_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit), + [fw](rep val) { return fw(val * Q::reference); }) +\end{codeblock} +\end{itemdescr} + +\indexlibrarymemberx{piecewise_constant_distribution}{intervals} +\begin{itemdecl} +std::vector intervals() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +const std::vector intervals_rep = base::intervals(); +std::vector intervals_qty; +intervals_qty.reserve(intervals_rep.size()); +for (const rep& val : intervals_rep) { + intervals_qty.push_back(val * Q::reference); +} +return intervals_qty; +\end{codeblock} +\end{itemdescr} + +\rSec4[qty.rand.samp.plinear]{Class template \tcode{piecewise_linear_distribution}} + +\indexlibraryglobal{piecewise_linear_distribution} +\begin{codeblock} +namespace mp_units { +template<@\libconcept{Quantity}@ Q> + requires std::@\stdconcept{floating_point}@ +class piecewise_linear_distribution // hosted + : public std::piecewise_linear_distribution { + using rep = Q::rep; + using base = std::piecewise_linear_distribution; + + template + piecewise_linear_distribution(const std::vector& i, InputIt first_w); + + piecewise_linear_distribution(const std::vector& bl, const std::vector& weights); + +public: + piecewise_linear_distribution() : base() {} + + template + piecewise_linear_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w); + + template + piecewise_linear_distribution(std::initializer_list bl, UnaryOperation fw); + + template + piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw); + + template + Q operator()(Generator& g); + + std::vector intervals() const; + + Q min() const; + Q max() const; +}; +} +\end{codeblock} + +\indexlibraryctor{piecewise_linear_distribution} +\begin{itemdecl} +template +piecewise_linear_distribution(const std::vector& i, InputIt first_w); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(i.cbegin(), i.cend(), first_w) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_linear_distribution} +\begin{itemdecl} +piecewise_linear_distribution(const std::vector& bl, const std::vector& weights); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(bl.cbegin(), bl.cend(), weights.cbegin()) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_linear_distribution} +\begin{itemdecl} +template +piecewise_linear_distribution(InputIt1 first_i, InputIt1 last_i, InputIt2 first_w); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +piecewise_linear_distribution(@\exposidnc{i-qty-to-rep}@(first_i, last_i), first_w) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_linear_distribution} +\begin{itemdecl} +template +piecewise_linear_distribution(std::initializer_list bl, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +piecewise_linear_distribution(@\exposidnc{bl-qty-to-rep}@(bl), @\exposidnc{fw-bl-pwl}@(bl, fw)) +\end{codeblock} +\end{itemdescr} + +\indexlibraryctor{piecewise_linear_distribution} +\begin{itemdecl} +template +piecewise_linear_distribution(std::size_t nw, const Q& xmin, const Q& xmax, UnaryOperation fw); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes the \tcode{base} subobject with +\begin{codeblock} +base(nw, xmin.numerical_value_ref_in(Q::unit), xmax.numerical_value_ref_in(Q::unit), + [fw](rep val) { return fw(val * Q::reference); }) +\end{codeblock} +\end{itemdescr} + +\indexlibrarymemberx{piecewise_linear_distribution}{intervals} +\begin{itemdecl} +std::vector intervals() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +const std::vector intervals_rep = base::intervals(); +std::vector intervals_qty; +intervals_qty.reserve(intervals_rep.size()); +for (const rep& val : intervals_rep) { + intervals_qty.push_back(val * Q::reference); +} +return intervals_qty; +\end{codeblock} +\end{itemdescr} + +\rSec1[qty.pt]{Quantity point} + +\rSec2[qty.pt.general]{General} + +\pnum +Subclause \ref{qty.pt} describes the class template \tcode{quantity_point} +that represents the value of a quantity\irefiev{112-01-28} +that is an element of an affine space\irefiev{102-03-02,102-04-01}. + +\rSec2[qty.pt.orig]{Point origin} + +\rSec3[qty.pt.orig.general]{General} + +\pnum +This subclause specifies the components +for defining the origin of an affine space. +An \defn{origin} is a point from which measurements\irefiev{112-04-01} take place. + +\rSec3[qty.pt.orig.concepts]{Concepts} + +\begin{itemdecl} +template +concept @\deflibconcept{PointOrigin}@ = @\exposconceptnc{SymbolicConstant}@ && std::@\stdconcept{derived_from}@; + +template +concept @\deflibconcept{PointOriginFor}@ = @\libconcept{PointOrigin}@ && @\libconcept{QuantitySpecOf}@; + +template +concept @\defexposconceptnc{SameAbsolutePointOriginAs}@ = // \expos + @\libconcept{PointOrigin}@ && @\libconcept{PointOrigin}@ && @\exposidnc{same-absolute-point-origins}@(T{}, V); +\end{itemdecl} + +\rSec3[qty.pt.orig.types]{Types} + +\rSec4[qty.abs.pt.orig]{Absolute} + +\begin{codeblock} +namespace mp_units { + +template<@\libconcept{QuantitySpec}@ auto QS> +struct @\libglobal{absolute_point_origin}@ : @\exposidnc{point-origin-interface}@ { + static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = QS; // \expos +}; + +} +\end{codeblock} + +\pnum +An \defnadj{absolute}{origin} is an origin +chosen by convention and not defined in terms of another origin. +A specialization of \tcode{absolute_point_origin} is used as a base type when defining an absolute origin. +\tcode{QS} is the quantity the origin represents. + +\rSec4[qty.rel.pt.orig]{Relative} + +\begin{codeblock} +namespace mp_units { + +template<@\libconcept{QuantityPoint}@ auto QP> +struct @\libglobal{relative_point_origin}@ : @\exposidnc{point-origin-interface}@ { + static constexpr @\libconcept{QuantityPoint}@ auto @\exposidnc{quantity-point}@ = QP; // \expos + static constexpr @\libconcept{QuantitySpec}@ auto @\exposidnc{quantity-spec}@ = @\seebelownc@; // \expos + static constexpr @\libconcept{PointOrigin}@ auto @\exposidnc{absolute-point-origin}@ = // \expos + QP.absolute_point_origin; +}; + +} +\end{codeblock} + +\pnum +A \defnadj{relative}{origin} is an origin +of a subspace\irefiev{102-03-03}. +A specialization of \tcode{relative_point_origin} is used as a base type when defining a relative origin \placeholder{O}. +\placeholder{O} is offset from \tcode{QP.absolute_point_origin} by \tcode{QP.quantity_from_zero()}. + +\pnum +The member \exposid{quantity-spec} is equal to +\tcode{QP.point_origin.\exposidnc{quantity-spec}} if +\begin{codeblock} +@\exposconceptnc{QuantityKindSpec}@ +\end{codeblock} +is satisfied, and +to \tcode{QP.\exposidnc{quantity-spec}} otherwise. + +\rSec4[qty.zeroth.pt.orig]{Zeroth} + +\begin{codeblock} +namespace mp_units { + +template<@\libconcept{QuantitySpec}@ auto QS> +struct @\libglobal{zeroth_point_origin_}@ final : absolute_point_origin {}; + +} +\end{codeblock} + +\pnum \tcode{zeroth_point_origin_} represents an origin chosen by convention as the value $0$ of the quantity \tcode{QS}. @@ -6644,6 +8674,79 @@ \end{codeblock} \end{itemdescr} +\rSec2[qty.pt.math]{Math} + +\indexlibrarymember{isfinite}{quantity_point} +\begin{itemdecl} +template + requires requires(quantity q) { isfinite(q); } +constexpr bool isfinite(const quantity_point& a) noexcept; // hosted +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return isfinite(a.quantity_ref_from(a.point_origin));} +\end{itemdescr} + +\indexlibrarymember{isinf}{quantity_point} +\begin{itemdecl} +template + requires requires(quantity q) { isinf(q); } +constexpr bool isinf(const quantity_point& a) noexcept; // hosted +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return isinf(a.quantity_ref_from(a.point_origin));} +\end{itemdescr} + +\indexlibrarymember{isnan}{quantity_point} +\begin{itemdecl} +template + requires requires(quantity q) { isnan(q); } +constexpr bool isnan(const quantity_point& a) noexcept; // hosted +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\tcode{return isnan(a.quantity_ref_from(a.point_origin));} +\end{itemdescr} + +\indexlibrarymember{fma}{quantity} +\indexlibrarymember{fma}{quantity_point} +\begin{itemdecl} +template + requires requires { + get_common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S), get_quantity_spec(T)); + } && (equivalent(get_unit(R) * get_unit(S), get_unit(T))) && + requires(Rep1 v1, Rep2 v2, Rep3 v3) { + requires requires { fma(v1, v2, v3); } || requires { std::fma(v1, v2, v3); }; + } +constexpr QuantityPointOf auto +fma(const quantity& a, const quantity& x, // hosted + const quantity_point& b) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Equivalent to: +\begin{codeblock} +using std::fma; +return Origin + + quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit), + b.quantity_ref_from(b.point_origin).numerical_value_ref_in(b.unit)), + get_common_reference(R* S, T)}; +\end{codeblock} +\end{itemdescr} + \rSec1[qty.systems]{Systems} \rSec1[qty.chrono]{\tcode{std::chrono} interoperability}