From fbbb28fdfdd175fcddd6035f64972b4b3df435b6 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Sat, 16 Nov 2019 18:30:44 +0100 Subject: [PATCH] `measurement` example added --- example/CMakeLists.txt | 6 ++ example/measurement.cpp | 141 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 example/measurement.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index d155f770..fb500daf 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -26,3 +26,9 @@ target_link_libraries(example PRIVATE mp::units ) + +add_executable(measurement measurement.cpp) +target_link_libraries(measurement + PRIVATE + mp::units +) diff --git a/example/measurement.cpp b/example/measurement.cpp new file mode 100644 index 00000000..09c6b6e1 --- /dev/null +++ b/example/measurement.cpp @@ -0,0 +1,141 @@ +// 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. + +#include +#include + +namespace { + + template typename Trait> + concept Satisfies = Trait::value; + + // root sum of squares + template + T rss(const T& v1, const T& v2) + { + return std::sqrt(std::pow(v1, 2) + std::pow(v2, 2)); + } + + template + class measurement { + public: + using value_type = T; + + measurement() = default; + + constexpr /* explicit */ measurement(const value_type& val, const value_type& err = {}): // cannot be explicit as `magma` concept requires implicit conversions :-( + value_(val), uncertainty_(std::abs(err)) + { + } + + constexpr const value_type& value() const { return value_; } + constexpr const value_type& uncertainty() const { return uncertainty_; } + + constexpr value_type relative_uncertainty() const { return uncertainty() / value(); } + constexpr value_type lower_bound() const { return value() - uncertainty(); } + constexpr value_type upper_bound() const { return value() + uncertainty(); } + + [[nodiscard]] constexpr measurement operator-() const { return measurement(-value(), uncertainty()); } + + [[nodiscard]] friend constexpr measurement operator+(const measurement& lhs, const measurement& rhs) + { + return measurement(lhs.value() + rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator-(const measurement& lhs, const measurement& rhs) + { + return measurement(lhs.value() - rhs.value(), rss(lhs.uncertainty(), rhs.uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator*(const measurement& lhs, const measurement& rhs) + { + const auto val = lhs.value() * rhs.value(); + return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty())); + } + + [[nodiscard]] friend constexpr measurement operator/(const measurement& lhs, const measurement& rhs) + { + const auto val = lhs.value() / rhs.value(); + return measurement(val, val * rss(lhs.relative_uncertainty(), rhs.relative_uncertainty())); + } + + [[nodiscard]] friend constexpr bool operator==(const measurement& lhs, const measurement& rhs) + { + return lhs.value() == rhs.value() && lhs.uncertainty() == rhs.uncertainty(); + } + + [[nodiscard]] friend constexpr bool operator!=(const measurement& lhs, const measurement& rhs) + { + return !(lhs == rhs); + } + + [[nodiscard]] friend constexpr bool operator<(const measurement& lhs, const measurement& rhs) + { + return lhs.value() == rhs.value() ? lhs.uncertainty() < rhs.uncertainty() : lhs.value() < rhs.value(); + } + + [[nodiscard]] friend constexpr bool operator>(const measurement& lhs, const measurement& rhs) + { + return rhs < lhs; + } + + [[nodiscard]] friend constexpr bool operator<=(const measurement& lhs, const measurement& rhs) + { + return !(rhs < lhs); + } + + [[nodiscard]] friend constexpr bool operator>=(const measurement& lhs, const measurement& rhs) + { + return !(lhs < rhs); + } + + friend std::ostream& operator<<(std::ostream& os, const measurement& v) + { + return os << v.value() << " ± " << v.uncertainty(); + } + + private: + value_type value_{}; + value_type uncertainty_{}; + }; + + template + using m_quantity = units::quantity>; + +} // namespace + +template +inline constexpr bool units::treat_as_floating_point> = std::is_floating_point_v; + + +int main() +{ + const auto a = m_quantity(measurement(9.8, 0.1)); + const auto t = m_quantity(measurement(1.2, 0.1)); + + units::Velocity AUTO v1 = a * t; + m_quantity v2(v1); + std::cout << a << " * " << t << " = " << v1 << " = " << v2 << '\n'; + + m_quantity length(measurement(123., 1.)); + std::cout << "10 * " << length << " = " << 10 * length << '\n'; +}