Files
mp-units/docs/use_cases/unknown_dimensions.rst
2020-05-13 12:50:14 +02:00

110 lines
4.1 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. namespace:: units
Working with Unknown Dimensions and Their Units
===============================================
From time to time the user of this library will face an `unknown_dimension` and
`unknown_coherent_unit` types. This chapters describes their purpose and usage in
detail.
What is an unknown dimension?
-----------------------------
As we learned in the :ref:`Dimensions` chapter, in most cases the result of multiplying
or dividing two quantities of specific dimensions is a quantity of yet another dimension.
If such a resulting dimension is predefined by the user (and a proper header file with its
definition is included in the current translation unit) :ref:`The Downcasting Facility`
will determine its type. The same applies to the resulting unit. For example:
.. code-block::
:emphasize-lines: 3,7-9
#include <units/physical/si/length.h>
#include <units/physical/si/time.h>
#include <units/physical/si/speed.h>
using namespace units::physical::si;
constexpr auto result = 144q_km / 2q_h;
static_assert(std::is_same_v<decltype(result)::dimension, dim_velocity>);
static_assert(std::is_same_v<decltype(result)::unit, kilometre_per_hour>);
However, if the resulting dimension is not predefined by the user the library framework
will create an instance of an `unknown_dimension`. The coherent unit of such an unknown
dimension is an `unknown_coherent_unit`. Let's see what happens with our example when
we forget to include a header file with the resulting dimension definition:
.. code-block::
:emphasize-lines: 3,9,11
#include <units/physical/si/length.h>
#include <units/physical/si/time.h>
// #include <units/physical/si/speed.h>
using namespace units::physical::si;
constexpr auto result = 144q_km / 2q_h;
static_assert(std::is_same_v<decltype(result)::dimension,
unknown_dimension<exp<dim_length, 1>, exp<dim_time, -1>>>);
static_assert(std::is_same_v<decltype(result)::unit,
scaled_unit<ratio<1, 36, 1>, unknown_coherent_unit>>);
Operations On Unknown Dimensions And Their Units
------------------------------------------------
For some cases we can eliminate the need to predefine a specific dimension and just use
the `unknown_dimension` instead. Let's play with the previous example a bit::
static_assert(result.count() == 72);
As we can see the value stored in this quantity can be easily obtained and contains a
correct result. However, if we try to print its value to the text output we will get::
std::cout << "Speed: " << result << '\n'; // prints 'Speed: 72 [1/36 × 10¹] m/s'
The output from above program should not be a surprise. It is an unknown dimensions with
a scaled unknown coherent unit. The library can't know what is the symbol of such unit
so it does its best and prints the unit in terms of units of base dimensions that formed
this particular unknown derived dimension.
In case we would like to print the result in terms of base units we can simply do the
following::
auto s = quantity_cast<unknown_coherent_unit>(result);
std::cout << "Speed: " << s << '\n'; // prints 'Speed: 20 m/s'
.. seealso::
Another good example of unknown dimension usage can be found in the
:ref:`box_example`::
std::cout << "float rise rate = " << box.fill_level(measured_mass) / fill_time << '\n';
Temporary Results
-----------------
In many cases there is nothing inherently wrong with having unknown dimensions and units
in your program. A typical example here are temporary results of a long calculation:
.. code-block::
:emphasize-lines: 5,7
auto some_long_calculation(Length auto d, Time auto t)
{
Speed auto s1 = avg_speed(d, t);
auto temp1 = s1 * 200q_km; // intermediate unknown dimension
Speed auto s2 = temp1 / 50q_km; // back to known dimensions again
Length auto d2 = s2 * 4q_h;
// ...
}
If a programmer wants to break the calculation to several lines/variables he/she does not
have to ensure that the intermediate results are of predefined dimensions or just a clear
science fiction :-) The final result will always be correct.