diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b1f9c89e..3074c15f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -78,6 +78,7 @@ add_mp_units_module( include/mp-units/concepts.h include/mp-units/core.h include/mp-units/framework.h + include/mp-units/limits.h MODULE_INTERFACE_UNIT mp-units-core.cpp ) diff --git a/src/core/include/mp-units/core.h b/src/core/include/mp-units/core.h index 702f3b6b..b1c9e6a4 100644 --- a/src/core/include/mp-units/core.h +++ b/src/core/include/mp-units/core.h @@ -26,6 +26,7 @@ #include #include #include +#include #if MP_UNITS_HOSTED #include diff --git a/src/core/include/mp-units/limits.h b/src/core/include/mp-units/limits.h new file mode 100644 index 00000000..e04cf49d --- /dev/null +++ b/src/core/include/mp-units/limits.h @@ -0,0 +1,154 @@ +// 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. + +#pragma once + +#include +#include +#include + +#ifndef MP_UNITS_IN_MODULE_INTERFACE +#ifdef MP_UNITS_IMPORT_STD +import std; +#else +#include +#endif // MP_UNITS_IMPORT_STD +#endif // MP_UNITS_IN_MODULE_INTERFACE + +template + requires requires { typename std::numeric_limits; } +class std::numeric_limits> : public std::numeric_limits { +public: + static constexpr mp_units::quantity min() noexcept + requires requires { mp_units::quantity::min(); } + { + return mp_units::quantity::min(); + } + + static constexpr mp_units::quantity max() noexcept + requires requires { mp_units::quantity::max(); } + { + return mp_units::quantity::max(); + } + + static constexpr mp_units::quantity lowest() noexcept + requires requires { std::numeric_limits::lowest(); } + { + return {std::numeric_limits::lowest(), R}; + } + + static constexpr mp_units::quantity epsilon() noexcept + requires requires { std::numeric_limits::epsilon(); } + { + return {std::numeric_limits::epsilon(), R}; + } + + static constexpr mp_units::quantity round_error() noexcept + requires requires { std::numeric_limits::round_error(); } + { + return {std::numeric_limits::round_error(), R}; + } + + static constexpr mp_units::quantity infinity() noexcept + requires requires { std::numeric_limits::infinity(); } + { + return {std::numeric_limits::infinity(), R}; + } + + static constexpr mp_units::quantity quiet_NaN() noexcept + requires requires { std::numeric_limits::quiet_NaN(); } + { + return {std::numeric_limits::quiet_NaN(), R}; + } + + static constexpr mp_units::quantity signaling_NaN() noexcept + requires requires { std::numeric_limits::signaling_NaN(); } + { + return {std::numeric_limits::signaling_NaN(), R}; + } + + static constexpr mp_units::quantity denorm_min() noexcept + requires requires { std::numeric_limits::denorm_min(); } + { + return {std::numeric_limits::denorm_min(), R}; + } +}; + + +template + requires requires { typename std::numeric_limits; } +class std::numeric_limits> : public std::numeric_limits { +public: + static constexpr mp_units::quantity_point min() noexcept + requires requires { mp_units::quantity_point::min(); } + { + return mp_units::quantity_point::min(); + } + + static constexpr mp_units::quantity_point max() noexcept + requires requires { mp_units::quantity_point::max(); } + { + return mp_units::quantity_point::max(); + } + + static constexpr mp_units::quantity_point lowest() noexcept + requires requires { std::numeric_limits>::lowest(); } + { + return {std::numeric_limits>::lowest(), PO}; + } + + static constexpr mp_units::quantity_point epsilon() noexcept + requires requires { std::numeric_limits>::epsilon(); } + { + return {std::numeric_limits>::epsilon(), PO}; + } + + static constexpr mp_units::quantity_point round_error() noexcept + requires requires { std::numeric_limits>::round_error(); } + { + return {std::numeric_limits>::round_error(), PO}; + } + + static constexpr mp_units::quantity_point infinity() noexcept + requires requires { std::numeric_limits>::infinity(); } + { + return {std::numeric_limits>::infinity(), PO}; + } + + static constexpr mp_units::quantity_point quiet_NaN() noexcept + requires requires { std::numeric_limits>::quiet_NaN(); } + { + return {std::numeric_limits>::quiet_NaN(), PO}; + } + + static constexpr mp_units::quantity_point signaling_NaN() noexcept + requires requires { std::numeric_limits>::signaling_NaN(); } + { + return {std::numeric_limits>::signaling_NaN(), PO}; + } + + static constexpr mp_units::quantity_point denorm_min() noexcept + requires requires { std::numeric_limits>::denorm_min(); } + { + return {std::numeric_limits>::denorm_min(), PO}; + } +}; diff --git a/src/core/include/mp-units/math.h b/src/core/include/mp-units/math.h index a71ea60b..1bfb3b7e 100644 --- a/src/core/include/mp-units/math.h +++ b/src/core/include/mp-units/math.h @@ -320,7 +320,8 @@ template */ template requires requires { std::numeric_limits::epsilon(); } -[[nodiscard]] constexpr quantity epsilon(R r) noexcept +[[deprecated("Use `std::numeric_limits::epsilon()` instead")]] [[nodiscard]] constexpr quantity +epsilon(R r) noexcept { return {static_cast(std::numeric_limits::epsilon()), r}; } diff --git a/test/runtime/math_test.cpp b/test/runtime/math_test.cpp index bee5f7e8..285eae00 100644 --- a/test/runtime/math_test.cpp +++ b/test/runtime/math_test.cpp @@ -145,20 +145,6 @@ TEST_CASE("math operations", "[math]") } } - SECTION("numeric_limits functions") - { - SECTION("'epsilon' works as expected using default floating type") - { - REQUIRE(epsilon(isq::length[m]).numerical_value_in(m) == - std::numeric_limits::epsilon()); - } - SECTION("'epsilon' works as expected using integers") - { - REQUIRE(epsilon(isq::length[m]).numerical_value_in(m) == - std::numeric_limits::epsilon()); - } - } - SECTION("floor functions") { SECTION("floor 1 second with target unit second should be 1 second") diff --git a/test/static/CMakeLists.txt b/test/static/CMakeLists.txt index 48bd4a05..a01c2fc1 100644 --- a/test/static/CMakeLists.txt +++ b/test/static/CMakeLists.txt @@ -45,8 +45,9 @@ add_library( iec_test.cpp imperial_test.cpp international_test.cpp - isq_test.cpp isq_angle_test.cpp + isq_test.cpp + limits_test.cpp natural_test.cpp prime_test.cpp quantity_point_test.cpp diff --git a/test/static/limits_test.cpp b/test/static/limits_test.cpp new file mode 100644 index 00000000..24048708 --- /dev/null +++ b/test/static/limits_test.cpp @@ -0,0 +1,188 @@ +// 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 +#ifdef MP_UNITS_IMPORT_STD +import std; +#else +#include +#endif + +namespace { + +// ********************* QUANTITY ********************* + +using q_double = mp_units::quantity; +using q_int = mp_units::quantity; + +// cv qualifiers +static_assert(std::numeric_limits::max() == q_double::max()); +static_assert(std::numeric_limits::max() == q_double::max()); +static_assert(std::numeric_limits::max() == q_double::max()); + +// is_specialized +static_assert(std::numeric_limits::is_specialized == true); +static_assert(std::numeric_limits::is_specialized == true); + +// is_integer +static_assert(std::numeric_limits::is_integer == false); +static_assert(std::numeric_limits::is_integer == true); + +// has_infinity +static_assert(std::numeric_limits::has_infinity == true); +static_assert(std::numeric_limits::has_infinity == false); + +// min +static_assert(std::numeric_limits::min() == q_double::min()); +static_assert(std::numeric_limits::min() == q_int::min()); + +static_assert(std::numeric_limits::min().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); +static_assert(std::numeric_limits::min().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); + +// max +static_assert(std::numeric_limits::max() == q_double::max()); +static_assert(std::numeric_limits::max() == q_int::max()); + +static_assert(std::numeric_limits::max().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::max()); +static_assert(std::numeric_limits::max().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::max()); + +// lowest +static_assert(std::numeric_limits::lowest().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); +static_assert(std::numeric_limits::lowest().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); + +// epsilon +static_assert(std::numeric_limits::epsilon().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::epsilon()); +static_assert(std::numeric_limits::epsilon().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::epsilon()); + +// round_error +static_assert(std::numeric_limits::round_error().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::round_error()); +static_assert(std::numeric_limits::round_error().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::round_error()); + +// infinity +static_assert(std::numeric_limits::infinity().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::infinity()); +static_assert(std::numeric_limits::infinity().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::infinity()); + +// quiet_NaN +static_assert(std::isnan(std::numeric_limits::quiet_NaN().numerical_value_in(mp_units::si::metre))); + +// signaling_NaN +static_assert(std::isnan(std::numeric_limits::signaling_NaN().numerical_value_in(mp_units::si::metre))); + +// denorm_min +static_assert(std::numeric_limits::denorm_min().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::denorm_min()); +static_assert(std::numeric_limits::denorm_min().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::denorm_min()); + + +// ********************* QUANTITY POINT ********************* + +using qp_double = mp_units::quantity_point; +using qp_int = mp_units::quantity_point; + +// cv qualifiers +static_assert(std::numeric_limits::max() == qp_double::max()); +static_assert(std::numeric_limits::max() == qp_double::max()); +static_assert(std::numeric_limits::max() == qp_double::max()); + +// is_specialized +static_assert(std::numeric_limits::is_specialized == true); +static_assert(std::numeric_limits::is_specialized == true); + +// is_integer +static_assert(std::numeric_limits::is_integer == false); +static_assert(std::numeric_limits::is_integer == true); + +// has_infinity +static_assert(std::numeric_limits::has_infinity == true); +static_assert(std::numeric_limits::has_infinity == false); + +// min +static_assert(std::numeric_limits::min() == qp_double::min()); +static_assert(std::numeric_limits::min() == qp_int::min()); + +static_assert(std::numeric_limits::min().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); +static_assert(std::numeric_limits::min().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); + +// max +static_assert(std::numeric_limits::max() == qp_double::max()); +static_assert(std::numeric_limits::max() == qp_int::max()); + +static_assert(std::numeric_limits::max().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::max()); +static_assert(std::numeric_limits::max().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::max()); + +// lowest +static_assert(std::numeric_limits::lowest().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); +static_assert(std::numeric_limits::lowest().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::lowest()); + +// epsilon +static_assert(std::numeric_limits::epsilon().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::epsilon()); +static_assert(std::numeric_limits::epsilon().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::epsilon()); + +// round_error +static_assert(std::numeric_limits::round_error().quantity_from_zero().numerical_value_in( + mp_units::si::metre) == std::numeric_limits::round_error()); +static_assert(std::numeric_limits::round_error().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::round_error()); + +// infinity +static_assert(std::numeric_limits::infinity().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::infinity()); +static_assert(std::numeric_limits::infinity().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::infinity()); + +// quiet_NaN +static_assert( + std::isnan(std::numeric_limits::quiet_NaN().quantity_from_zero().numerical_value_in(mp_units::si::metre))); + +// signaling_NaN +static_assert(std::isnan( + std::numeric_limits::signaling_NaN().quantity_from_zero().numerical_value_in(mp_units::si::metre))); + +// denorm_min +static_assert(std::numeric_limits::denorm_min().quantity_from_zero().numerical_value_in( + mp_units::si::metre) == std::numeric_limits::denorm_min()); +static_assert(std::numeric_limits::denorm_min().quantity_from_zero().numerical_value_in(mp_units::si::metre) == + std::numeric_limits::denorm_min()); + +} // namespace