Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
floating_point_helper.h 4.52 KiB
/*******************************************************************************
 * 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