docs: 📝 dimensionless quantities documentation added

This commit is contained in:
Mateusz Pusz committed 2020-09-08 17:13:38 +02:00
1 parent 8c9986dec8
commit 33ad51311b
3 files changed
+161

No files matched your search

@@ -99,3 +99,80 @@ or a specific target `quantity_point`::
For more information on conversion and casting and on how to extend the above "integral"
vs "floating-point" logic please refer to the :ref:`Using Custom Representation Types`
chapter.
Implicit conversions of dimensionless quantities
------------------------------------------------
As noted in the :ref:`Dimensionless Quantities` chapter, :term:`quantity of dimension one`
is somehow special but still obey most of the rules defined for quantities. However, as they
represent numbers it would be highly uncomfortable to every time type::
const auto d1 = 10q_km;
const auto d2 = 3q_km;
if(d1 / d2 > dimensionless<unitless, 2>) {
// ...
}
or::
const auto fill_time_left = (box.height / box.fill_level(measured_mass) -
dimensionless<unitless, 1>) * fill_time;
This is why it was decided to allow the ``dimensionless<unitless>`` quantity of any
representation type to be implicitly constructible from this representation type.
With that the above examples can be rewritten as follows::
const auto d1 = 10q_km;
const auto d2 = 3q_km;
if(d1 / d2 > 2) {
// ...
}
and::
const auto fill_time_left = (box.height / box.fill_level(measured_mass) - 1) * fill_time;
The above is true only for dimensionless quantities of `unitless` unit. If our quantity have a unit with
ratio different than ``1`` the implicit conversion will not happen. This is to prevent cases were the code
could be ambiguous. For example::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return d1 / d2 + 1;
}
As long as we can reason about what such code means for ``foo(10q_km, 2q_km)`` it is not that obvious
at all in the case of ``foo(10q_cm, 2q_ft)``. To make such code to compile for every case we have to
either change the type of the resulting unit to the one having ``ratio(1)`` (:term:`coherent derived unit`)::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return quantity_cast<unitless>(d1 / d2) + 1;
}
or to explicitly state what is the unit of our dimensionless value, e.g. `unitless`, `percent`, etc::
Dimensionless auto foo(Length auto d1, Length auto d2)
{
return d1 / d2 + dimensionless<unitless>(1);
}
There is one more important point to note here. As the the dimensionless quantity is more than just
a number, it is never implicitly converted back to the representation type. This means that the following
code will not compile::
auto v = std::exp(10q_m / 5q_m);
To make it compile fine we have to either explicitly get the value stored in the quantity::
auto v = std::exp(quantity_cast<unitless>(10q_m / 5q_m).count());
or use a mathematical wrapper function from `units` namespace::
auto v = units::exp(10q_m / 5q_m);
.. important::
Always remember to explicitly cast the quantity to the destination unit with `quantity_cast` before
calling `quantity::count()`!
+56
View File
@@ -157,3 +157,59 @@ but often we would like to know a specific type too. We have two options here:
More information on this subject can be found in :ref:`Conversions and Casting`
chapter.
Dimensionless Quantities
------------------------
Whenever we divide two quantities of the same dimension we end up with a
:term:`dimensionless quantity` otherwise known as :term:`quantity of dimension one`::
static_assert(10q_km / 5q_km == 2);
static_assert(std::is_same_v<decltype(10q_km / 5q_km), quantity<dim_one, unitless, std::int64_t>>);
According to the official ISO definition `dim_one` is a dimension "for which all the
exponents of the factors corresponding to the base quantities in its quantity dimension
are zero".
.. seealso::
Reasoning for the above design is provided in
:ref:`Why a dimensionless quantity is not just an fundamental arithmetic type?`
To simplify the usage of the dimensionless quantity a following concept and alias template
are provided::
template<typename T>
concept Dimensionless = QuantityOf<T, dim_one>;
template<Unit U, Scalar Rep = double>
using dimensionless = quantity<dim_one, U, Rep>;
There are two special units provided for usage with such a quantity:
- `unitless` which is the :ref:`coherent unit` of dimensionless quantity and does not
provide any textual symbol (according to the ISO definition "the measurement units and
values of quantities of dimension one are numbers"),
- `percent` which has the symbol ``%`` and ``ratio(1, 100)`` of the `unitless` unit.
For example the following code::
std::cout << quantity_cast<percent>(50.q_m / 100.q_m) << '\n';
will print ``50 %`` to the console output.
Again, according to the ISO definition "such quantities convey more information than a
number". This is exactly what we observe in the above example. The value stored inside
the quantity, the text output, and the value returned by the `quantity::count()` member
function is ``50`` rather than ``0.5``. It means that dimensionless quantities behave
like all other quantities and store the value in terms of a ratio of a coherent unit.
This allows us to not loose precision when we divide quantities of the same dimensions
but with units having vastly different ratios, e.g.
`Dimensionless Hubble parameter <https://en.wikipedia.org/wiki/Hubble%27s_law#Dimensionless_Hubble_parameter>`_
is expressed as a ratio of kilometers and megaparsecs.
.. seealso::
More information on dimensionless quantities can be found in
:ref:`Implicit conversions of dimensionless quantities`.