Skip to content

Commit f363c89

Browse files
extending fussy comparison
1 parent 829b180 commit f363c89

File tree

1 file changed

+69
-26
lines changed

1 file changed

+69
-26
lines changed

ocs2_core/include/ocs2_core/misc/Numerics.h

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,68 @@ namespace numerics {
4242
*
4343
* @tparam T1: data type of x.
4444
* @tparam T2: data type of y.
45-
* @param [in] x: a floating-point number.
46-
* @param [in] y: a floating-point number.
45+
* @tparam T3: data type of prec.
46+
* @param [in] x: First floating-point number.
47+
* @param [in] y: Second floating-point number.
48+
* @param [in] prec: The comparison precision.
4749
* @return bool: true if x=y.
4850
*/
49-
template <class T1, class T2>
50-
typename std::enable_if<std::is_floating_point<typename std::remove_reference<T1>::type>::value ||
51-
std::is_floating_point<typename std::remove_reference<T2>::type>::value,
52-
bool>::type
53-
almost_eq(T1&& x, T2&& y) {
54-
using TypeResult = typename std::conditional<std::is_floating_point<typename std::remove_reference<T1>::type>::value,
55-
typename std::remove_reference<T1>::type, typename std::remove_reference<T2>::type>::type;
51+
template <class T1, class T2, class T3>
52+
bool almost_eq(T1&& x, T2&& y, T3&& prec) {
53+
static_assert(std::is_floating_point<typename std::remove_reference<T1>::type>::value, "First argument is not floating point!");
54+
static_assert(std::is_floating_point<typename std::remove_reference<T2>::type>::value, "Second argument is not floating point!");
55+
static_assert(std::is_floating_point<typename std::remove_reference<T3>::type>::value, "prec is not floating point!");
5656
// the machine epsilon has to be scaled to the magnitude of the values used
57-
// and multiplied by the desired precision in ULPs (units in the last place)
58-
return std::abs(x - y) <= std::numeric_limits<TypeResult>::epsilon() * std::abs(x + y)
59-
// unless the result is subnormal
60-
|| std::abs(x - y) < std::numeric_limits<TypeResult>::min();
57+
// and multiplied by the desired precision unless the result is subnormal
58+
using Type = const std::remove_reference_t<T1>;
59+
const auto absDiff = std::abs(x - static_cast<Type>(y));
60+
const auto magnitude = std::min(std::abs(x), std::abs(static_cast<Type>(y)));
61+
return absDiff <= static_cast<Type>(prec) * magnitude || absDiff < std::numeric_limits<Type>::min();
62+
}
63+
64+
/**
65+
* Almost equal which uses machine epsilon to compare floating-point values for equality.
66+
* refer to: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
67+
*
68+
* @tparam T1: data type of x.
69+
* @tparam T2: data type of y.
70+
* @param [in] x: First floating-point number.
71+
* @param [in] y: Second floating-point number.
72+
* @return bool: true if x=y.
73+
*/
74+
template <class T1, class T2>
75+
bool almost_eq(T1&& x, T2&& y) {
76+
const auto prec = std::numeric_limits<std::remove_reference_t<T1>>::epsilon();
77+
return almost_eq(x, y, prec);
6178
}
6279

6380
/**
6481
* Almost less-equal which uses machine epsilon to compare floating-point values for equality.
6582
*
6683
* @tparam T1: data type of x.
6784
* @tparam T2: data type of y.
68-
* @param [in] x: a floating-point number.
69-
* @param [in] y: a floating-point number.
85+
* @tparam T3: data type of prec.
86+
* @param [in] x: First floating-point number.
87+
* @param [in] y: Second floating-point number.
88+
* @param [in] prec: The comparison precision.
7089
* @return bool: true if x<=y.
7190
*/
72-
template <class T1, class T2>
73-
typename std::enable_if<std::is_floating_point<typename std::remove_reference<T1>::type>::value ||
74-
std::is_floating_point<typename std::remove_reference<T2>::type>::value,
75-
bool>::type
76-
almost_le(T1&& x, T2&& y) {
91+
template <class T1, class T2, class T3>
92+
bool almost_le(T1&& x, T2&& y, T3&& prec) {
93+
return x < y || almost_eq(x, y, prec);
94+
}
95+
96+
/**
97+
* Almost less-equal which uses machine epsilon to compare floating-point values for equality.
98+
*
99+
* @tparam T1: data type of x.
100+
* @tparam T2: data type of y.
101+
* @param [in] x: First floating-point number.
102+
* @param [in] y: Second floating-point number.
103+
* @return bool: true if x<=y.
104+
*/
105+
template <class T1, class T2, class T3>
106+
bool almost_le(T1&& x, T2&& y) {
77107
return x < y || almost_eq(x, y);
78108
}
79109

@@ -82,15 +112,28 @@ almost_le(T1&& x, T2&& y) {
82112
*
83113
* @tparam T1: data type of x.
84114
* @tparam T2: data type of y.
85-
* @param [in] x: a floating-point number.
86-
* @param [in] y: a floating-point number.
115+
* @tparam T3: data type of prec.
116+
* @param [in] x: First floating-point number.
117+
* @param [in] y: Second floating-point number.
118+
* @param [in] prec: The comparison precision.
119+
* @return bool: true if x>=y.
120+
*/
121+
template <class T1, class T2, class T3>
122+
bool almost_ge(T1&& x, T2&& y, T3&& prec) {
123+
return x > y || almost_eq(x, y, prec);
124+
}
125+
126+
/**
127+
* Almost greater-equal which uses machine epsilon to compare floating-point values for equality.
128+
*
129+
* @tparam T1: data type of x.
130+
* @tparam T2: data type of y.
131+
* @param [in] x: First floating-point number.
132+
* @param [in] y: Second floating-point number.
87133
* @return bool: true if x>=y.
88134
*/
89135
template <class T1, class T2>
90-
typename std::enable_if<std::is_floating_point<typename std::remove_reference<T1>::type>::value ||
91-
std::is_floating_point<typename std::remove_reference<T2>::type>::value,
92-
bool>::type
93-
almost_ge(T1&& x, T2&& y) {
136+
bool almost_ge(T1&& x, T2&& y) {
94137
return x > y || almost_eq(x, y);
95138
}
96139

0 commit comments

Comments
 (0)