[libcxx-commits] [libcxx] r359184 - Implement midpoint for floating point types. Reviewed as https://reviews.llvm.org/D61014.
Marshall Clow via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Apr 25 05:11:43 PDT 2019
Author: marshall
Date: Thu Apr 25 05:11:43 2019
New Revision: 359184
URL: http://llvm.org/viewvc/llvm-project?rev=359184&view=rev
Log:
Implement midpoint for floating point types. Reviewed as https://reviews.llvm.org/D61014.
Added:
libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp
libcxx/trunk/test/support/fp_compare.h
Modified:
libcxx/trunk/docs/FeatureTestMacroTable.rst
libcxx/trunk/include/numeric
libcxx/trunk/include/version
libcxx/trunk/test/std/language.support/support.limits/support.limits.general/numeric.version.pass.cpp
libcxx/trunk/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
libcxx/trunk/utils/generate_feature_test_macro_components.py
Modified: libcxx/trunk/docs/FeatureTestMacroTable.rst
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/docs/FeatureTestMacroTable.rst?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/docs/FeatureTestMacroTable.rst (original)
+++ libcxx/trunk/docs/FeatureTestMacroTable.rst Thu Apr 25 05:11:43 2019
@@ -188,6 +188,8 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_generic_unordered_lookup`` *unimplemented*
------------------------------------------------- -----------------
+ ``__cpp_lib_interpolate`` ``201902L``
+ ------------------------------------------------- -----------------
``__cpp_lib_is_constant_evaluated`` ``201811L``
------------------------------------------------- -----------------
``__cpp_lib_list_remove_return_type`` *unimplemented*
Modified: libcxx/trunk/include/numeric
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/numeric?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/include/numeric (original)
+++ libcxx/trunk/include/numeric Thu Apr 25 05:11:43 2019
@@ -145,6 +145,7 @@ floating_point midpoint(floating_point
#include <iterator>
#include <limits> // for numeric_limits
#include <functional>
+#include <cmath> // for isnormal
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -552,7 +553,24 @@ midpoint(_TPtr __a, _TPtr __b) noexcept
{
return __a + _VSTD::midpoint(ptrdiff_t(0), __b - __a);
}
-#endif
+
+
+template <typename _Tp>
+int __sign(_Tp __val) {
+ return (_Tp(0) < __val) - (__val < _Tp(0));
+}
+
+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;
+}
+#endif // _LIBCPP_STD_VER > 17
_LIBCPP_END_NAMESPACE_STD
Modified: libcxx/trunk/include/version
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/version?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/include/version (original)
+++ libcxx/trunk/include/version Thu Apr 25 05:11:43 2019
@@ -58,6 +58,7 @@ __cpp_lib_hypot
__cpp_lib_incomplete_container_elements 201505L <forward_list> <list> <vector>
__cpp_lib_integer_sequence 201304L <utility>
__cpp_lib_integral_constant_callable 201304L <type_traits>
+__cpp_lib_interpolate 201902L <numeric>
__cpp_lib_invoke 201411L <functional>
__cpp_lib_is_aggregate 201703L <type_traits>
__cpp_lib_is_constant_evaluated 201811L <type_traits>
@@ -222,6 +223,7 @@ __cpp_lib_void_t
// # define __cpp_lib_destroying_delete 201806L
# define __cpp_lib_erase_if 201811L
// # define __cpp_lib_generic_unordered_lookup 201811L
+# define __cpp_lib_interpolate 201902L
# if !defined(_LIBCPP_HAS_NO_BUILTIN_IS_CONSTANT_EVALUATED)
# define __cpp_lib_is_constant_evaluated 201811L
# endif
Modified: libcxx/trunk/test/std/language.support/support.limits/support.limits.general/numeric.version.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/support.limits/support.limits.general/numeric.version.pass.cpp?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/test/std/language.support/support.limits/support.limits.general/numeric.version.pass.cpp (original)
+++ libcxx/trunk/test/std/language.support/support.limits/support.limits.general/numeric.version.pass.cpp Thu Apr 25 05:11:43 2019
@@ -15,6 +15,7 @@
/* Constant Value
__cpp_lib_gcd_lcm 201606L [C++17]
+ __cpp_lib_interpolate 201902L [C++2a]
__cpp_lib_parallel_algorithm 201603L [C++17]
*/
@@ -27,6 +28,10 @@
# error "__cpp_lib_gcd_lcm should not be defined before c++17"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# ifdef __cpp_lib_parallel_algorithm
# error "__cpp_lib_parallel_algorithm should not be defined before c++17"
# endif
@@ -37,6 +42,10 @@
# error "__cpp_lib_gcd_lcm should not be defined before c++17"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# ifdef __cpp_lib_parallel_algorithm
# error "__cpp_lib_parallel_algorithm should not be defined before c++17"
# endif
@@ -50,6 +59,10 @@
# error "__cpp_lib_gcd_lcm should have the value 201606L in c++17"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_parallel_algorithm
# error "__cpp_lib_parallel_algorithm should be defined in c++17"
@@ -72,6 +85,13 @@
# error "__cpp_lib_gcd_lcm should have the value 201606L in c++2a"
# endif
+# ifndef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should be defined in c++2a"
+# endif
+# if __cpp_lib_interpolate != 201902L
+# error "__cpp_lib_interpolate should have the value 201902L in c++2a"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_parallel_algorithm
# error "__cpp_lib_parallel_algorithm should be defined in c++2a"
Modified: libcxx/trunk/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp (original)
+++ libcxx/trunk/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp Thu Apr 25 05:11:43 2019
@@ -50,6 +50,7 @@
__cpp_lib_incomplete_container_elements 201505L [C++17]
__cpp_lib_integer_sequence 201304L [C++14]
__cpp_lib_integral_constant_callable 201304L [C++14]
+ __cpp_lib_interpolate 201902L [C++2a]
__cpp_lib_invoke 201411L [C++17]
__cpp_lib_is_aggregate 201703L [C++17]
__cpp_lib_is_constant_evaluated 201811L [C++2a]
@@ -248,6 +249,10 @@
# error "__cpp_lib_integral_constant_callable should not be defined before c++14"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# ifdef __cpp_lib_invoke
# error "__cpp_lib_invoke should not be defined before c++17"
# endif
@@ -596,6 +601,10 @@
# error "__cpp_lib_integral_constant_callable should have the value 201304L in c++14"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# ifdef __cpp_lib_invoke
# error "__cpp_lib_invoke should not be defined before c++17"
# endif
@@ -1082,6 +1091,10 @@
# error "__cpp_lib_integral_constant_callable should have the value 201304L in c++17"
# endif
+# ifdef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should not be defined before c++2a"
+# endif
+
# ifndef __cpp_lib_invoke
# error "__cpp_lib_invoke should be defined in c++17"
# endif
@@ -1778,6 +1791,13 @@
# error "__cpp_lib_integral_constant_callable should have the value 201304L in c++2a"
# endif
+# ifndef __cpp_lib_interpolate
+# error "__cpp_lib_interpolate should be defined in c++2a"
+# endif
+# if __cpp_lib_interpolate != 201902L
+# error "__cpp_lib_interpolate should have the value 201902L in c++2a"
+# endif
+
# ifndef __cpp_lib_invoke
# error "__cpp_lib_invoke should be defined in c++2a"
# endif
Added: 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=359184&view=auto
==============================================================================
--- libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp (added)
+++ libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.float.pass.cpp Thu Apr 25 05:11:43 2019
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03, c++11, c++14, c++17
+// <numeric>
+
+// template <class _Float>
+// _Tp midpoint(_Float __a, _Float __b) noexcept
+//
+
+#include <numeric>
+#include <cassert>
+
+#include "test_macros.h"
+#include "fp_compare.h"
+
+// Totally arbitrary picks for precision
+template <typename T>
+constexpr T fp_error_pct();
+
+template <>
+constexpr float fp_error_pct<float>() { return 1.0e-4f; }
+
+template <>
+constexpr double fp_error_pct<double>() { return 1.0e-12; }
+
+template <>
+constexpr long double fp_error_pct<long double>() { return 1.0e-13l; }
+
+
+template <typename T>
+void fp_test()
+{
+ ASSERT_SAME_TYPE(T, decltype(std::midpoint(T(), T())));
+ ASSERT_NOEXCEPT( std::midpoint(T(), T()));
+
+ constexpr T maxV = std::numeric_limits<T>::max();
+ 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)));
+
+// Things that can't be compared exactly
+ constexpr T pct = fp_error_pct<T>();
+ assert((fptest_close_pct(std::midpoint(T( 1.3), T(11.4)), T( 6.35), pct)));
+ assert((fptest_close_pct(std::midpoint(T(11.33), T(31.45)), T(21.39), pct)));
+ assert((fptest_close_pct(std::midpoint(T(-1.3), T(11.4)), T( 5.05), pct)));
+ assert((fptest_close_pct(std::midpoint(T(11.4), T(-1.3)), T( 5.05), pct)));
+ assert((fptest_close_pct(std::midpoint(T(0.1), T(0.4)), T(0.25), pct)));
+
+ assert((fptest_close_pct(std::midpoint(T(11.2345), T(14.5432)), T(12.88885), pct)));
+
+// From e to pi
+ assert((fptest_close_pct(std::midpoint(T(2.71828182845904523536028747135266249775724709369995),
+ T(3.14159265358979323846264338327950288419716939937510)),
+ T(2.92993724102441923691146542731608269097720824653752), pct)));
+
+ assert((fptest_close_pct(std::midpoint(maxV, T(0)), maxV/2, pct)));
+ assert((fptest_close_pct(std::midpoint(T(0), maxV), maxV/2, pct)));
+ assert((fptest_close_pct(std::midpoint(minV, T(0)), minV/2, pct)));
+ 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)));
+
+// Denormalized values
+// TODO
+
+// Check two values "close to each other"
+ T d1 = 3.14;
+ T d0 = std::nexttoward(d1, T(2));
+ T d2 = std::nexttoward(d1, T(5));
+ assert(d0 < d1); // sanity checking
+ assert(d1 < d2); // sanity checking
+
+// Since there's nothing in between, the midpoint has to be one or the other
+ T res;
+ res = std::midpoint(d0, d1);
+ assert(res == d0 || res == d1);
+ assert(d0 <= res);
+ assert(res <= d1);
+ res = std::midpoint(d1, d0);
+ assert(res == d0 || res == d1);
+ assert(d0 <= res);
+ assert(res <= d1);
+
+ res = std::midpoint(d1, d2);
+ assert(res == d1 || res == d2);
+ assert(d1 <= res);
+ assert(res <= d2);
+ res = std::midpoint(d2, d1);
+ assert(res == d1 || res == d2);
+ assert(d1 <= res);
+ assert(res <= d2);
+}
+
+
+int main (int, char**)
+{
+ fp_test<float>();
+ fp_test<double>();
+ fp_test<long double>();
+
+ return 0;
+}
Added: libcxx/trunk/test/support/fp_compare.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/fp_compare.h?rev=359184&view=auto
==============================================================================
--- libcxx/trunk/test/support/fp_compare.h (added)
+++ libcxx/trunk/test/support/fp_compare.h Thu Apr 25 05:11:43 2019
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef SUPPORT_FP_COMPARE_H
+#define SUPPORT_FP_COMPARE_H
+
+#include <cmath> // for std::abs
+#include <algorithm> // for std::max
+#include <cassert>
+
+// See https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/boost_test/testing_tools/extended_comparison/floating_point/floating_points_comparison_theory.html
+
+template<typename T>
+bool fptest_close(T val, T expected, T eps)
+{
+ constexpr T zero = T(0);
+ assert(eps >= zero);
+
+// Handle the zero cases
+ if (eps == zero) return val == expected;
+ if (val == zero) return std::abs(expected) <= eps;
+ if (expected == zero) return std::abs(val) <= eps;
+
+ return std::abs(val - expected) < eps
+ && std::abs(val - expected)/std::abs(val) < eps;
+}
+
+template<typename T>
+bool fptest_close_pct(T val, T expected, T percent)
+{
+ constexpr T zero = T(0);
+ assert(percent >= zero);
+
+// Handle the zero cases
+ if (percent == zero) return val == expected;
+ T eps = (percent / T(100)) * std::max(std::abs(val), std::abs(expected));
+
+ return fptest_close(val, expected, eps);
+}
+
+
+#endif // SUPPORT_FP_COMPARE_H
Modified: libcxx/trunk/utils/generate_feature_test_macro_components.py
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/utils/generate_feature_test_macro_components.py?rev=359184&r1=359183&r2=359184&view=diff
==============================================================================
--- libcxx/trunk/utils/generate_feature_test_macro_components.py (original)
+++ libcxx/trunk/utils/generate_feature_test_macro_components.py Thu Apr 25 05:11:43 2019
@@ -565,6 +565,12 @@ feature_test_macros = sorted([ add_versi
"depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
"internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)",
},
+ {"name": "__cpp_lib_interpolate",
+ "values": {
+ "c++2a": 201902L,
+ },
+ "headers": ["numeric"],
+ },
]], key=lambda tc: tc["name"])
def get_std_dialects():
More information about the libcxx-commits
mailing list