/******************************************************************************* * Copyright (c) 2021, Bayerische Motoren Werke Aktiengesellschaft (BMW AG) * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 *******************************************************************************/ //----------------------------------------------------------------------------- /** @file floating_point_helper.h */ //----------------------------------------------------------------------------- #ifndef MANTLEAPI_COMMON_FLOATING_POINT_HELPER_H #define MANTLEAPI_COMMON_FLOATING_POINT_HELPER_H #include <units.h> #include <cmath> #include <limits> #include <type_traits> namespace mantle_api { /// @brief Compares two floating point numbers for equality. /// /// **Attention** No approximation of the correct precision for the actual value is done! /// /// This function uses a default precision of `std::numeric_limts<T>::epsilon()`, which means that without providing the /// precision yourself, it is only suited for /// * bit-wise equal numbers /// * numbers around 1 or smaller /// /// @tparam T Floating point type, ensured by SFINAE /// @param lhs Left-hand operand /// @param rhs Right-hand operand /// @param precision Given precision, defaults to `std::numeric_limits<T>::epsilon()`. /// @return True if both numbers are equal within the given precision. inline bool IsEqual(double lhs, double rhs, double precision = std::numeric_limits<double>::epsilon()) { return std::abs(lhs - rhs) < precision; } /// @brief Compares two floating point numbers for equality. /// /// **Attention** No approximation of the correct precision for the actual value is done! /// /// This function uses a default precision of `std::numeric_limts<T>::epsilon()`, which means that without providing the /// precision yourself, it is only suited for /// * bit-wise equal numbers /// * numbers around 1 or smaller /// /// @tparam T Floating point type, ensured by SFINAE /// @param lhs Left-hand operand /// @param rhs Right-hand operand /// @param precision Given precision, defaults to `std::numeric_limits<T>::epsilon()`. /// @return True if both numbers are equal within the given precision. template <typename T, class = typename std::enable_if_t<units::traits::is_unit_t<T>::value>> bool IsEqual(T lhs, T rhs, double precision = std::numeric_limits<double>::epsilon()) { return units::unit_cast<double>(units::math::abs(lhs - rhs)) < precision; } /// @brief Compares two floating point numbers for equality. /// /// **Attention** No approximation of the correct precision for the actual value is done! /// /// This function uses a default precision of `std::numeric_limts<T>::epsilon()`, which means that without providing the /// precision yourself, it is only suited for /// * bit-wise equal numbers /// * numbers around 1 or smaller /// /// @tparam T Floating point type, ensured by SFINAE /// @param lhs Left-hand operand /// @param rhs Right-hand operand /// @param precision Given precision, defaults to `std::numeric_limits<T>::epsilon()`. /// @return True if lhs is greater than rhs or both numbers are equal within the given precision. template <typename T, class = typename std::enable_if_t<units::traits::is_unit_t<T>::value>> bool GreaterOrEqual(T lhs, T rhs, double precision = std::numeric_limits<double>::epsilon()) { if (lhs > rhs) { return true; } return IsEqual(lhs, rhs, precision); } /// @brief Compares two floating point numbers for equality. /// /// **Attention** No approximation of the correct precision for the actual value is done! /// /// This function uses a default precision of `std::numeric_limts<T>::epsilon()`, which means that without providing the /// precision yourself, it is only suited for /// * bit-wise equal numbers /// * numbers around 1 or smaller /// /// @tparam T Floating point type, ensured by SFINAE /// @param lhs Left-hand operand /// @param rhs Right-hand operand /// @param precision Given precision, defaults to `std::numeric_limits<T>::epsilon()`. /// @return True if lhs is less than rhs or both numbers are equal within the given precision. template <typename T, class = typename std::enable_if_t<units::traits::is_unit_t<T>::value>> bool LessOrEqual(T lhs, T rhs, double precision = std::numeric_limits<double>::epsilon()) { if (lhs < rhs) { return true; } return IsEqual(lhs, rhs, precision); } } // namespace mantle_api #endif // MANTLEAPI_COMMON_FLOATING_POINT_HELPER_H