[libcxx-commits] [libcxx] r363714 - Fix the floating point version of midpoint. It wasn't constexpr, among other things. Add more tests. As a drive-by, the LCD implementation had a class named '__abs' which did a 'absolute value to a common-type' conversion. Rename that to be '__ct_abs'.

Marshall Clow via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 18 11:13:54 PDT 2019


Author: marshall
Date: Tue Jun 18 11:13:54 2019
New Revision: 363714

URL: http://llvm.org/viewvc/llvm-project?rev=363714&view=rev
Log:
Fix the floating point version of midpoint. It wasn't constexpr, among other things. Add more tests. As a drive-by, the LCD implementation had a class named '__abs' which did a 'absolute value to a common-type' conversion. Rename that to be '__ct_abs'.

Modified:
    libcxx/trunk/include/numeric
    libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp

Modified: libcxx/trunk/include/numeric
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/numeric?rev=363714&r1=363713&r2=363714&view=diff
==============================================================================
--- libcxx/trunk/include/numeric (original)
+++ libcxx/trunk/include/numeric Tue Jun 18 11:13:54 2019
@@ -460,10 +460,10 @@ iota(_ForwardIterator __first, _ForwardI
 
 
 #if _LIBCPP_STD_VER > 14
-template <typename _Result, typename _Source, bool _IsSigned = is_signed<_Source>::value> struct __abs;
+template <typename _Result, typename _Source, bool _IsSigned = is_signed<_Source>::value> struct __ct_abs;
 
 template <typename _Result, typename _Source>
-struct __abs<_Result, _Source, true> {
+struct __ct_abs<_Result, _Source, true> {
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     _Result operator()(_Source __t) const noexcept
     {
@@ -474,7 +474,7 @@ struct __abs<_Result, _Source, true> {
 };
 
 template <typename _Result, typename _Source>
-struct __abs<_Result, _Source, false> {
+struct __ct_abs<_Result, _Source, false> {
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     _Result operator()(_Source __t) const noexcept { return __t; }
 };
@@ -500,8 +500,8 @@ gcd(_Tp __m, _Up __n)
     using _Rp = common_type_t<_Tp,_Up>;
     using _Wp = make_unsigned_t<_Rp>;
     return static_cast<_Rp>(_VSTD::__gcd(
-        static_cast<_Wp>(__abs<_Rp, _Tp>()(__m)),
-        static_cast<_Wp>(__abs<_Rp, _Up>()(__n))));
+        static_cast<_Wp>(__ct_abs<_Rp, _Tp>()(__m)),
+        static_cast<_Wp>(__ct_abs<_Rp, _Up>()(__n))));
 }
 
 template<class _Tp, class _Up>
@@ -516,8 +516,8 @@ lcm(_Tp __m, _Up __n)
         return 0;
 
     using _Rp = common_type_t<_Tp,_Up>;
-    _Rp __val1 = __abs<_Rp, _Tp>()(__m) / _VSTD::gcd(__m, __n);
-    _Rp __val2 = __abs<_Rp, _Up>()(__n);
+    _Rp __val1 = __ct_abs<_Rp, _Tp>()(__m) / _VSTD::gcd(__m, __n);
+    _Rp __val2 = __ct_abs<_Rp, _Up>()(__n);
     _LIBCPP_ASSERT((numeric_limits<_Rp>::max() / __val1 > __val2), "Overflow in lcm");
     return __val1 * __val2;
 }
@@ -563,16 +563,23 @@ constexpr int __sign(_Tp __val) {
     return (_Tp(0) < __val) - (__val < _Tp(0));
 }
 
+template <typename _Fp>
+constexpr _Fp __fp_abs(_Fp __f) { return __f >= 0 ? __f : -__f; }
+
 template <class _Fp>
 _LIBCPP_INLINE_VISIBILITY constexpr
 enable_if_t<is_floating_point_v<_Fp>, _Fp>
 midpoint(_Fp __a, _Fp __b) noexcept
 {
-    return isnormal(__a) && isnormal(__b)
-       && ((__sign(__a) != __sign(__b)) || ((numeric_limits<_Fp>::max() - abs(__a)) < abs(__b)))
-             ?  __a / 2 + __b / 2
-             : (__a + __b) / 2;
+	constexpr _Fp __lo = numeric_limits<_Fp>::min()*2;
+	constexpr _Fp __hi = numeric_limits<_Fp>::max()/2;
+    return __fp_abs(__a) <= __hi && __fp_abs(__b) <= __hi ?  // typical case: overflow is impossible
+      (__a + __b)/2 :                                        // always correctly rounded
+      __fp_abs(__a) < __lo ? __a + __b/2 :                   // not safe to halve a
+      __fp_abs(__a) < __lo ? __a/2 + __b :                   // not safe to halve b
+      __a/2 + __b/2;                                         // otherwise correctly rounded
 }
+
 #endif // _LIBCPP_STD_VER > 17
 
 _LIBCPP_END_NAMESPACE_STD

Modified: libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp?rev=363714&r1=363713&r2=363714&view=diff
==============================================================================
--- libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp (original)
+++ libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp Tue Jun 18 11:13:54 2019
@@ -43,11 +43,11 @@ void fp_test()
     constexpr T minV = std::numeric_limits<T>::min();
     
 //  Things that can be compared exactly
-    assert((std::midpoint(T(0), T(0)) == T(0)));
-    assert((std::midpoint(T(2), T(4)) == T(3)));
-    assert((std::midpoint(T(4), T(2)) == T(3)));
-    assert((std::midpoint(T(3), T(4)) == T(3.5)));
-    assert((std::midpoint(T(0), T(0.4)) == T(0.2)));
+    static_assert((std::midpoint(T(0), T(0))   == T(0)),   "");
+    static_assert((std::midpoint(T(2), T(4))   == T(3)),   "");
+    static_assert((std::midpoint(T(4), T(2))   == T(3)),   "");
+    static_assert((std::midpoint(T(3), T(4))   == T(3.5)), "");
+    static_assert((std::midpoint(T(0), T(0.4)) == T(0.2)), "");
 
 //  Things that can't be compared exactly
     constexpr T pct = fp_error_pct<T>();
@@ -70,6 +70,17 @@ void fp_test()
     assert((fptest_close_pct(std::midpoint(T(0), minV), minV/2, pct)));
     assert((fptest_close_pct(std::midpoint(maxV, maxV), maxV,   pct)));
     assert((fptest_close_pct(std::midpoint(minV, minV), minV,   pct)));
+    assert((fptest_close_pct(std::midpoint(maxV, minV), maxV/2, pct)));
+    assert((fptest_close_pct(std::midpoint(minV, maxV), maxV/2, pct)));
+
+//  Near the min and the max
+    assert((fptest_close_pct(std::midpoint(maxV*T(0.75), maxV*T(0.50)),  maxV*T(0.625), pct)));
+    assert((fptest_close_pct(std::midpoint(maxV*T(0.50), maxV*T(0.75)),  maxV*T(0.625), pct)));
+    assert((fptest_close_pct(std::midpoint(minV*T(2),    minV*T(8)),     minV*T(5),     pct)));
+
+//  Big numbers of different signs
+    assert((fptest_close_pct(std::midpoint(maxV*T( 0.75),  maxV*T(-0.5)), maxV*T( 0.125), pct)));
+    assert((fptest_close_pct(std::midpoint(maxV*T(-0.75),  maxV*T( 0.5)), maxV*T(-0.125), pct)));
 
 //  Denormalized values
 //  TODO




More information about the libcxx-commits mailing list