Let's continue the previous example. This time, our purpose will not be to showcase as many
library features as possible, but we will scope on different interfaces one can provide
with the mp-units. We will also describe some advantages and disadvantages of presented
solutions.
First, we either import a module or include all the necessary header files and import all
the identifiers from the mp_units namespace:
Next, we define two functions calculating average speed based on quantities of fixed units
and integral and floating-point representation types, respectively, and a third function
that we introduced in the previous example:
template<QuantityOf<isq::length>D,QuantityOf<isq::time>T,QuantityOf<isq::speed>V>voidprint_result(Ddistance,Tduration,Vspeed){constautoresult_in_kmph=speed.force_in(si::kilo<si::metre>/non_si::hour);std::cout<<"Average speed of a car that makes "<<distance<<" in "<<duration<<" is "<<result_in_kmph<<".\n";}
Now, let's analyze how those three utility functions behave with different sets of arguments.
First, we are going to use quantities of SI units and integral representation:
voidexample(){usingnamespacemp_units::si::unit_symbols;// SI (int){constexprautodistance=220*km;constexprautoduration=2*h;std::cout<<"SI units with 'int' as representation\n";print_result(distance,duration,fixed_int_si_avg_speed(distance,duration));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}
The above provides the following output:
SI units with 'int' as representation
Average speed of a car that makes 220 km in 2 h is 108 km/h.
Average speed of a car that makes 220 km in 2 h is 110 km/h.
Average speed of a car that makes 220 km in 2 h is 110 km/h.
Please note that in the first two cases, we must convert length from km to m and
time from h to s. The converted values are used to calculate speed in m/s which
is then again converted to the one in km/h. Those conversions not only impact the
application's runtime performance but may also affect the precision of the final result.
Such truncation can be easily observed in the first case where we deal with integral
representation types (the resulting speed is 108 km/h).
The second scenario is really similar to the previous one, but this time, function arguments
have floating-point representation types:
// SI (double){constexprautodistance=220.*km;constexprautoduration=2.*h;std::cout<<"\nSI units with 'double' as representation\n";// conversion from a floating-point to an integral type is a truncating one so an explicit cast is neededprint_result(distance,duration,fixed_int_si_avg_speed(value_cast<int>(distance),value_cast<int>(duration)));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}
Conversion from floating-point to integral representation types is
considered value-truncating
and that is why now, in the first case, we need an explicit call to value_cast<int>.
In the text output, we can observe that, again, the resulting value gets truncated during conversions
in the first cast:
SI units with 'double' as representation
Average speed of a car that makes 220 km in 2 h is 108 km/h.
Average speed of a car that makes 220 km in 2 h is 110 km/h.
Average speed of a car that makes 220 km in 2 h is 110 km/h.
Next, let's do the same for integral and floating-point representations, but this time
using international mile:
// International mile (int){usingnamespacemp_units::international::unit_symbols;constexprautodistance=140*mi;constexprautoduration=2*h;std::cout<<"\nInternational mile with 'int' as representation\n";// it is not possible to make a lossless conversion of miles to meters on an integral type// (explicit cast needed)print_result(distance,duration,fixed_int_si_avg_speed(distance.force_in(m),duration));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}// International mile (double){usingnamespacemp_units::international::unit_symbols;constexprautodistance=140.*mi;constexprautoduration=2.*h;std::cout<<"\nInternational mile with 'double' as representation\n";// conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed// also it is not possible to make a lossless conversion of miles to meters on an integral type// (explicit cast needed)print_result(distance,duration,fixed_int_si_avg_speed(value_cast<m,int>(distance),value_cast<int>(duration)));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}
One important difference here is the fact that as it is not possible to make a lossless conversion
of miles to meters on a quantity using an integral representation type, so this time, we need a
value_cast<m, int> to force it.
If we check the text output of the above, we will see the following:
International mile with 'int' as representation
Average speed of a car that makes 140 mi in 2 h is 111 km/h.
Average speed of a car that makes 140 mi in 2 h is 112.654 km/h.
Average speed of a car that makes 140 mi in 2 h is 112 km/h.
International mile with 'double' as representation
Average speed of a car that makes 140 mi in 2 h is 111 km/h.
Average speed of a car that makes 140 mi in 2 h is 112.654 km/h.
Average speed of a car that makes 140 mi in 2 h is 112.654 km/h.
Please note how the first and third results get truncated using integral representation types.
// CGS (int){constexprautodistance=22'000'000*cgs::centimetre;constexprautoduration=7200*cgs::second;std::cout<<"\nCGS units with 'int' as representation\n";// it is not possible to make a lossless conversion of centimeters to meters on an integral type// (explicit cast needed)print_result(distance,duration,fixed_int_si_avg_speed(distance.force_in(m),duration));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}// CGS (double){constexprautodistance=22'000'000.*cgs::centimetre;constexprautoduration=7200.*cgs::second;std::cout<<"\nCGS units with 'double' as representation\n";// conversion from a floating-point to an integral type is a truncating one so an explicit cast is needed// it is not possible to make a lossless conversion of centimeters to meters on an integral type// (explicit cast needed)print_result(distance,duration,fixed_int_si_avg_speed(value_cast<m,int>(distance),value_cast<int>(duration)));print_result(distance,duration,fixed_double_si_avg_speed(distance,duration));print_result(distance,duration,avg_speed(distance,duration));}}}// namespace
Again, we observe value_cast being used in the same places and consistent truncation errors
in the text output:
CGS units with 'int' as representation
Average speed of a car that makes 22000000 cm in 7200 s is 108 km/h.
Average speed of a car that makes 22000000 cm in 7200 s is 110 km/h.
Average speed of a car that makes 22000000 cm in 7200 s is 109 km/h.
CGS units with 'double' as representation
Average speed of a car that makes 2.2e+07 cm in 7200 s is 108 km/h.
Average speed of a car that makes 2.2e+07 cm in 7200 s is 110 km/h.
Average speed of a car that makes 2.2e+07 cm in 7200 s is 110 km/h.
The example file ends with a simple main() function: