@@ -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 */
89135template <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