mirror of
https://github.com/mpusz/mp-units.git
synced 2025-08-05 13:14:29 +02:00
docs: 📝 dimensionless quantities documentation added
This commit is contained in:
28
docs/faq.rst
28
docs/faq.rst
@@ -28,6 +28,34 @@ different dimensions (i.e. height, width, and depth) all of them will just be
|
||||
measured in meters.
|
||||
|
||||
|
||||
Why a dimensionless quantity is not just an fundamental arithmetic type?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the initial design of this library the resulting type of the division of
|
||||
two quantities was their common representation type::
|
||||
|
||||
static_assert(std::is_same_v<decltype(10q_km / 5q_km), std::int64_t>);
|
||||
|
||||
The reasoning behind it was to not provide a false impression of a strong `quantity` type
|
||||
for something that looks and feels like a regular number. Also all of the mathematic
|
||||
and trigonometric functions were working fine out of the box with such representation
|
||||
types, so we did not have to rewrite ``sin()``, ``cos()``, ``exp()``, and others.
|
||||
|
||||
However, the feedback we got from the production usage was that such an approach
|
||||
is really bad for generic programming. It is really hard to handle the result of
|
||||
division (or multiplication) of two quantities as it might be either a `quantity`
|
||||
or a fundamental type. If we want to raise such a result to some power we have to
|
||||
either use ``units::pow`` or ``std::pow`` depending on the resulting type. Those
|
||||
are only a few from many similar issues related to such an approach.
|
||||
|
||||
This is why it was decided to go with the current approach.
|
||||
|
||||
.. seealso::
|
||||
|
||||
More information on the current design can be found in :ref:`Dimensionless quantities`
|
||||
chapter.
|
||||
|
||||
|
||||
Why do we spell ``metre`` instead of ``meter``?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@@ -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()`!
|
||||
|
@@ -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`.
|
||||
|
Reference in New Issue
Block a user