forked from mpusz/mp-units
110 lines
4.1 KiB
ReStructuredText
110 lines
4.1 KiB
ReStructuredText
.. 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.
|