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

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

View file

@ -7,15 +7,7 @@ project(xo_unit VERSION 1.0)
include(GNUInstallDirs)
include(cmake/xo-bootstrap-macros.cmake)
xo_cxx_toplevel_options2()
# ----------------------------------------------------------------
# cmake -DCMAKE_BUILD_TYPE=debug
xo_toplevel_debug_config2()
# ----------------------------------------------------------------
# cmake -DCMAKE_BUILD_TYPE=coverage
xo_toplevel_coverage_config2()
xo_cxx_toplevel_options3()
# ----------------------------------------------------------------
# c++ settings

View file

@ -5,9 +5,11 @@ xo_docdir_doxygen_config()
xo_docdir_sphinx_config(
index.rst examples.rst glossary.rst install.rst implementation.rst development.rst
quantity-reference.rst quantity-class.rst quantity-factoryfunctions.rst quantity-unitvars.rst
unit-reference.rst unit-concept.rst unit-quantities.rst
scaled-unit-class.rst natural-unit-class.rst
bpu-class.rst bu-store-class.rst basis-unit-reference.rst
xquantity-reference.rst xquantity-class.rst
scaled-unit-reference.rst scaled-unit-class.rst scaled-unit-constants.rst
natural-unit-class.rst
bpu-class.rst
bu-store-class.rst basis-unit-reference.rst
basis-unit-class.rst basis-unit-constants.rst
dimension-enum.rst
)

View file

@ -3,16 +3,56 @@
Basis Unit
==========
A unit representing a fixed multiple of a native dimension.
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
|cYEL basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
Introduction
------------
A :code:`basis_unit` represents a unit belonging to a single native dimension.
For example :code:`bu::meter` representing a distance of 1 meter.
.. code-block:: cpp
#include <xo/unit/basis_unit.hpp>
.. uml::
:scale: 99%
:align: center
:caption: basis unit representing 1 minute
object bu1<<basis_unit>>
bu1 : native_dim = time
bu1 : scalefactor = 60
:code:`basis_unit` is intended as an implementation-level abstraction.
Application code will normally interact with the more-capable :code:`scaled_unit`
instead of :code:`basis_unit`.
Class
-----
A :code:`basis_unit` represents a unit belonging to a single native dimension.
For example :code:`bu::meter` representing a distance of 1 meter.
.. doxygenclass:: xo::qty::basis_unit
Member Variables

View file

@ -3,10 +3,38 @@
Basis Unit Constants
====================
These constants represent low-level building blocks.
Relative scalefactors for each built-in unit.
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
|cYEL basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
Introduction
------------
Constants in the :code:`xo::qty::detail::bu` namespace represent
low-level building blocks for specifying units.
Relative scalefactors for each unit are chosen here.
Application code will not use this class directly;
Application code will not typically use these values directtly;
instead it's expected to use units from the :code:`xo::qty::u` namespace.
Those units are implemented on top of the basis units described here.

View file

@ -3,26 +3,29 @@
Basis Unit Reference
====================
.. ditaa::
Built-in named units for each native dimension
+-----------+-----------+
| quantity | xquantity |
+-----------+-----------+
| scaled_unit |
+-----------------------+
| natural_unit |
+-----------------------+
| bpu |
+-----------+ |
| bu_store | |
+-----------+-----------+
|cYEL basis_unit |
+-----------------------+
| dimension |
+-----------------------+
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
|cYEL basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. toctree::
:maxdepth: 2
:maxdepth: 1
basis-unit-class
Basis Unit Class <basis-unit-class>
basis-unit-constants

View file

@ -3,23 +3,32 @@
BPU
===
.. ditaa::
A rational (usually integral) power of a single basis unit
+-----------+-----------+
| quantity | xquantity |
+-----------+-----------+
| scaled_unit |
+-----------------------+
| natural_unit |
+-----------------------+
|cYEL bpu |
+-------------+ |
| bu_store | |
+-------------+---------+
| basis_unit |
+-----------------------+
| dimension |
+-----------------------+
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
|cYEL bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
Introduction
------------
.. code-block:: cpp
@ -49,6 +58,13 @@ For example:
vol : scalefactor = 365*24*3600
vol : power = -1/2
:code:`bpu` is intended as an implementation-level abstraction.
Application code will normally interact with the more-general :code:`scaled_unit`
instead of :code:`bpu`.
Class
-----
.. doxygenclass:: xo::qty::bpu
Member Variables

View file

@ -4,22 +4,23 @@ Basis Unit Store
================
.. ditaa::
:--scale: 0.85
+-----------+-----------+
| quantity | xquantity |
+-----------+-----------+
| scaled_unit |
+-----------------------+
| natural_unit |
+-----------------------+
| bpu |
+-------------+ |
|cYEL bu_store| |
+-------------+---------+
| basis_unit |
+-----------------------+
| dimension |
+-----------------------+
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
|cYEL bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. code-block:: cpp

View file

@ -1,12 +1,12 @@
.. _development:
Development
===========
Miscellaneous development notes for *xo-unit*.
How To...
=========
Add Basis Unit
--------------
Addding a Basis Unit
--------------------
To add a basis unit for an existing dimension:

View file

@ -1,34 +1,66 @@
.. _dimension:
Dimension
=========
Native Dimension
================
An abstract dimension; distinct native dimensions are orthogonal
Context
-------
.. ditaa::
:--scale: 0.85
+-----------+-----------+
| quantity | xquantity |
+-----------+-----------+
| scaled_unit |
+-----------------------+
| natural_unit |
+-----------------------+
| bpu |
+-----------+ |
| bu_store | |
+-----------+-----------+
| basis_unit |
+-----------------------+
|cYEL dimension |
+-----------------------+
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
|cYEL dimension |
+--------------------------------+
Introduction
------------
Identifies an abstract dimension, for example *mass* or *time*.
.. code-block:: cpp
#include <xo/unit/dimension.hpp>
Identifies an abstract dimension, for example *mass* or *time*.
For example can use this enum to index basis members of a :doc:`scaled_unit<scaled-unit-class>` instance:
.. code-block:: cpp
:emphasize-lines: 7-8
#include <xo/unit/quantity.hpp>
using namespace xo::qty;
auto x = q::kilometers(100) / q::hours(1);
auto bpu1 = x.lookup_dim(dim::time);
auto bpu2 = x.lookup_dim(dim::distance);
Enum
----
.. doxygenenum:: xo::qty::dimension
Constants
---------
.. doxygenvariable:: xo::qty::n_dim
Functions
---------
.. doxygenfunction:: xo::qty::dim2str

View file

@ -15,7 +15,7 @@ Units propagate through familiar arithmetic expressions:
.. code-block:: cpp
:linenos:
:emphasize-lines: 15-16
:emphasize-lines: 14-15
#include "xo/unit/quantity.hpp"
#include "xo/unit/quantity_iostream.hpp"
@ -25,7 +25,6 @@ Units propagate through familiar arithmetic expressions:
main () {
namespace q = xo::qty::qty;
namespace su = xo::qty::su;
using xo::qty::quantity;
using namespace std;
constexpr auto t = q::minutes(2);
@ -40,7 +39,6 @@ Units propagate through familiar arithmetic expressions:
<< endl;
}
with output:
.. code-block::
@ -101,29 +99,50 @@ See ``xo-unit/examples/ex2`` for code below.
:linenos:
:emphasize-lines: 10,13,16-17
...
#include "xo/unit/quantity.hpp"
#include "xo/unit/quantity_iostream.hpp"
#include <iostream>
constexpr auto t = q::minutes(2);
constexpr auto d = q::kilometers(2.5);
int
main () {
namespace q = xo::qty::qty;
namespace u = xo::qty::u;
using xo::qty::with_units_from;
using xo::qty::with_units;
using xo::qty::quantity;
using xo::flatstring;
using namespace std;
constexpr auto t2 = t*t;
constexpr auto a = d / (t*t);
constexpr auto t = q::minutes(2);
constexpr auto d = q::kilometers(2.5);
// 1.
constexpr auto a2 = with_units<su::meter / (su::second * su::second)>(a);
constexpr auto t2 = t*t;
constexpr auto a = d / (t*t);
// 2.
constexpr auto a3 = a.rescale_ext<su::meter / (su::second * su::second)>();
cerr << "t: " << t << ", d: " << d
<< ", t^2: " << t2
<< ", d.t^-2: " << a
<< endl;
// 3.
constexpr auto au = q::meter / (q::second * q::second);
constexpr auto a4 = with_units_from(a, au); // 3.
constexpr auto a2 = with_units<u::meter / (u::second * u::second)>(a);
static_assert(a2.abbrev() == flatstring("m.s^-2"));
static_assert(a2.abbrev() == flatstring("m.s^-2"));
cerr << "a2: " << a2 << endl;
cerr << "a3: " << a3 << endl;
cerr << "a4: " << a4 << endl;
cerr << "a2: " << a2 << endl;
constexpr auto a3 = a.rescale_ext<u::meter / (u::second * u::second)>();
static_assert(a3.abbrev() == flatstring("m.s^-2"));
cerr << "a3: " << a3 << endl;
constexpr auto au = q::meter / (q::second * q::second);
constexpr auto a4 = with_units_from(a, au);
static_assert(a4.abbrev() == flatstring("m.s^-2"));
cerr << "a4: " << a4 << endl;
}
with output:
@ -149,13 +168,11 @@ See ``xo-unit/example/ex3`` for code below
int
main () {
namespace q = xo::qty::qty;
namespace nu = xo::qty::nu;
using xo::qty::with_units;
namespace u = xo::qty::u;
using xo::qty::quantity;
using xo::flatstring;
constexpr quantity<nu::second> t = q::minutes(2);
constexpr quantity<nu::meter> d = q::kilometers(2.5);
constexpr quantity<u::second> t = q::minutes(2);
constexpr quantity<u::meter> d = q::kilometers(2.5);
constexpr auto t2 = t*t;
constexpr auto a = d / (t*t);
@ -174,8 +191,8 @@ with output:
Remarks:
- Assignment to ``t`` converted to representation ``double``.
We could have used :code:`quantity<nu::second, int>` to preserve
right-hand-side representation.
We could have instead used :code:`quantity<u::second, int>` to propagate
right-hand-side representation
Scale conversion and arithmetic
-------------------------------
@ -185,6 +202,8 @@ xo-unit uses at most one scale for each :term:`basis dimension` associated with
When an arithmetic operator encounters basis units involving two different scales,
the operator will adopt the scale provided by the left-hand argument:
See ``xo-unit/example/ex4`` for code below
.. code-block:: cpp
:linenos:
:emphasize-lines: 11
@ -193,15 +212,13 @@ the operator will adopt the scale provided by the left-hand argument:
#include <iostream>
int main() {
namespace u = xo::unit;
namespace qty = xo::units::qty;
using namespace std;
namespace q = xo::qty::qty;
auto t1 = qty::milliseconds(1);
auto t2 = qty::minutes(1);
auto p = t1 * t2;
cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << endl;
std::cerr << "t1: " << t1 << ", t2: " << t2 << ", p: " << p << std::endl;
}
with output:
@ -210,9 +227,12 @@ with output:
t1: 1ms, t2: 1min, t1*t2: 60000ms^2
Dimensionless quantities unwrap implicitly
------------------------------------------
Conversely, compiler rejects attempt to implictly unwrap a dimensioned quantity.
See ``xo-unit/examples/ex4`` for code below.
.. code-block:: cpp
@ -237,13 +257,10 @@ See ``xo-unit/examples/ex4`` for code below.
static_assert(std::same_as<static_cast<double>(r1), double>);
// static_assert fails b/c static_cast only available for dimensionless quantity
//static_assert(std::same_as<decltype(static_cast<double>(t2)), double>);
// r1_value: assignment compiles, since r1 dimensionless
double r1_value = r1;
// r2_value: assignment won't compile, 'cannot convert' error
// r2_value: bad assignment won't compile, 'cannot convert' error
//double r2_value = t2;
std::cerr << "t1: " << t1 << ", t2: " << t2 << ", t1/t2: " << r1_value << std::endl;
@ -273,18 +290,19 @@ See ``xo-unit/examples/ex6`` for code below
:emphasize-lines: 15
#include "xo/unit/quantity.hpp"
#include "xo/unit/quantity_iostream.hpp"
#include <iostream>
int
main () {
namespace u = xo::unit::units;
namespace qty = xo::unit::qty;
namespace q = xo::unit::qty;
using namespace std;
/* 20% volatility over 250 days (approx number of trading days in one year) */
auto q1 = qty::volatility250d(0.2);
auto q1 = q::volatility_250d(0.2);
/* 10% volatility over 30 days */
auto q2 = qty::volatility30d(0.1);
auto q2 = q::volatility_30d(0.1);
auto sum = q1 + q2;
auto prod = q1 * q2;
@ -306,3 +324,43 @@ with output:
q2: 0.1mo^(-1/2)
q1+q2: 0.54641yr360^(-1/2)
q1*q2: 0.069282yr360^-1
Dynamic dimension
-----------------
If the dimension (or units) associated with a quantity are not known at compile-time,
use ``xo::qty::xquantity`` instead of ``xo::qty::quantity``.
See ``xo-unit/example/ex8`` for code below
.. code-block:: cpp
:linenos:
:emphasize-lines: 10-12
#include "xo/unit/xquantity.hpp"
#include "xo/unit/xquantity_iostream.hpp"
#include <iostream>
int
main () {
using namespace xo::qty;
namespace u = xo::qty::u;
xquantity qty1(7, u::foot);
xquantity qty2(6.0, u::inch);
xquantity qty3 = qty1 + qty2;
std::cerr << "qty1: " << qty1 << std::endl;
std::cerr << "qty2: " << qty2 << std::endl;
std::cerr << "qty3: " << qty3 << std::endl;
/* rescale to mm */
xquantity res = qty3.rescale(xo::qty::nu::millimeter);
/* 2286mm */
std::cerr << "res: " << res << std::endl;
}
Here ``u::foot`` and ``u::inch`` are literals,
but they could have been read from console input or another runtime-only context.

View file

@ -1,9 +1,23 @@
.. _implementation:
Abstraction Tower
=================
Components
==========
Abstraction tower for *xo-unit* components.
Library dependencies for *xo-unit*:
.. ditaa::
+-----------------+
| xo_unit |
+-----------------+
| xo_ratio |
+-----------------+
| xo_flatstring |
+-----------------+
``xo-unit`` also depends on ``xo-cmake`` macros.
Abstraction tower for *xo-unit* components:
.. ditaa::
@ -25,14 +39,32 @@ Abstraction tower for *xo-unit* components.
- :doc:`quantity<quantity-reference>`:
A quantity with compile-time unit work
A quantity with unit checking and conversion done at compile-time
- xquantity:
.. code-block:: cpp
#include "xo/unit/quantity.hpp"
auto q1 = xo::qty::qty::kilometers(7.5);
- :doc:`xquantity<xquantity-reference>`:
A quantity with unit checking and conversion done at run-time.
This is useful if unit information isn't known at compile time, for example
if reading units from console input.
.. code-block:: cpp
#include "xo/unit/xquantity.hpp"
xquantity qty1(7.5, xo::qty::u::foot)
A quantity with unit work deferred until runtime
- :doc:`scaled_unit<scaled-unit-class>`:
.. code-block:: cpp
#include "xo/unit/scaled_unit.hpp"
auto u = xo::qty::u::millimeter;
A unit involving zero or more dimensions, and associated conversion factor.
- can express result of arithmetic involving multiple scales,
@ -45,6 +77,11 @@ Abstraction tower for *xo-unit* components.
- :doc:`natural_unit<natural-unit-class>`
.. code-block:: cpp
#include "xo/unit/natural_unit.hpp"
auto u = xo::qty::nu::millimeter;
A unit involving zero or more dimensions, and at most one scale per dimension.
A quantity instance is always represented as a dimensionless multiple
of a natural unit
@ -56,24 +93,46 @@ Abstraction tower for *xo-unit* components.
A rational (usually integer) power of a basis unit. Has a single dimension.
.. code-block:: cpp
#include "xo/unit/bpu.hpp"
xo::qty::bpu(xo::qty::detail::bu::millimeter,
xo::qty::power_ratio_type(2)); // mm^2
- :doc:`bu_store<bu-store-class>`
Associates basis units with abbreviations.
Abbreviations used to decorate printed quantities.
For example ``bu::kilogram`` => ``"kg"``
.. code-block:: cpp
#include "xo/unit/bu_store.hpp"
xo::qty::bu_abbrev_store.bu_abbrev(xo::qty::detail::bu::picogram); // "pg"
- :doc:`basis_unit<basis-unit-reference>`
A unit with a single dimension and scale.
.. code-block:: cpp
#include "xo/unit/basis_unit.hpp"
auto b = xo::qty::detail::bu::picogram;
- :doc:`dimension<dimension-enum>`
identifies a dimension, such as mass or time.
.. code-block:: cpp
#include "xo/unit/dimension.hpp"
auto d = xo::qty::dimension::mass;
Representation
==============
Worked example using :cpp:class:`xo::qty::quantity`
Worked example using :cpp:class:`xo::qty::quantity`.
.. code-block:: cpp
:linenos:
@ -81,11 +140,14 @@ Worked example using :cpp:class:`xo::qty::quantity`
#include "xo/unit/quantity.hpp"
...
using xo::qty;
namespace q = xo::qty::qty;
// 7.55km.min^-2
quantity qty1 = 7.55 * q::kilometer / (q::minute * q::minute);
Note: in diagrams below, components with pale blue background are discarded before runtime
.. uml::
:caption: representation for quantity 7.55km.min^-2
:scale: 99%
@ -94,7 +156,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty1<<quantity>>
qty1 : scale = 7.55
rectangle {
rectangle #e0f0ff {
object km_per_min2<<natural_unit>>
km_per_min2 : n_bpu = 2
@ -132,7 +194,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty2<<quantity>>
qty2 : scale = 123
rectangle {
rectangle #e0f0ff {
object ng_unit<<natural_unit>>
ng_unit : n_bpu = 1
@ -163,7 +225,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty3<<quantity>>
qty3 : scale = 928.65
rectangle {
rectangle #e0f0ff {
object ng_km_min2_unit<<natural_unit>>
ng_km_min2_unit : n_bpu = 3
@ -214,7 +276,7 @@ Worked example using :cpp:class:`xo::qty::quantity`
object qty3b<<quantity>>
qty3b : scale = 2.59758e-10
rectangle {
rectangle #e0f0ff {
object kg_m_s2_unit<<natural_unit>>
kg_m_s2_unit : n_bpu = 3

View file

@ -33,15 +33,15 @@ runtime (since we can't construct new c++ types at runtime).
install
examples
implementation
development
unit-quantities
quantity-reference
scaled-unit-class
xquantity-reference
scaled-unit-reference
natural-unit-class
bpu-class
bu-store-class
basis-unit-reference
dimension-enum
development
Indices and Tables
------------------

View file

@ -6,24 +6,39 @@
Install
=======
`xo-unit source`_ lives on github.
``xo-unit`` uses supporting header-only libraries ``xo-ratio`` and ``xo-flatstring``.
All three are on github:
- `xo-unit source`_
- `xo-ratio source`_
- `xo-flatstring source`_
.. _xo-unit source: https://github.com/rconybea/xo-unit
.. _xo-ratio source: https://github.com/rconybea/xo-ratio
.. _xo-flatstring source: https://github.com/rconybea/xo-flatstring
Implementation relies on some c++20 features (for example class-instances as template arguments).
Tested with gcc 12.3, 13.2
``xo-unit`` also relies on sister header-only libraries:
One way to use ``xo-unit`` in a project is to import the source tree directly:
Include as submodule
--------------------
.. code-block:: bash
cd myproject
git submodule add -b main https://github.com/rconybea/xo-flatstring ext/xo-flatstring
git submodule add -b main https://github.com/rconybea/xo-ratio ext/xo-ratio
git submodule add -b main https://github.com/rconybea/xo-unit ext/xo-unit
git submodule update --init
This assumes you organize directly-incorporated dependencies under directory ``myproject/ext``.
You would then add ``myproject/ext/xo-unit/include`` to your compiler's include path,
You would then add to your compiler's include path the directories ``myproject/ext/xo-flatstring/include``,
``myproject/ext/xo-ratio/include``, ``myproject/ext/xo-unit/include``;
and add
.. code-block:: c++
@ -32,31 +47,258 @@ and add
to c++ source files that rely on xo-unit
Ubuntu Install Pattern
----------------------
Example instructions (from github actions CI) for build starting from stock ubuntu are in `ubuntu-main.yml`_
.. _ubuntu-main.yml: https://github.com/Rconybea/xo-unit/blob/main/.github/workflows/ubuntu-main.yml
Installing from source
----------------------
Although the xo-unit, xo-ratio and xo-flatstring libraries are header-only,
they do have a build dependency on shared cmake macros, and a bootstrap script `xo-cmake-config`.
* `xo-cmake`_ source
.. _xo-cmake: https://github.com/rconybea/xo-cmake
Preamble:
.. code-block:: bash
mkdir -p ~/proj/xo
cd ~/proj/xo
git clone https://github.com/rconybea/xo-cmake
git clone https://github.com/rconybea/xo-flatstring
git clone https://github.com/rconybea/xo-ratio
git clone https://github.com/rconybea/xo-unit
PREFIX=~/local # ..or other desired installation prefix
Ordering below is important; cmake support for each subsystem
requires successful installation of its predecessor.
Install `xo-cmake`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake
cmake --build xo-cmake/.build -j # placeholder, no-op for now
cmake --install xo-cmake/.build
Build and Install `xo-flatstring`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
-B xo-flatstring/.build -S xo-flatstring
cmake --build xo-flatstring/.build -j
cmake --install xo-flatstring/.build
Build and Install `xo-ratio`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
-B xo-ratio/.build -S xo-ratio
cmake --build xo-ratio/.build -j
cmake --install xo-ratio/.build
Build and Install `xo-unit`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DENABLE_TESTING=0 \
-B xo-unit/.build -S xo-unit
cmake --build xo-unit/.build -j
cmake --install xo-unit/.build
Directories under ``PREFIX`` will then contain:
.. code-block::
PREFIX
+- bin
| \- xo-cmake-config
+- include
| \- xo
| +- cxxutil/
| +- flatstring/
| +- ratio/
| +- unit/
+- lib
| \- cmake
| +- indentlog/
| +- randomgen/
| +- xo_flatstring/
| \- xo_unit/
+- share
\- cmake
\- xo_macros/
Use CMake Support
-----------------
To use built-in cmake suport:
Make sure ``PREFIX/lib/cmake`` is searched by cmake (if necessary, include it in ``CMAKE_PREFIX_PATH``)
Add to ``CMakeLists.txt``:
.. code-block:: cmake
FindPackage(xo_unit CONFIG REQUIRED)
target_link_libraries(mytarget INTERFACE xo_unit)
Build and Install with Unit Tests Enabled
-----------------------------------------
Running unit tests require a few additional dependencies:
* `catch2`_ header-only unit-test framework
* `xo-indentlog`_ logging with call-structure indenting
* `xo-randomgen`_ fast random number generator (xoshiro256ss)
.. _catch2: https://github.com/catchorg/Catch2
.. _xo-indentlog: https://github.com/rconybea/indentlog
.. _xo-randomgen: https://github.com/rconybea/randomgen
Preamble:
.. code-block:: bash
mkdir -p ~/proj/xo
cd ~/proj/xo
git clone https://github.com/rconybea/xo-cmake
git clone https://github.com/rconybea/indentlog xo-indentlog
git clone https://github.com/rconybea/randomgen xo-randomgen
git clone https://github.com/rconybea/xo-flatstring
git clone https://github.com/rconybea/xo-ratio
git clone https://github.com/rconybea/xo-unit
PREFIX=~/local # ..or other desired installation prefix
Build and Install `catch2` (assuming ubuntu here):
.. code-block:: bash
sudo apt-get install catch2 # on ubuntu, for example
Build and Install `xo-cmake`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-cmake/.build -S xo-cmake
cmake --build xo-cmake/.build -j # placeholder, no-op for now
cmake --install xo-cmake/.build
Build, Test and Install `xo-indentlog`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-indentlog/.build -S xo-indentlog
cmake --build xo-indentlog/.build -j
cmake --build xo-indentlog/.build -- test # run unit tests, cmake invokes ctest
(cd xo-indentlog/.build && ctest) # or invoke ctest directly
cmake --install xo-indentlog/.build
Build and Install `xo-randomgen` (no unit tests yet):
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-randomgen/.build -S xo-randomgen
cmake --build xo-randomgen/.build -j
cmake --install xo-randomgen/.build
Build, Test and Install `xo-flatstring`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-flatstring/.build -S xo-flatstring
cmake --build xo-flatstring/.build -j
cmake --build xo-flatstring/.build -- test # run unit tests, cmake invokes ctest
(cd xo-flatstring/.build && ctest) # or invoke ctest directly
cmake --install xo-flatstring/.build
Build, Test and Install `xo-ratio`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-ratio/.build -S xo-ratio
cmake --build xo-ratio/.build -j
cmake --build xo-ratio/.build -- test # run unit tests, cmake invokes ctest
(cd xo-ratio/.build && ctest) # or invoke ctest directly
cmake --install xo-ratio/.build
Build, Test and Install `xo-unit`:
.. code-block:: bash
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build -S xo-unit
cmake --build xo-unit/.build -j
cmake --build xo-unit/.build -- test # run unit tests, cmake invokes ctest
(cd xo-unit/.build && ctest) # or invoke ctest directly
cmake --install xo-unit/.build
Build Examples
--------------
To enable building example programs:
.. code-block:: bash
cd ~/proj/xo
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DXO_ENABLE_EXAMPLES=1 -B xo-unit/.build -S xo-unit
Run examples from the build directory:
.. code-block:: bash
~/proj/xo/xo-unit/.build/example/ex1/xo_unit_ex1
~/proj/xo/xo-unit/.build/example/ex2/xo_unit_ex2
# etc
Build and Install Documentation
-------------------------------
xo-unit documentation has these additional dependencies:
* `doxygen`_ annotation-driven inline documentation
* `sphinx`_ documentation based on ReST files
* `sphinx-rtd-theme`_ popular CSS theme for sphinx
* `breathe`_ make doxygen-generated ingredients available from sphinx
.. _doxygen: https://www.doxygen.nl
.. _sphinx: https://www.sphinx-doc.org
.. _sphinx-rtd-theme: https://pypi.org/project/sphinx-rtd-theme
.. _breathe: https://breathe.readthedocs.io/en/latest
Preamble (assuming ubuntu here):
.. code-block:: bash
sudo apt-get install doxygen
sudo apt-get install python3-sphinx
sudo apt-get install python3-sphinx-rtd-theme
sudo apt-get install python3-breathe
Build `xo-unit` docs
.. code-block:: bash
cd ~/proj/xo
cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -B xo-unit/.build
cmake --build xo-unit/.build -- docs
cmake --install xo-unit/.build # if docs built, installs to $PREFIX/share/doc/xo_unit/html
Supported compilers
-------------------
* developed with gcc 12.3.0 and gcc 13.2.0; github CI using gcc 11.4.0 (asof March 2024)
Building from source
--------------------
Although the xo-unit library is header-only, unit tests have some dependencies.
Example instructions (github CI) for build starting from stock ubuntu are in `ubuntu-main.yml`_
.. _ubuntu-main.yml: https://github.com/Rconybea/xo-unit/blob/main/.github/workflows/ubuntu-main.yml
Unit test dependencies:
* `catch2`_ header-only unit-test framework
* `xo-cmake`_ cmake macros
* `xo-indentlog`_ logging with call-structure indenting
* `xo-refcnt`_ intrusive reference counting (needed by xo-reflect)
* `xo-subsys`_ plugin initialization support (needed by xo-reflect)
* `xo-reflect`_ c++ introspection library
.. _catch2: https://github.com/catchorg/Catch2
.. _xo-cmake: https://github.com/rconybea/xo-cmake
.. _xo-indentlog: https://github.com/rconybea/indentlog
.. _xo-refcnt: https://github.com/rconybea/refcnt
.. _xo-subsys: https://github.com/rconybea/subsys
.. _xo-reflect: https://github.com/rconybea/reflect

View file

@ -3,38 +3,107 @@
Natural Unit
============
.. ditaa::
A natural unit represents a product of terms, each involving a distinct basis dimension
+----------------+----------------+
| quantity | xquantity |
+----------------+----------------+
| scaled_unit |
+---------------------------------+
|cYEL natural_unit |
+---------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+----------------+
| basis_unit |
+---------------------------------+
| dimension |
+---------------------------------+
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
|cYEL natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
Introduction
------------
.. code-block:: cpp
#include <xo/unit/natural_unit.hpp>
Representation for the unit associated with a @ref quantity or xquantity.
Representation for the unit associated with a :doc:`xquantity<xquantity-class>`
- represents a cartesian product of basis units.
- constexpr implementation
- limited support for fractional dimensions such as time^-1/2
.. uml::
:caption: natural unit for a Newton (unit of force)
:scale: 99%
:align: center
object newton<<natural_unit>>
newton : n_bpu = 3
newton : bpu_v[]
object kg<<bpu>>
kg : native_dim = dim::mass
kg : scalefactor = 1000/1
kg : power = 1/1
object m<<bpu>>
m : native_dim = dim::distance
m : scalefactor = 1/1
m : power = 1/1
object s2<<bpu>>
s2 : native_dim = dim::time
s2 : scalefactor = 1/1
s2 : power = -2/1
newton o-- kg
newton o-- m
newton o-- s2
Class
-----
.. doxygenclass:: xo::qty::natural_unit
Member Variables
----------------
.. doxygengroup:: natural-unit-instance-vars
Type Traits
-----------
.. doxygengroup:: natural-unit-type-traits
Constructors
------------
.. doxygengroup:: natural-unit-ctors
Access Methods
--------------
.. doxygengroup:: natural-unit-access-methods
General Methods
---------------
.. doxygengroup:: natural-unit-methods
Conversion
----------
.. doxygengroup:: natural-unit-conversion-methods
Comparison Functions
--------------------
.. doxygengroup:: natural-unit-comparison-functions

View file

@ -3,26 +3,70 @@
Quantity
========
.. ditaa::
+----------------+---------------+
|cYEL quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. code-block:: cpp
#include <xo/unit/quantity.hpp>
.. uml::
:scale: 99%
:align: center
allowmixing
object qty1<<quantity>>
qty1 : scale = 1.23
rectangle constexpr #e0f0ff {
object unit<<natural_unit>>
qty1 o-- unit : s_unit (static constexpr)
}
Arithmetic on :doc:`xo::qty::quantity<quantity-reference>` instances
does *not* use ``xo::qty::quantity::s_scaled_unit`` at runtime;
instead gets everything it needs at compile time.
Class
-----
The primary data structure for interacting with xo-unit is the
template class ``xo::qty::quantity``.
A quantity is a compile-time wrapper around a single arithmetic value,
with type taken from the ``Repr`` parameter in ``quantity<Unit, Repr>``.
.. doxygenclass:: xo::qty::quantity
Type Traits
-----------
.. doxygengroup:: quantity-type-traits
Member Variables
----------------
.. doxygengroup:: quantity-static-vars
.. doxygengroup:: quantity-instance-vars
Type Traits
-----------
.. doxygengroup:: quantity-type-traits
Constructors
------------

View file

@ -1,5 +1,23 @@
.. _quantity_factoryfunctions:
.. ditaa::
+----------------+---------------+
|cYEL quantity | xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. toctree::
:maxdepth: 2
@ -12,20 +30,39 @@ Quantity Factory Functions
Mass
----
.. doxygenfunction:: xo::qty::qty::picograms
.. doxygenfunction:: xo::qty::qty::nanograms
.. doxygenfunction:: xo::qty::qty::micrograms
.. doxygenfunction:: xo::qty::qty::milligrams
.. doxygenfunction:: xo::qty::qty::grams
.. doxygenfunction:: xo::qty::qty::kilograms
.. doxygenfunction:: xo::qty::qty::tonnes
.. doxygenfunction:: xo::qty::qty::kilotonnes
.. doxygenfunction:: xo::qty::qty::megatonnes
.. doxygenfunction:: xo::qty::qty::gigatonnes
Distance
--------
.. doxygenfunction:: xo::qty::qty::picometers
.. doxygenfunction:: xo::qty::qty::nanometers
.. doxygenfunction:: xo::qty::qty::micrometers
.. doxygenfunction:: xo::qty::qty::millimeters
.. doxygenfunction:: xo::qty::qty::meters
.. doxygenfunction:: xo::qty::qty::kilometers
.. doxygenfunction:: xo::qty::qty::megameters
.. doxygenfunction:: xo::qty::qty::gigameters
.. doxygenfunction:: xo::qty::qty::lightseconds
.. doxygenfunction:: xo::qty::qty::astronomicalunits
.. doxygenfunction:: xo::qty::qty::inches
.. doxygenfunction:: xo::qty::qty::feet
.. doxygenfunction:: xo::qty::qty::yards
.. doxygenfunction:: xo::qty::qty::miles
Time
----
.. doxygenfunction:: xo::qty::qty::picoseconds
.. doxygenfunction:: xo::qty::qty::nanoseconds
.. doxygenfunction:: xo::qty::qty::microseconds
.. doxygenfunction:: xo::qty::qty::milliseconds
@ -33,3 +70,16 @@ Time
.. doxygenfunction:: xo::qty::qty::minutes
.. doxygenfunction:: xo::qty::qty::hours
.. doxygenfunction:: xo::qty::qty::days
.. doxygenfunction:: xo::qty::qty::weeks
.. doxygenfunction:: xo::qty::qty::months
.. doxygenfunction:: xo::qty::qty::years
.. doxygenfunction:: xo::qty::qty::year250s
.. doxygenfunction:: xo::qty::qty::year360s
.. doxygenfunction:: xo::qty::qty::year365s
Volatility
----------
.. doxygenfunction:: xo::qty::qty::volatility_30d
.. doxygenfunction:: xo::qty::qty::volatility_250d
.. doxygenfunction:: xo::qty::qty::volatility_360d
.. doxygenfunction:: xo::qty::qty::volatility_365d

View file

@ -3,7 +3,13 @@
Scaled Unit
===========
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+----------------+
| quantity | xquantity |
@ -21,15 +27,53 @@ Scaled Unit
| dimension |
+---------------------------------+
Introduction
------------
.. code-block::cpp
#include <xo/unit/scaled_unit.hpp>
Result of mutliplication or division of natural units (:doc:`natural-unit-class`).
Extension of :doc:`natural_unit<natural-unit-class>` to enable representing the intermediate
result of multiplication (or division) of natural units.
- represents a (dimensionless) multiple of a cartesian product of basis units.
- constexpr implementation
- limited support for fractional dimensions such as time^-1/2
.. uml::
:caption: scaled unit after (u::meter * u::foot / u::minute)
:scale: 99%
:align: center
object area_per_time<<scaled_unit>>
area_per_time : outer_scale_factor = 3048/10000
area_per_time : outer_scale_sq = 1.0
area_per_time : natural_unit = m2_per_min
object m2_per_min<<natural_unit>>
m2_per_min : n_bpu = 2
m2_per_min : bpu_v[]
object m2<<bpu>>
m2 : native_dim = dim::distance
m2 : scalefactor = 1/1
m2 : power = 2/1
object min<<bpu>>
min : native_dim = dim::time
min : scalefactor = 60/1
min : power = -1/1
area_per_time o-- m2_per_min
m2_per_min o-- m2
m2_per_min o-- min
Scaled units with non-unity outer scalefactors arise as intermediate results
of quantity arithmetic
Motivation
----------
^^^^^^^^^^
Consider multiplying two units:
@ -47,13 +91,75 @@ to do this we accumulate a product of conversion factors from such consolidation
For example:
.. code-block:: cpp
:emphasize-lines: 3
static_assert(u_prod.natural_unit[0].bu() == detail::bu::meter);
static_assert(u_prod.natural_unit[0].power() == power_ratio_type(2));
static_assert(u_prod.n_bpu() == 1);
static_assert(u_prod[0].bu() == detail::bu::meter);
static_assert(u_prod[0].power() == power_ratio_type(2));
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1000));
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
Here we accumulate :code:`1000`, from converting kilometers to meters.
Division works similarly. In this example dimension cancel, but we still have a non-unity conversion factor.
.. code-block:: cpp
:emphasize-lines: 7
namespace u = xo::qty::u;
constexpr auto u_div = u::meter / u::kilometer;
// dimensionlesss result
static_assert(u_prod.n_bpu() == 0);
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1,1000));
static_assert(u_prod.outer_scale_sq_ == 1.0);
When multiple dimensions needing conversion are involved, scalefactors accumulate:
.. code-block:: cpp
:emphasize-lines: 8
namespace u = xo::qty::u;
constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute;
static_assert(u2_prod.n_bpu() == 2);
static_assert(u2_prod[0].bu() == detail::bu::meter);
static_assert(u2_prod[1].bu() == detail::bu::hour);
static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(50,3));
static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
Here the :code:`50/3` result comes from multiplying :code:`1000/1` (converting kilometers -> meters)
by :code:`1/60` (converting minutes -> hours)
Class
-----
.. doxygenclass:: xo::qty::scaled_unit
Member Variables
----------------
.. doxygengroup:: scaled-unit-instance-vars
Type Traits
-----------
.. doxygengroup:: scaled-unit-type-traits
Access Methods
--------------
.. doxygengroup:: scaled-unit-access-methods
General Methods
---------------
.. doxygengroup:: scaled-unit-general-methods
Operators
---------
.. doxygengroup:: scaled-unit-operators

View file

@ -0,0 +1,75 @@
.. _scaled-unit-constants
Scaled Unit Constants
=====================
Built-in unit constants.
Context
-------
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
|cYEL scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
Introduction
------------
Built-in units. Application code may use these to trigger conversion
.. code-block:: cpp
:emphasize-lines: 5
#include <xo/unit/quantity.hpp>
using namespace xo::qty;
constexpr quantity<u::meter / u::second> q1 = q::miles(60) / q::hour;
Note that it's often easiest to use :doc:`unit quantity constants<quantity-unitvars>`,
like :code:`q::hour` in the example above
Dimensionless Constant
----------------------
.. doxygengroup:: scaled-unit-dimensionless
Mass Units
----------
.. doxygengroup:: scaled-unit-mass
Distance Units
--------------
.. doxygengroup:: scaled-unit-distance
Time Units
----------
.. doxygengroup:: scaled-unit-time
Volatility Units
----------------
.. doxygengroup:: scaled-unit-volatility
Miscellaneous Units
-------------------
.. doxygengroup:: scaled-unit-misc

View file

@ -0,0 +1,31 @@
.. _scaled-unit-reference:
Scaled Unit Reference
=====================
A dimensionless multiple of a :doc:`natural_unit<natural-unit-class>`
.. ditaa::
:--scale: 0.85
+----------------+---------------+
| quantity | xquantity |
+----------------+---------------+
|cYEL scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. toctree::
:maxdepth: 1
Scaled Unit Class <scaled-unit-class>
scaled-unit-constants

View file

@ -1,12 +0,0 @@
.. _unit-concept:
Unit Concepts
=============
.. code-block:: cpp
#include <xo/unit/unit_concept.hpp>
.. doxygenconcept:: xo::unit::unit_concept
.. doxygenconcept:: xo::unit::basis_unit_concept

View file

@ -1,93 +0,0 @@
.. _unit-quantities:
.. toctree
:maxdepth: 2
Unit Quantities
===============
Xo-unit uses the type system to represent units.
This is great for eliminating runtime overhead.
One place where we face some awkwardness is conversions involving multiple dimensions.
We'd like to write something concise like
.. code-block:: cpp
meter / (second * second);
The difficulty arises because xo-unit represents `meter` and `second` by types
(``xo::unit::units::meter`` and ``xo::unit::units::second``); operators like `*` and `/`
apply to *values*, not types.
We'll present various ways to express rescaling below
Converting units
----------------
First, xo-unit provides constexpr unit quantities in namespace ``xo::unit::unit_qty``:
.. code-block:: cpp
:linenos:
static constexpr auto meter = qty::meters(1);
static constexpr auto kilometer = qty::kilometers(1);
// etc
Second, a method ``quantity::with_units_from`` that takes units (only) from its argument:
``quantity::with_units_from`` just extracts its argument's unit_type to call ``quantity::with_units``.
.. code-block:: cpp
:linenos:
template <typename Unit, typename Repr>
template <Quantity>
auto quantity<Unit, Repr>::with_units_from(Quantity q) {
return this->with_units<typename Quantity::unit_type>();
}
Motivation is that it's easier to express an argument to `with_units_from`
than to express template arguments to `with_units`.
Prefer
.. code-block:: cpp
:linenos:
:emphasize-lines: 5
namespace u = xo::unit::unit_qty; // u::meter is a value
namespace qty = xo::unit::qty;
auto q1 = qty::kilometers(150.0) / qty::hours(0.5);
auto q2 = q1.with_units_from(u::meter / u::second);
instead of the more verbose:
.. code-block:: cpp
:linenos:
:emphasize-lines: 5-6
namespace u = xo::unit::units; // u::meter is a type
auto q1 = qty::kilometers(150.0) / qty::hours(0.5);
auto q2 = q1.with_units<unit_cartesian_product_t<u::meter,
unit_invert_t<u::second>>>();
Using basis units
-----------------
An alternative way to request multidimensional unit conversion is with basis units
.. code-block:: cpp
:linenos:
:emphasize-lines: 4-5
namespace u = xo::unit::units; // u::meter is a type
auto q1 = qty::kilometers(150.0) / qty::hours(0.5);
auto q2 = q1.with_basis_unit<u::second>(); // q2 in km.s^-1
auto q3 = q2.with_basis_unit<u::meter>(); // q3 in m.s^-1
With this technique we don't have to supply the basis dimension's exponent.
Instead we're just giving scale.

View file

@ -1,10 +0,0 @@
.. _unit-reference:
Unit Reference
==============
.. toctree::
:maxdepth: 2
:caption: Unit Reference
unit-concept

15
docs/xquantity-class.rst Normal file
View file

@ -0,0 +1,15 @@
.. _xquantity-class:
Xquantity
=========
.. code-block:: cpp
#include <xo/unit/xquantity.hpp>
Class
-----
Class with run-time unit representation.
.. doxygenclass:: xo::qty::xquantity

View file

@ -0,0 +1,27 @@
.. _xquantity-reference:
Xquantity Reference
===================
.. ditaa::
+----------------+---------------+
| quantity |cYEL xquantity |
+----------------+---------------+
| scaled_unit |
+--------------------------------+
| natural_unit |
+--------------------------------+
| bpu |
+----------------+ |
| bu_store | |
+----------------+---------------+
| basis_unit |
+--------------------------------+
| dimension |
+--------------------------------+
.. toctree::
:maxdepth: 2
xquantity-class

View file

@ -5,3 +5,5 @@ add_subdirectory(ex4)
add_subdirectory(ex5)
add_subdirectory(ex6)
add_subdirectory(ex7)
add_subdirectory(ex8)
add_subdirectory(ex_su)

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex1)
set(SELF_SRCS ex1.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex2)
set(SELF_SRCS ex2.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex3)
set(SELF_SRCS ex3.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -8,9 +8,7 @@ int
main () {
namespace q = xo::qty::qty;
namespace u = xo::qty::u;
//namespace nu = xo::qty::nu;
using xo::qty::quantity;
using xo::flatstring;
using namespace std;
constexpr quantity<u::second> t = q::minutes(2);

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex4)
set(SELF_SRCS ex4.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -17,7 +17,6 @@ main () {
static_assert(!t2.is_dimensionless());
static_assert(std::same_as<decltype(static_cast<double>(r1)), double>);
//static_assert(std::same_as<decltype(static_cast<double>(t2)), double>);
/* r1_value: assignment compiles, since r1 dimensionless */
double r1_value = r1;

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex5)
set(SELF_SRCS ex5.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex6)
set(SELF_SRCS ex6.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -3,12 +3,10 @@
set(SELF_EXE xo_unit_ex7)
set(SELF_SRCS ex7.cpp)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

View file

@ -0,0 +1,12 @@
# xo-unit/example/ex8/CMakeLists.txt
set(SELF_EXE xo_unit_ex8)
set(SELF_SRCS ex8.cpp)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

29
example/ex8/ex8.cpp Normal file
View file

@ -0,0 +1,29 @@
/** @file ex8.cpp **/
#include "xo/unit/xquantity.hpp"
#include "xo/unit/xquantity_iostream.hpp"
#include <iostream>
int
main () {
using namespace xo::qty;
namespace u = xo::qty::u;
//namespace q = xo::qty::qty;
using namespace std;
xquantity qty1(7, u::foot);
xquantity qty2(6.0, u::inch);
xquantity qty3 = qty1 + qty2;
cerr << "qty1: " << qty1 << endl;
cerr << "qty2: " << qty2 << endl;
cerr << "qty3: " << qty3 << endl;
/* rescale to mm */
xquantity res = qty3.rescale(xo::qty::nu::millimeter);
/* 2286mm */
cerr << "res: " << res << endl;
}
/** end ex8.cpp */

View file

@ -0,0 +1,12 @@
# xo-unit/example/su/CMakeLists.txt
set(SELF_EXE xo_unit_ex_su)
set(SELF_SRCS ex_su.cpp)
if (XO_ENABLE_EXAMPLES)
xo_add_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_headeronly_dependency(${SELF_EXE} xo_unit)
xo_dependency(${SELF_EXE} xo_flatstring)
endif()
# end CMakeLists.txt

38
example/ex_su/ex_su.cpp Normal file
View file

@ -0,0 +1,38 @@
/** @file ex_su.cpp **/
#include "xo/unit/scaled_unit.hpp"
#include "xo/unit/scaled_unit_iostream.hpp"
#include <iostream>
using namespace std;
int
main() {
using namespace xo::qty;
constexpr auto u_prod = u::meter * u::kilometer;
static_assert(u_prod[0].bu() == detail::bu::meter);
static_assert(u_prod[0].power() == power_ratio_type(2));
static_assert(u_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1000));
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
constexpr auto u_div = u::meter / u::kilometer;
static_assert(u_div.n_bpu() == 0);
static_assert(u_div.outer_scale_factor_ == xo::ratio::ratio<int64_t>(1,1000));
static_assert(u_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
constexpr auto u2_prod = u::meter * u::hour * u::kilometer * u::minute;
static_assert(u2_prod.n_bpu() == 2);
static_assert(u2_prod[0].bu() == detail::bu::meter);
static_assert(u2_prod[1].bu() == detail::bu::hour);
// *1000 from converting kilometers -> meters
// /60 from converting minutes -> hours
// 1000/60 = 50/3 in lowest terms
static_assert(u2_prod.outer_scale_factor_ == xo::ratio::ratio<int64_t>(50,3)); // used if fractional dimension
static_assert(u2_prod.outer_scale_sq_ == 1.0); // used if fractional dimension
}
/** end ex_su.cpp **/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,13 +12,15 @@ set(SELF_SRCS
unit.test.cpp #quantity.test.cpp
)
xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS})
if (ENABLE_TESTING)
xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS})
# ----------------------------------------------------------------
# dependencies..
# ----------------------------------------------------------------
# dependencies..
xo_self_dependency(${SELF_EXE} xo_unit)
xo_headeronly_dependency(${SELF_EXE} xo_ratio)
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
xo_self_dependency(${SELF_EXE} xo_unit)
xo_headeronly_dependency(${SELF_EXE} xo_ratio)
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
endif()
# end CMakeLists.txt