Examples with an alternate way to create quantities refactored

- examples modified to provide a unified library look-and-feel
- originals moved to a dedicated subdirectory for further reference and comparison
This commit is contained in:
Mateusz Pusz
2020-03-01 14:44:45 +01:00
parent 0c5864cc87
commit 4b33c0f7c5
10 changed files with 644 additions and 259 deletions

View File

@ -35,3 +35,5 @@ add_example(capacitor_time_curve)
add_example(clcpp_response) add_example(clcpp_response)
add_example(conversion_factor) add_example(conversion_factor)
add_example(kalman_filter-alpha_beta_filter_example2) add_example(kalman_filter-alpha_beta_filter_example2)
add_subdirectory(alternative_namespaces)

View File

@ -0,0 +1,31 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
function(add_example target)
add_executable(${target}_alt ${target}.cpp)
target_link_libraries(${target}_alt PRIVATE mp::units)
endfunction()
add_example(box_example)
add_example(capacitor_time_curve)
add_example(clcpp_response)
add_example(conversion_factor)

View File

@ -0,0 +1,118 @@
#include <units/physical/si/acceleration.h>
#include <units/physical/si/density.h>
#include <units/physical/si/force.h>
#include <units/physical/si/length.h>
#include <units/physical/si/mass.h>
#include <units/physical/si/time.h>
#include <units/physical/si/volume.h>
#include <cassert>
namespace {
namespace length {
template<typename Rep = double>
using m = units::si::length<units::si::metre, Rep>;
template<typename Rep = double>
using mm = units::si::length<units::si::millimetre, Rep>;
} // namespace length
namespace acceleration {
template<typename Rep = double>
using mps2 = units::si::acceleration<units::si::metre_per_second_sq, Rep>;
template<typename Rep = double>
constexpr mps2<> g{static_cast<Rep>(9.80665)};
} // namespace acceleration
namespace force {
template<typename Rep = double>
using N = units::si::force<units::si::newton, Rep>;
}
namespace mass {
template<typename Rep = double>
using kg = units::si::mass<units::si::kilogram, Rep>;
}
namespace density {
template<typename Rep = double>
using kgpm3 = units::si::density<units::si::kilogram_per_metre_cub, Rep>;
}
namespace volume {
template<typename Rep = double>
using m3 = units::si::volume<units::si::cubic_metre, Rep>;
}
} // namespace
struct Box {
static constexpr density::kgpm3<> air_density{1.225};
length::m<> length;
length::m<> width;
length::m<> height;
struct contents {
density::kgpm3<> density = air_density;
} contents;
Box(const length::m<>& l, const length::m<>& w, const length::m<>& h) : length{l}, width{w}, height{h} {}
force::N<> filled_weight() const
{
const volume::m3<> volume = length * width * height;
const mass::kg<> mass = contents.density * volume;
return mass * acceleration::g<>;
}
length::m<> fill_level(const mass::kg<>& measured_mass) const
{
return height * (measured_mass * acceleration::g<>) / filled_weight();
}
volume::m3<> spare_capacity(const mass::kg<>& measured_mass) const
{
return (height - fill_level(measured_mass)) * width * length;
}
void set_contents_density(const density::kgpm3<>& density_in)
{
assert(density_in > air_density);
contents.density = density_in;
}
};
#include <iostream>
using namespace units::si::literals;
int main()
{
auto box = Box{1000.0q_mm, 500.0q_mm, 200.0q_mm};
box.set_contents_density(1000.0q_kgpm3);
auto fill_time = 200.0q_s; // time since starting fill
auto measured_mass = 20.0q_kg; // measured mass at fill_time
std::cout << "mpusz/units box example...\n";
std::cout << "fill height at " << fill_time << " = " << box.fill_level(measured_mass) << " ("
<< (box.fill_level(measured_mass) / box.height) * 100 << "% full)\n";
std::cout << "spare_capacity at " << fill_time << " = " << box.spare_capacity(measured_mass) << '\n';
std::cout << "input flow rate after " << fill_time << " = " << measured_mass / fill_time << '\n';
std::cout << "float rise rate = " << box.fill_level(measured_mass) / fill_time << '\n';
auto fill_time_left = (box.height / box.fill_level(measured_mass) - 1) * fill_time;
std::cout << "box full E.T.A. at current flow rate = " << fill_time_left << '\n';
}

View File

@ -0,0 +1,80 @@
/*
Copyright (c) 2003-2020 Andy Little.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses./
*/
/*
capacitor discharge curve using compile_time
physical_quantities
*/
#include <units/physical/si/capacitance.h>
#include <units/physical/si/resistance.h>
#include <units/physical/si/time.h>
#include <units/physical/si/voltage.h>
#include <cmath>
#include <iostream>
namespace {
namespace voltage {
template<typename Rep = double>
using V = units::si::voltage<units::si::volt, Rep>;
template<typename Rep = double>
using mV = units::si::voltage<units::si::millivolt, Rep>;
template<typename Rep = double>
using uV = units::si::voltage<units::si::microvolt, Rep>;
template<typename Rep = double>
using nV = units::si::voltage<units::si::nanovolt, Rep>;
template<typename Rep = double>
using pV = units::si::voltage<units::si::picovolt, Rep>;
} // namespace voltage
} // namespace
using namespace units::si::literals;
int main()
{
std::cout << "mpusz/units capacitor time curve example...\n";
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout.precision(3);
constexpr auto C = 0.47q_uF;
constexpr auto V0 = 5.0q_V;
constexpr auto R = 4.7q_kR;
for (auto t = 0q_ms; t <= 50q_ms; ++t) {
const auto Vt = V0 * std::exp(-t / (R * C));
std::cout << "at " << t << " voltage is ";
if (Vt >= 1q_V)
std::cout << Vt;
else if (Vt >= 1q_mV)
std::cout << voltage::mV<>{Vt};
else if (Vt >= 1q_uV)
std::cout << voltage::uV<>{Vt};
else if (Vt >= 1q_nV)
std::cout << voltage::nV<>{Vt};
else
std::cout << voltage::pV<>{Vt};
std::cout << "\n";
}
}

View File

@ -0,0 +1,236 @@
/*
Copyright (c) 2003-2019 Andy Little.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses./
*/
#include <units/physical/iau/length.h>
#include <units/physical/imperial/length.h>
#include <units/physical/international/length.h>
#include <units/physical/si/area.h>
#include <units/physical/si/length.h>
#include <units/physical/si/time.h>
#include <units/physical/si/volume.h>
#include <units/physical/typographic/length.h>
#include <units/physical/us/length.h>
#include <iostream>
namespace {
namespace length {
template<typename Rep = double>
using m = units::si::length<units::si::metre, Rep>;
template<typename Rep = double>
using mm = units::si::length<units::si::millimetre, Rep>;
template<typename Rep = double>
using fm = units::si::length<units::si::femtometre, Rep>;
template<typename Rep = double>
using km = units::si::length<units::si::kilometre, Rep>;
template<typename Rep = double>
using AU = units::si::length<units::si::astronomical_unit, Rep>;
template<typename Rep = double>
using in = units::si::length<units::international::inch, Rep>;
template<typename Rep = double>
using angstrom = units::si::length<units::iau::angstrom, Rep>;
template<typename Rep = double>
using ch = units::si::length<units::imperial::chain, Rep>;
template<typename Rep = double>
using fathom = units::si::length<units::international::fathom, Rep>;
template<typename Rep = double>
using fathom_us = units::si::length<units::us::fathom, Rep>;
template<typename Rep = double>
using ft = units::si::length<units::international::foot, Rep>;
template<typename Rep = double>
using ft_us = units::si::length<units::us::foot, Rep>;
template<typename Rep = double>
using ly = units::si::length<units::iau::light_year, Rep>;
template<typename Rep = double>
using mi = units::si::length<units::international::mile, Rep>;
template<typename Rep = double>
using mi_naut = units::si::length<units::international::nautical_mile, Rep>;
template<typename Rep = double>
using pc = units::si::length<units::iau::parsec, Rep>;
template<typename Rep = double>
using pica_comp = units::si::length<units::typographic::pica_comp, Rep>;
template<typename Rep = double>
using pica_prn = units::si::length<units::typographic::pica_prn, Rep>;
template<typename Rep = double>
using point_comp = units::si::length<units::typographic::point_comp, Rep>;
template<typename Rep = double>
using point_prn = units::si::length<units::typographic::point_prn, Rep>;
template<typename Rep = double>
using rd = units::si::length<units::imperial::rod, Rep>;
template<typename Rep = double>
using yd = units::si::length<units::international::yard, Rep>;
} // namespace length
namespace time {
template<typename Rep = double>
using s = units::si::time<units::si::second, Rep>;
template<typename Rep = double>
using min = units::si::time<units::si::minute, Rep>;
template<typename Rep = double>
using h = units::si::time<units::si::hour, Rep>;
} // namespace time
namespace area {
template<typename Rep = double>
using m2 = units::si::area<units::si::square_metre, Rep>;
template<typename Rep = double>
using fm2 = units::si::area<units::si::square_femtometre, Rep>;
} // namespace area
} // namespace
using namespace units::si::literals;
using namespace units::international;
void simple_quantities()
{
using distance = length::m<>;
using time = time::s<>;
constexpr distance km = 1.0q_km;
constexpr distance miles = 1.0q_mi;
constexpr time sec = 1q_s;
constexpr time min = 1q_min;
constexpr time hr = 1q_h;
std::cout << "A physical quantities library can choose the simple\n";
std::cout << "option to provide output using a single type for each base unit:\n\n";
std::cout << km << '\n';
std::cout << miles << '\n';
std::cout << sec << '\n';
std::cout << min << '\n';
std::cout << hr << "\n\n";
}
void quantities_with_typed_units()
{
constexpr length::km<> km = 1.0q_km;
constexpr length::mi<> miles = 1.0q_mi;
std::cout.precision(6);
constexpr time::s<> sec = 1q_s;
constexpr time::min<> min = 1q_min;
constexpr time::h<> hr = 1q_h;
std::cout << "A more flexible option is to provide separate types for each unit,\n\n";
std::cout << km << '\n';
std::cout << miles << '\n';
std::cout << sec << '\n';
std::cout << min << '\n';
std::cout << hr << "\n\n";
constexpr length::m<> meter = 1q_m;
std::cout << "then a wide range of pre-defined units can be defined and converted,\n"
" for consistency and repeatability across applications:\n\n";
std::cout << meter << '\n';
std::cout << " = " << length::AU<>(meter) << '\n';
std::cout << " = " << length::angstrom<>(meter) << '\n';
std::cout << " = " << length::ch<>(meter) << '\n';
std::cout << " = " << length::fathom<>(meter) << '\n';
std::cout << " = " << length::fathom_us<>(meter) << '\n';
std::cout << " = " << length::ft<>(meter) << '\n';
std::cout << " = " << length::ft_us<>(meter) << '\n';
std::cout << " = " << length::in<>(meter) << '\n';
std::cout << " = " << length::ly<>(meter) << '\n';
std::cout << " = " << length::mi<>(meter) << '\n';
std::cout << " = " << length::mi_naut<>(meter) << '\n';
std::cout << " = " << length::pc<>(meter) << '\n';
std::cout << " = " << length::pica_comp<>(meter) << '\n';
std::cout << " = " << length::pica_prn<>(meter) << '\n';
std::cout << " = " << length::point_comp<>(meter) << '\n';
std::cout << " = " << length::point_prn<>(meter) << '\n';
std::cout << " = " << length::rd<>(meter) << '\n';
std::cout << " = " << length::yd<>(meter) << '\n';
}
void calcs_comparison()
{
std::cout.precision(20);
std::cout << "\nA distinct unit for each type is efficient and accurate\n"
"when adding two values of the same very big\n"
"or very small type:\n\n";
length::fm<float> L1A = 2q_fm;
length::fm<float> L2A = 3q_fm;
length::fm<float> LrA = L1A + L2A;
std::cout << L1A << " + " << L2A << " = " << LrA << "\n\n";
std::cout << "The single unit method must convert large\n"
"or small values in other units to the base unit.\n"
"This is both inefficient and inaccurate\n\n";
length::m<float> L1B = L1A;
length::m<float> L2B = L2A;
length::m<float> LrB = L1B + L2B;
std::cout << L1B << " + " << L2B << " = " << LrB << "\n\n";
std::cout << "In multiplication and division:\n\n";
area::fm2<float> ArA = L1A * L2A;
std::cout << L1A << " * " << L2A << " = " << ArA << "\n\n";
std::cout << "similar problems arise\n\n";
area::m2<float> ArB = L1B * L2B;
std::cout << L1B << " * " << L2B << "\n = " << ArB << '\n';
}
int main()
{
std::cout << "This demo was originally posted on com.lang.c++.moderated in 2006\n";
std::cout << "http://compgroups.net/comp.lang.c++.moderated/dimensional-analysis-units/51712\n";
std::cout << "Here converted to use mpusz/units library.\n\n";
simple_quantities();
quantities_with_typed_units();
calcs_comparison();
}

View File

@ -0,0 +1,79 @@
/*
Copyright (c) 2003-2020 Andy Little.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses./
*/
#include <units/physical/si/length.h>
#include <iostream>
/*
get conversion factor from one dimensionally equivalent
quantity type to another
*/
namespace {
template<units::Quantity Target, units::Quantity Source>
requires units::equivalent_dim<typename Source::dimension, typename Target::dimension>
inline constexpr std::common_type_t<typename Target::rep, typename Source::rep> conversion_factor(Target, Source)
{
// get quantities looking like inputs but with Q::rep that doesn't have narrowing conversion
typedef std::common_type_t<typename Target::rep, typename Source::rep> rep;
typedef units::quantity<typename Source::dimension, typename Source::unit, rep> source;
typedef units::quantity<typename Target::dimension, typename Target::unit, rep> target;
return target{source{1}}.count();
}
// get at the units text of the quantity, without its numeric value
inline auto constexpr units_str(const units::Quantity AUTO& q)
{
typedef std::remove_cvref_t<decltype(q)> qtype;
return units::detail::unit_text<typename qtype::dimension, typename qtype::unit>();
}
} // namespace
namespace {
namespace length {
template<typename Rep = double>
using m = units::si::length<units::si::metre, Rep>;
template<typename Rep = double>
using mm = units::si::length<units::si::millimetre, Rep>;
} // namespace length
} // namespace
using namespace units::si::literals;
int main()
{
std::cout << "conversion factor in mpusz/units...\n\n";
constexpr length::m<> lengthA = 2.0q_m;
constexpr length::mm<> lengthB = lengthA;
std::cout << "lengthA( " << lengthA << " ) and lengthB( " << lengthB << " )\n"
<< "represent the same length in different units.\n\n";
std::cout << "therefore ratio lengthA / lengthB == " << lengthA / lengthB << "\n\n";
std::cout << "conversion factor from lengthA::unit of "
<< units_str(lengthA) << " to lengthB::unit of " << units_str(lengthB) << " :\n\n"
<< "lengthB.count( " << lengthB.count() << " ) == lengthA.count( " << lengthA.count()
<< " ) * conversion_factor( " << conversion_factor(lengthB, lengthA) << " )\n";
}

View File

@ -1,118 +1,82 @@
#include <units/physical/si/acceleration.h> #include <units/physical/si/acceleration.h>
#include <units/physical/si/constants.h>
#include <units/physical/si/density.h> #include <units/physical/si/density.h>
#include <units/physical/si/force.h> #include <units/physical/si/force.h>
#include <units/physical/si/length.h> #include <units/physical/si/length.h>
#include <units/physical/si/mass.h> #include <units/physical/si/mass.h>
#include <units/physical/si/time.h> #include <units/physical/si/time.h>
#include <units/physical/si/volume.h> #include <units/physical/si/volume.h>
#include <units/format.h>
#include <cassert> #include <cassert>
namespace { namespace {
namespace length { using namespace units;
using namespace units::si::literals;
template<typename Rep = double> using m = si::metre;
using m = units::si::length<units::si::metre, Rep>; using kg = si::kilogram;
using N = si::newton;
using m3 = si::cubic_metre;
using kgpm3 = si::kilogram_per_metre_cub;
template<typename Rep = double> inline constexpr auto g = si::standard_gravity;
using mm = units::si::length<units::si::millimetre, Rep>;
} // namespace length
namespace acceleration {
template<typename Rep = double>
using mps2 = units::si::acceleration<units::si::metre_per_second_sq, Rep>;
template<typename Rep = double>
constexpr mps2<> g{static_cast<Rep>(9.80665)};
} // namespace acceleration
namespace force {
template<typename Rep = double>
using N = units::si::force<units::si::newton, Rep>;
}
namespace mass {
template<typename Rep = double>
using kg = units::si::mass<units::si::kilogram, Rep>;
}
namespace density {
template<typename Rep = double>
using kgpm3 = units::si::density<units::si::kilogram_per_metre_cub, Rep>;
}
namespace volume {
template<typename Rep = double>
using m3 = units::si::volume<units::si::cubic_metre, Rep>;
}
} // namespace } // namespace
struct Box { struct Box {
static constexpr density::kgpm3<> air_density{1.225}; static constexpr auto air_density = 1.225q_kgpm3;
length::m<> length; si::length<m> length;
length::m<> width; si::length<m> width;
length::m<> height; si::length<m> height;
struct contents { struct contents {
density::kgpm3<> density = air_density; si::density<kgpm3> density = air_density;
} contents; } contents;
Box(const length::m<>& l, const length::m<>& w, const length::m<>& h) : length{l}, width{w}, height{h} {} constexpr Box(const si::length<m>& l, const si::length<m>& w, const si::length<m>& h) : length{l}, width{w}, height{h} {}
force::N<> filled_weight() const constexpr si::force<N> filled_weight() const
{ {
const volume::m3<> volume = length * width * height; const si::volume<m3> volume = length * width * height;
const mass::kg<> mass = contents.density * volume; const si::mass<kg> mass = contents.density * volume;
return mass * acceleration::g<>; return mass * g;
} }
length::m<> fill_level(const mass::kg<>& measured_mass) const constexpr si::length<m> fill_level(const si::mass<kg>& measured_mass) const
{ {
return height * (measured_mass * acceleration::g<>) / filled_weight(); return height * (measured_mass * g) / filled_weight();
} }
volume::m3<> spare_capacity(const mass::kg<>& measured_mass) const constexpr si::volume<m3> spare_capacity(const si::mass<kg>& measured_mass) const
{ {
return (height - fill_level(measured_mass)) * width * length; return (height - fill_level(measured_mass)) * width * length;
} }
void set_contents_density(const density::kgpm3<>& density_in) constexpr void set_contents_density(const si::density<kgpm3>& density_in)
{ {
assert(density_in > air_density); assert(density_in > air_density);
contents.density = density_in; contents.density = density_in;
} }
}; };
#include <iostream> #include <iostream>
using namespace units::si::literals;
int main() int main()
{ {
auto box = Box{1000.0q_mm, 500.0q_mm, 200.0q_mm}; auto box = Box(1000.0q_mm, 500.0q_mm, 200.0q_mm);
box.set_contents_density(1000.0q_kgpm3); box.set_contents_density(1000.0q_kgpm3);
auto fill_time = 200.0q_s; // time since starting fill const auto fill_time = 200.0q_s; // time since starting fill
auto measured_mass = 20.0q_kg; // measured mass at fill_time const auto measured_mass = 20.0q_kg; // measured mass at fill_time
std::cout << "mpusz/units box example...\n"; std::cout << "mp-units box example...\n";
std::cout << "fill height at " << fill_time << " = " << box.fill_level(measured_mass) << " (" std::cout << "fill height at " << fill_time << " = " << box.fill_level(measured_mass) << " ("
<< (box.fill_level(measured_mass) / box.height) * 100 << "% full)\n"; << (box.fill_level(measured_mass) / box.height) * 100 << "% full)\n";
std::cout << "spare_capacity at " << fill_time << " = " << box.spare_capacity(measured_mass) << '\n'; std::cout << "spare_capacity at " << fill_time << " = " << box.spare_capacity(measured_mass) << '\n';
std::cout << "input flow rate after " << fill_time << " = " << measured_mass / fill_time << '\n'; std::cout << "input flow rate after " << fill_time << " = " << measured_mass / fill_time << '\n';
std::cout << "float rise rate = " << box.fill_level(measured_mass) / fill_time << '\n'; std::cout << "float rise rate = " << box.fill_level(measured_mass) / fill_time << '\n';
auto fill_time_left = (box.height / box.fill_level(measured_mass) - 1) * fill_time; const auto fill_time_left = (box.height / box.fill_level(measured_mass) - 1) * fill_time;
std::cout << "box full E.T.A. at current flow rate = " << fill_time_left << '\n'; std::cout << "box full E.T.A. at current flow rate = " << fill_time_left << '\n';
} }

View File

@ -27,32 +27,12 @@
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
namespace {
namespace voltage {
template<typename Rep = double>
using V = units::si::voltage<units::si::volt, Rep>;
template<typename Rep = double>
using mV = units::si::voltage<units::si::millivolt, Rep>;
template<typename Rep = double>
using uV = units::si::voltage<units::si::microvolt, Rep>;
template<typename Rep = double>
using nV = units::si::voltage<units::si::nanovolt, Rep>;
template<typename Rep = double>
using pV = units::si::voltage<units::si::picovolt, Rep>;
} // namespace voltage
} // namespace
using namespace units::si::literals;
int main() int main()
{ {
std::cout << "mpusz/units capacitor time curve example...\n"; using namespace units;
using namespace units::si;
std::cout << "mp-units capacitor time curve example...\n";
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield); std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout.precision(3); std::cout.precision(3);
@ -61,20 +41,20 @@ int main()
constexpr auto R = 4.7q_kR; constexpr auto R = 4.7q_kR;
for (auto t = 0q_ms; t <= 50q_ms; ++t) { for (auto t = 0q_ms; t <= 50q_ms; ++t) {
const auto Vt = V0 * std::exp(-t / (R * C)); const Voltage auto Vt = V0 * std::exp(-t / (R * C));
std::cout << "at " << t << " voltage is "; std::cout << "at " << t << " voltage is ";
if (Vt >= 1q_V) if (Vt >= 1q_V)
std::cout << Vt; std::cout << Vt;
else if (Vt >= 1q_mV) else if (Vt >= 1q_mV)
std::cout << voltage::mV<>{Vt}; std::cout << quantity_cast<millivolt>(Vt);
else if (Vt >= 1q_uV) else if (Vt >= 1q_uV)
std::cout << voltage::uV<>{Vt}; std::cout << quantity_cast<microvolt>(Vt);
else if (Vt >= 1q_nV) else if (Vt >= 1q_nV)
std::cout << voltage::nV<>{Vt}; std::cout << quantity_cast<nanovolt>(Vt);
else else
std::cout << voltage::pV<>{Vt}; std::cout << quantity_cast<picovolt>(Vt);
std::cout << "\n"; std::cout << "\n";
} }
} }

View File

@ -27,115 +27,23 @@
#include <iostream> #include <iostream>
namespace { namespace {
namespace length {
template<typename Rep = double> using namespace units;
using m = units::si::length<units::si::metre, Rep>;
template<typename Rep = double>
using mm = units::si::length<units::si::millimetre, Rep>;
template<typename Rep = double>
using fm = units::si::length<units::si::femtometre, Rep>;
template<typename Rep = double>
using km = units::si::length<units::si::kilometre, Rep>;
template<typename Rep = double>
using AU = units::si::length<units::si::astronomical_unit, Rep>;
template<typename Rep = double>
using in = units::si::length<units::international::inch, Rep>;
template<typename Rep = double>
using angstrom = units::si::length<units::iau::angstrom, Rep>;
template<typename Rep = double>
using ch = units::si::length<units::imperial::chain, Rep>;
template<typename Rep = double>
using fathom = units::si::length<units::international::fathom, Rep>;
template<typename Rep = double>
using fathom_us = units::si::length<units::us::fathom, Rep>;
template<typename Rep = double>
using ft = units::si::length<units::international::foot, Rep>;
template<typename Rep = double>
using ft_us = units::si::length<units::us::foot, Rep>;
template<typename Rep = double>
using ly = units::si::length<units::iau::light_year, Rep>;
template<typename Rep = double>
using mi = units::si::length<units::international::mile, Rep>;
template<typename Rep = double>
using mi_naut = units::si::length<units::international::nautical_mile, Rep>;
template<typename Rep = double>
using pc = units::si::length<units::iau::parsec, Rep>;
template<typename Rep = double>
using pica_comp = units::si::length<units::typographic::pica_comp, Rep>;
template<typename Rep = double>
using pica_prn = units::si::length<units::typographic::pica_prn, Rep>;
template<typename Rep = double>
using point_comp = units::si::length<units::typographic::point_comp, Rep>;
template<typename Rep = double>
using point_prn = units::si::length<units::typographic::point_prn, Rep>;
template<typename Rep = double>
using rd = units::si::length<units::imperial::rod, Rep>;
template<typename Rep = double>
using yd = units::si::length<units::international::yard, Rep>;
} // namespace length
namespace time {
template<typename Rep = double>
using s = units::si::time<units::si::second, Rep>;
template<typename Rep = double>
using min = units::si::time<units::si::minute, Rep>;
template<typename Rep = double>
using h = units::si::time<units::si::hour, Rep>;
} // namespace time
namespace area {
template<typename Rep = double>
using m2 = units::si::area<units::si::square_metre, Rep>;
template<typename Rep = double>
using fm2 = units::si::area<units::si::square_femtometre, Rep>;
} // namespace area
} // namespace
using namespace units::si::literals;
using namespace units::international;
void simple_quantities() void simple_quantities()
{ {
using distance = length::m<>; using namespace units::si;
using time = time::s<>; using namespace units::international;
using distance = length<metre>;
using duration = si::time<second>;
constexpr distance km = 1.0q_km; constexpr distance km = 1.0q_km;
constexpr distance miles = 1.0q_mi; constexpr distance miles = 1.0q_mi;
constexpr time sec = 1q_s; constexpr duration sec = 1q_s;
constexpr time min = 1q_min; constexpr duration min = 1q_min;
constexpr time hr = 1q_h; constexpr duration hr = 1q_h;
std::cout << "A physical quantities library can choose the simple\n"; std::cout << "A physical quantities library can choose the simple\n";
std::cout << "option to provide output using a single type for each base unit:\n\n"; std::cout << "option to provide output using a single type for each base unit:\n\n";
@ -148,14 +56,17 @@ void simple_quantities()
void quantities_with_typed_units() void quantities_with_typed_units()
{ {
constexpr length::km<> km = 1.0q_km; using namespace units::si;
constexpr length::mi<> miles = 1.0q_mi; using namespace units::international;
constexpr length<kilometre> km = 1.0q_km;
constexpr length<mile> miles = 1.0q_mi;
std::cout.precision(6); std::cout.precision(6);
constexpr time::s<> sec = 1q_s; constexpr si::time<second> sec = 1q_s;
constexpr time::min<> min = 1q_min; constexpr si::time<minute> min = 1q_min;
constexpr time::h<> hr = 1q_h; constexpr si::time<hour> hr = 1q_h;
std::cout << "A more flexible option is to provide separate types for each unit,\n\n"; std::cout << "A more flexible option is to provide separate types for each unit,\n\n";
std::cout << km << '\n'; std::cout << km << '\n';
@ -164,42 +75,44 @@ void quantities_with_typed_units()
std::cout << min << '\n'; std::cout << min << '\n';
std::cout << hr << "\n\n"; std::cout << hr << "\n\n";
constexpr length::m<> meter = 1q_m; constexpr length<metre> meter = 1q_m;
std::cout << "then a wide range of pre-defined units can be defined and converted,\n" std::cout << "then a wide range of pre-defined units can be defined and converted,\n"
" for consistency and repeatability across applications:\n\n"; " for consistency and repeatability across applications:\n\n";
std::cout << meter << '\n'; std::cout << meter << '\n';
std::cout << " = " << length::AU<>(meter) << '\n'; std::cout << " = " << quantity_cast<si::astronomical_unit>(meter) << '\n';
std::cout << " = " << length::angstrom<>(meter) << '\n'; std::cout << " = " << quantity_cast<iau::angstrom>(meter) << '\n';
std::cout << " = " << length::ch<>(meter) << '\n'; std::cout << " = " << quantity_cast<imperial::chain>(meter) << '\n';
std::cout << " = " << length::fathom<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::fathom>(meter) << '\n';
std::cout << " = " << length::fathom_us<>(meter) << '\n'; std::cout << " = " << quantity_cast<us::fathom>(meter) << '\n';
std::cout << " = " << length::ft<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::foot>(meter) << '\n';
std::cout << " = " << length::ft_us<>(meter) << '\n'; std::cout << " = " << quantity_cast<us::foot>(meter) << '\n';
std::cout << " = " << length::in<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::inch>(meter) << '\n';
std::cout << " = " << length::ly<>(meter) << '\n'; std::cout << " = " << quantity_cast<iau::light_year>(meter) << '\n';
std::cout << " = " << length::mi<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::mile>(meter) << '\n';
std::cout << " = " << length::mi_naut<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::nautical_mile>(meter) << '\n';
std::cout << " = " << length::pc<>(meter) << '\n'; std::cout << " = " << quantity_cast<iau::parsec>(meter) << '\n';
std::cout << " = " << length::pica_comp<>(meter) << '\n'; std::cout << " = " << quantity_cast<typographic::pica_comp>(meter) << '\n';
std::cout << " = " << length::pica_prn<>(meter) << '\n'; std::cout << " = " << quantity_cast<typographic::pica_prn>(meter) << '\n';
std::cout << " = " << length::point_comp<>(meter) << '\n'; std::cout << " = " << quantity_cast<typographic::point_comp>(meter) << '\n';
std::cout << " = " << length::point_prn<>(meter) << '\n'; std::cout << " = " << quantity_cast<typographic::point_prn>(meter) << '\n';
std::cout << " = " << length::rd<>(meter) << '\n'; std::cout << " = " << quantity_cast<imperial::rod>(meter) << '\n';
std::cout << " = " << length::yd<>(meter) << '\n'; std::cout << " = " << quantity_cast<international::yard>(meter) << '\n';
} }
void calcs_comparison() void calcs_comparison()
{ {
using namespace units::si;
std::cout.precision(20); std::cout.precision(20);
std::cout << "\nA distinct unit for each type is efficient and accurate\n" std::cout << "\nA distinct unit for each type is efficient and accurate\n"
"when adding two values of the same very big\n" "when adding two values of the same very big\n"
"or very small type:\n\n"; "or very small type:\n\n";
length::fm<float> L1A = 2q_fm; Length AUTO L1A = 2.q_fm;
length::fm<float> L2A = 3q_fm; Length AUTO L2A = 3.q_fm;
length::fm<float> LrA = L1A + L2A; Length AUTO LrA = L1A + L2A;
std::cout << L1A << " + " << L2A << " = " << LrA << "\n\n"; std::cout << L1A << " + " << L2A << " = " << LrA << "\n\n";
@ -207,28 +120,30 @@ void calcs_comparison()
"or small values in other units to the base unit.\n" "or small values in other units to the base unit.\n"
"This is both inefficient and inaccurate\n\n"; "This is both inefficient and inaccurate\n\n";
length::m<float> L1B = L1A; length<metre> L1B = L1A;
length::m<float> L2B = L2A; length<metre> L2B = L2A;
length::m<float> LrB = L1B + L2B; length<metre> LrB = L1B + L2B;
std::cout << L1B << " + " << L2B << " = " << LrB << "\n\n"; std::cout << L1B << " + " << L2B << " = " << LrB << "\n\n";
std::cout << "In multiplication and division:\n\n"; std::cout << "In multiplication and division:\n\n";
area::fm2<float> ArA = L1A * L2A; Area AUTO ArA = L1A * L2A;
std::cout << L1A << " * " << L2A << " = " << ArA << "\n\n"; std::cout << L1A << " * " << L2A << " = " << ArA << "\n\n";
std::cout << "similar problems arise\n\n"; std::cout << "similar problems arise\n\n";
area::m2<float> ArB = L1B * L2B; Area AUTO ArB = L1B * L2B;
std::cout << L1B << " * " << L2B << "\n = " << ArB << '\n'; std::cout << L1B << " * " << L2B << "\n = " << ArB << '\n';
} }
} // namespace
int main() int main()
{ {
std::cout << "This demo was originally posted on com.lang.c++.moderated in 2006\n"; std::cout << "This demo was originally posted on com.lang.c++.moderated in 2006\n";
std::cout << "http://compgroups.net/comp.lang.c++.moderated/dimensional-analysis-units/51712\n"; std::cout << "http://compgroups.net/comp.lang.c++.moderated/dimensional-analysis-units/51712\n";
std::cout << "Here converted to use mpusz/units library.\n\n"; std::cout << "Here converted to use mp-units library.\n\n";
simple_quantities(); simple_quantities();
quantities_with_typed_units(); quantities_with_typed_units();

View File

@ -16,6 +16,7 @@
*/ */
#include <units/physical/si/length.h> #include <units/physical/si/length.h>
#include <units/format.h>
#include <iostream> #include <iostream>
/* /*
@ -36,44 +37,23 @@ inline constexpr std::common_type_t<typename Target::rep, typename Source::rep>
return target{source{1}}.count(); return target{source{1}}.count();
} }
// get at the units text of the quantity, without its numeric value
inline auto constexpr units_str(const units::Quantity AUTO& q)
{
typedef std::remove_cvref_t<decltype(q)> qtype;
return units::detail::unit_text<typename qtype::dimension, typename qtype::unit>();
}
} // namespace } // namespace
namespace {
namespace length {
template<typename Rep = double>
using m = units::si::length<units::si::metre, Rep>;
template<typename Rep = double>
using mm = units::si::length<units::si::millimetre, Rep>;
} // namespace length
} // namespace
using namespace units::si::literals;
int main() int main()
{ {
std::cout << "conversion factor in mpusz/units...\n\n"; using namespace units::si;
constexpr length::m<> lengthA = 2.0q_m; std::cout << "conversion factor in mp-units...\n\n";
constexpr length::mm<> lengthB = lengthA;
std::cout << "lengthA( " << lengthA << " ) and lengthB( " << lengthB << " )\n" constexpr length<metre> lengthA = 2.0q_m;
constexpr length<millimetre> lengthB = lengthA;
std::cout << fmt::format("lengthA( {} ) and lengthB( {} )\n", lengthA, lengthB)
<< "represent the same length in different units.\n\n"; << "represent the same length in different units.\n\n";
std::cout << "therefore ratio lengthA / lengthB == " << lengthA / lengthB << "\n\n"; std::cout << fmt::format("therefore ratio lengthA / lengthB == {}\n\n", lengthA / lengthB);
std::cout << "conversion factor from lengthA::unit of " std::cout << fmt::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n", lengthA, lengthB)
<< units_str(lengthA) << " to lengthB::unit of " << units_str(lengthB) << " :\n\n" << fmt::format("lengthB.count( {} ) == lengthA.count( {} ) * conversion_factor( {} )\n",
<< "lengthB.count( " << lengthB.count() << " ) == lengthA.count( " << lengthA.count() lengthB.count(), lengthA.count(), conversion_factor(lengthB, lengthA));
<< " ) * conversion_factor( " << conversion_factor(lengthB, lengthA) << " )\n";
} }