+2019-03-05 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/c_compatibility/math.h [C++20] (lerp): Add using
+ declaration.
+ * include/c_global/cmath [C++20] (__cpp_lib_interpolate): Define.
+ (__lerp): Define function template to implement lerp.
+ (lerp(float, float, float), lerp(double, double, double))
+ (lerp(long double, long double, long double)): Define for C++20.
+ * include/std/numeric [C++20] (__cpp_lib_interpolate): Define.
+ (midpoint(T, T), midpoint(T*, T*)): Define.
+ * include/std::version [C++20] (__cpp_lib_interpolate): Define.
+ * testsuite/26_numerics/lerp.cc: New test.
+ * testsuite/26_numerics/midpoint/floating.cc: New test.
+ * testsuite/26_numerics/midpoint/integral.cc: New test.
+ * testsuite/26_numerics/midpoint/pointer.cc: New test.
+
2019-03-04 Edward Smith-Rowland <3dw4rd@verizon.net>
PR libstdc++/88996 Implement P0439R0
using std::sph_neumann;
#endif // _GLIBCXX_USE_STD_SPEC_FUNCS
+#if __cplusplus > 201703L
+using std::lerp;
+#endif // C++20
+
#endif // _GLIBCXX_MATH_H
#endif // __cplusplus
}
#endif // C++17
+#if __cplusplus > 201703L
+ // linear interpolation
+# define __cpp_lib_interpolate 201902L
+
+ template<typename _Fp>
+ constexpr _Fp
+ __lerp(_Fp __a, _Fp __b, _Fp __t)
+ {
+ if (__a <= 0 && __b >= 0 || __a >= 0 && __b <= 0)
+ return __t * __b + (1 - __t) * __a;
+
+ if (__t == 1)
+ return __b; // exact
+
+ // Exact at __t=0, monotonic except near __t=1,
+ // bounded, determinate, and consistent:
+ const _Fp __x = __a + __t * (__b - __a);
+ return __t > 1 == __b > __a
+ ? (__b < __x ? __x : __b)
+ : (__b > __x ? __x : __b); // monotonic near __t=1
+ }
+
+ constexpr float
+ lerp(float __a, float __b, float __t)
+ { return std::__lerp(__a, __b, __t); }
+
+ constexpr double
+ lerp(double __a, double __b, double __t)
+ { return std::__lerp(__a, __b, __t); }
+
+ constexpr long double
+ lerp(long double __a, long double __b, long double __t)
+ { return std::__lerp(__a, __b, __t); }
+#endif // C++20
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
}
} // namespace __detail
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
#define __cpp_lib_gcd_lcm 201606
// These were used in drafts of SD-6:
#endif // C++17
+#if __cplusplus > 201703L
+ // midpoint
+# define __cpp_lib_interpolate 201902L
+
+template<typename _Tp>
+ constexpr
+ enable_if_t<__and_<is_arithmetic<_Tp>, is_same<remove_cv_t<_Tp>, _Tp>,
+ __not_<is_same<_Tp, bool>>>::value,
+ _Tp>
+ midpoint(_Tp __a, _Tp __b) noexcept
+ {
+ if constexpr (is_integral_v<_Tp>)
+ {
+ using _Up = make_unsigned_t<_Tp>;
+
+ int __k = 1;
+ _Up __m = __a;
+ _Up __M = __b;
+ if (__a > __b)
+ {
+ __k = -1;
+ __m = __b;
+ __M = __a;
+ }
+ return __a + __k * _Tp(_Up(__M - __m) / 2);
+ }
+ else
+ {
+ return __builtin_isnormal(__a) && __builtin_isnormal(__b)
+ ? __a / 2 + __b / 2
+ : (__a + __b) / 2;
+ }
+ }
+
+ template<typename _Tp>
+ constexpr
+ enable_if_t<__and_<is_object<_Tp>, bool_constant<sizeof(_Tp) != 0>>::value,
+ _Tp*>
+ midpoint(_Tp* __a, _Tp* __b) noexcept
+ {
+ return __a > __b ? __b + (__a - __b) / 2 : __a + (__b - __a) / 2;
+ }
+#endif // C++20
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
# define __cpp_lib_destroying_delete 201806L
#endif
#define __cpp_lib_erase_if 201900L
+#define __cpp_lib_interpolate 201902L
#ifdef _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED
# define __cpp_lib_is_constant_evaluated 201811L
#endif
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <cmath>
+
+#ifndef __cpp_lib_interpolate
+# error "Feature-test macro for midpoint and lerp missing"
+#elif __cpp_lib_interpolate != 201902L
+# error "Feature-test macro for midpoint and lerp has wrong value"
+#endif
+
+#include <limits>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using lim = std::numeric_limits<double>;
+
+ VERIFY( std::lerp(0.0, 1.0, 0.0) == 0.0 );
+ VERIFY( std::lerp(-2.0, 10.0, 1.0) == 10.0 );
+ VERIFY( std::lerp(2.0, -10.0, 1.0) == -10.0 );
+ VERIFY( std::lerp(-8.0, 10.0, 0.5) == 1.0 );
+ VERIFY( std::lerp(-10.0, 10.0, 0.25) == -5.0 );
+ VERIFY( std::lerp(10.0, -10.0, 0.375) == 2.5 );
+
+ VERIFY( std::lerp(2.0, 2.0, 200.0) == 2.0 );
+ VERIFY( std::lerp(2.0, 4.0, 200.0) == 402.0 );
+ VERIFY( std::lerp(2.0, 4.0, -20.0) == -38.0 );
+
+ VERIFY( std::lerp(1.1, 30201.1, 0) == 1.1 );
+ VERIFY( std::lerp(1.1, 30201.1, 1) == 30201.1 );
+ VERIFY( std::lerp(1.1, -30201.1, 0) == 1.1 );
+ VERIFY( std::lerp(1.1, -30201.1, 1) == -30201.1 );
+
+ VERIFY( std::lerp(1.1, 1.1, lim::infinity()) == 1.1 );
+ VERIFY( std::isfinite(std::lerp(1.1, 1.1+lim::min(), lim::max())) );
+
+ VERIFY( std::lerp(lim::max(), lim::max(), 1) == lim::max() );
+ VERIFY( std::lerp(lim::max(), lim::max()/9e9, 0) == lim::max() );
+ VERIFY( std::lerp(lim::max()/9e9, lim::max(), 1) == lim::max() );
+}
+
+void
+test02()
+{
+ using lim = std::numeric_limits<float>;
+
+ VERIFY( std::lerp(0.0f, 1.0f, 0.0f) == 0.0f );
+ VERIFY( std::lerp(-2.0f, 10.0f, 1.0f) == 10.0f );
+ VERIFY( std::lerp(2.0f, -10.0f, 1.0f) == -10.0f );
+ VERIFY( std::lerp(-8.0f, 10.0f, 0.5f) == 1.0f );
+ VERIFY( std::lerp(-10.0f, 10.0f, 0.25f) == -5.0f );
+ VERIFY( std::lerp(10.0f, -10.0f, 0.375f) == 2.5f );
+
+ VERIFY( std::lerp(2.0f, 2.0f, 200.0f) == 2.0f );
+ VERIFY( std::lerp(2.0f, 4.0f, 200.0f) == 402.0f );
+ VERIFY( std::lerp(2.0f, 4.0f, -20.0f) == -38.0f );
+
+ VERIFY( std::lerp(1.1f, 30201.1f, 0) == 1.1f );
+ VERIFY( std::lerp(1.1f, 30201.1f, 1) == 30201.1f );
+ VERIFY( std::lerp(1.1f, -30201.1f, 0) == 1.1f );
+ VERIFY( std::lerp(1.1f, -30201.1f, 1) == -30201.1f );
+
+ VERIFY( std::lerp(1.1f, 1.1f, lim::infinity()) == 1.1f );
+ VERIFY( std::isfinite(std::lerp(1.1f, 1.1f+lim::min(), lim::max())) );
+
+ VERIFY( std::lerp(lim::max(), lim::max(), 1) == lim::max() );
+ VERIFY( std::lerp(lim::max(), lim::max()/9e9f, 0) == lim::max() );
+ VERIFY( std::lerp(lim::max()/9e9f, lim::max(), 1) == lim::max() );
+}
+
+void
+test03()
+{
+ using lim = std::numeric_limits<long double>;
+
+ VERIFY( std::lerp(0.0l, 1.0l, 0.0l) == 0.0l );
+ VERIFY( std::lerp(-2.0l, 10.0l, 1.0l) == 10.0l );
+ VERIFY( std::lerp(2.0l, -10.0l, 1.0l) == -10.0l );
+ VERIFY( std::lerp(-8.0l, 10.0l, 0.5l) == 1.0l );
+ VERIFY( std::lerp(-10.0l, 10.0l, 0.25l) == -5.0l );
+ VERIFY( std::lerp(10.0l, -10.0l, 0.375l) == 2.5l );
+
+ VERIFY( std::lerp(2.0l, 2.0l, 200.0l) == 2.0l );
+ VERIFY( std::lerp(2.0l, 4.0l, 200.0l) == 402.0l );
+ VERIFY( std::lerp(2.0l, 4.0l, -20.0l) == -38.0l );
+
+ VERIFY( std::lerp(1.1l, 30201.1l, 0) == 1.1l );
+ VERIFY( std::lerp(1.1l, 30201.1l, 1) == 30201.1l );
+ VERIFY( std::lerp(1.1l, -30201.1l, 0) == 1.1l );
+ VERIFY( std::lerp(1.1l, -30201.1l, 1) == -30201.1l );
+
+ VERIFY( std::lerp(1.1l, 1.1l, lim::infinity()) == 1.1l );
+ VERIFY( std::isfinite(std::lerp(1.1l, 1.1l+lim::min(), lim::max())) );
+
+ VERIFY( std::lerp(lim::max(), lim::max(), 1) == lim::max() );
+ VERIFY( std::lerp(lim::max(), lim::max()/9e9l, 0) == lim::max() );
+ VERIFY( std::lerp(lim::max()/9e9l, lim::max(), 1) == lim::max() );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <numeric>
+#include <limits>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using lim = std::numeric_limits<double>;
+
+ VERIFY( std::midpoint(2.0, 4.0) == 3.0 );
+ VERIFY( std::midpoint(0.0, 0.4) == 0.2 );
+ VERIFY( std::midpoint(0.0, -0.0) == 0.0 );
+ VERIFY( std::midpoint(9e9, -9e9) == 0.0 );
+
+ VERIFY( std::midpoint(lim::max(), lim::max()) == lim::max() );
+}
+
+void
+test02()
+{
+ using lim = std::numeric_limits<float>;
+
+ VERIFY( std::midpoint(2.0f, 4.0f) == 3.0f );
+ VERIFY( std::midpoint(0.0f, 0.4f) == 0.2f );
+ VERIFY( std::midpoint(0.0f, -0.0f) == 0.0f );
+ VERIFY( std::midpoint(9e9f, -9e9f) == 0.0f );
+}
+
+void
+test03()
+{
+ using lim = std::numeric_limits<long double>;
+
+ VERIFY( std::midpoint(2.0l, 4.0l) == 3.0l );
+ VERIFY( std::midpoint(0.0l, 0.4l) == 0.2l );
+ VERIFY( std::midpoint(0.0l, -0.0l) == 0.0l );
+ VERIFY( std::midpoint(9e9l, -9e9l) == 0.0l );
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <numeric>
+
+#ifndef __cpp_lib_interpolate
+# error "Feature-test macro for midpoint and lerp missing"
+#elif __cpp_lib_interpolate != 201902L
+# error "Feature-test macro for midpoint and lerp has wrong value"
+#endif
+
+#include <climits>
+#include <testsuite_hooks.h>
+
+static_assert(std::is_same_v<decltype(std::midpoint(0, 1)), int>);
+static_assert(noexcept(std::midpoint(1, 2)));
+
+struct test_type { };
+template<typename T> decltype(std::midpoint<T>(T(), T())) try_midpoint(int);
+template<typename T> test_type try_midpoint(...);
+template<typename T> constexpr bool no_midpoint()
+{ return std::is_same_v<decltype(try_midpoint<T>()), test_type>; }
+
+static_assert(no_midpoint<bool>());
+static_assert(no_midpoint<const bool>());
+static_assert(no_midpoint<const int>());
+static_assert(no_midpoint<volatile int>());
+
+static_assert( std::midpoint(0, 0) == 0 );
+static_assert( std::midpoint(1, 1) == 1 );
+static_assert( std::midpoint(0, 1) == 0 );
+static_assert( std::midpoint(1, 0) == 1 );
+static_assert( std::midpoint(0, 2) == 1 );
+static_assert( std::midpoint(3, 2) == 3 );
+static_assert( std::midpoint(-5, 4) == -1 );
+static_assert( std::midpoint(5, -4) == 1 );
+static_assert( std::midpoint(-5, -4) == -5 );
+static_assert( std::midpoint(-4, -5) == -4 );
+static_assert( std::midpoint(INT_MIN, INT_MAX) == -1 );
+static_assert( std::midpoint(INT_MAX, INT_MIN) == 0 );
+static_assert( std::midpoint(INT_MAX, INT_MAX) == INT_MAX );
+static_assert( std::midpoint(INT_MAX, INT_MAX-1) == INT_MAX );
+static_assert( std::midpoint(INT_MAX-1, INT_MAX-1) == INT_MAX-1 );
+static_assert( std::midpoint(INT_MAX-1, INT_MAX) == INT_MAX-1 );
+static_assert( std::midpoint(INT_MAX, INT_MAX-2) == INT_MAX-1 );
+
+static_assert( std::midpoint(0u, 0u) == 0 );
+static_assert( std::midpoint(0u, 1u) == 0 );
+static_assert( std::midpoint(1u, 0u) == 1 );
+static_assert( std::midpoint(0u, 2u) == 1 );
+static_assert( std::midpoint(3u, 2u) == 3 );
+static_assert( std::midpoint(0u, UINT_MAX) == UINT_MAX/2 );
+static_assert( std::midpoint(UINT_MAX, 0u) == (UINT_MAX/2 + 1) );
+static_assert( std::midpoint(UINT_MAX, UINT_MAX) == UINT_MAX );
+static_assert( std::midpoint(UINT_MAX, UINT_MAX-1) == UINT_MAX );
+static_assert( std::midpoint(UINT_MAX-1, UINT_MAX-1) == UINT_MAX-1 );
+static_assert( std::midpoint(UINT_MAX-1, UINT_MAX) == UINT_MAX-1 );
+static_assert( std::midpoint(UINT_MAX, UINT_MAX-2) == UINT_MAX-1 );
+
+static_assert( std::midpoint<short>(0, 0) == 0 );
+static_assert( std::midpoint<short>(0, 1) == 0 );
+static_assert( std::midpoint<short>(1, 0) == 1 );
+static_assert( std::midpoint<short>(0, 2) == 1 );
+static_assert( std::midpoint<short>(3, 2) == 3 );
+static_assert( std::midpoint<short>(-5, 4) == -1 );
+static_assert( std::midpoint<short>(5, -4) == 1 );
+static_assert( std::midpoint<short>(-5, -4) == -5 );
+static_assert( std::midpoint<short>(-4, -5) == -4 );
+static_assert( std::midpoint<short>(SHRT_MIN, SHRT_MAX) == -1 );
+static_assert( std::midpoint<short>(SHRT_MAX, SHRT_MIN) == 0 );
+static_assert( std::midpoint<short>(SHRT_MAX, SHRT_MAX) == SHRT_MAX );
+static_assert( std::midpoint<short>(SHRT_MAX, SHRT_MAX-1) == SHRT_MAX );
+static_assert( std::midpoint<short>(SHRT_MAX-1, SHRT_MAX-1) == SHRT_MAX-1 );
+static_assert( std::midpoint<short>(SHRT_MAX-1, SHRT_MAX) == SHRT_MAX-1 );
+static_assert( std::midpoint<short>(SHRT_MAX, SHRT_MAX-2) == SHRT_MAX-1 );
+
+static_assert( std::midpoint<signed char>(0, 0) == 0 );
+static_assert( std::midpoint<signed char>(1, 1) == 1 );
+static_assert( std::midpoint<signed char>(0, 1) == 0 );
+static_assert( std::midpoint<signed char>(1, 0) == 1 );
+static_assert( std::midpoint<signed char>(0, 2) == 1 );
+static_assert( std::midpoint<signed char>(3, 2) == 3 );
+static_assert( std::midpoint<signed char>(-5, 4) == -1 );
+static_assert( std::midpoint<signed char>(5, -4) == 1 );
+static_assert( std::midpoint<signed char>(-5, -4) == -5 );
+static_assert( std::midpoint<signed char>(-4, -5) == -4 );
+static_assert( std::midpoint<signed char>(SCHAR_MIN, SCHAR_MAX) == -1 );
+static_assert( std::midpoint<signed char>(SCHAR_MAX, SCHAR_MIN) == 0 );
+static_assert( std::midpoint<signed char>(SCHAR_MAX, SCHAR_MAX) == SCHAR_MAX );
+static_assert( std::midpoint<signed char>(SCHAR_MAX, SCHAR_MAX-1) == SCHAR_MAX);
+
+void
+test01()
+{
+ // Test every possibility for signed char.
+ for (int a = SCHAR_MIN; a <= SCHAR_MAX; ++a)
+ for (int b = SCHAR_MIN; b <= SCHAR_MAX; ++b)
+ VERIFY( std::midpoint(a, b) == std::midpoint<int>(a, b) );
+}
+
+int main()
+{
+ test01();
+}
--- /dev/null
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <numeric>
+#include <climits>
+#include <testsuite_hooks.h>
+
+const int* p = nullptr;
+static_assert(std::is_same_v<decltype(std::midpoint(p, p)), decltype(p)>);
+// This is a GNU extension:
+static_assert(noexcept(std::midpoint(p, p)));
+
+struct test_type { };
+template<typename T> decltype(std::midpoint((T*)0, (T*)0)) try_midpoint(int);
+template<typename T> test_type try_midpoint(...);
+template<typename T> constexpr bool no_midpoint()
+{ return std::is_same_v<decltype(try_midpoint<T>()), test_type>; }
+
+static_assert(no_midpoint<void>());
+static_assert(no_midpoint<int()>());
+static_assert(no_midpoint<int&>());
+static_assert(no_midpoint<struct Incomplete>());
+
+constexpr int ca[3] = {};
+static_assert( std::midpoint(ca, ca+3) == ca+1 );
+
+void
+test01()
+{
+ int a[4];
+ VERIFY( std::midpoint(a, a) == a );
+ VERIFY( std::midpoint(a, a+1) == a );
+ VERIFY( std::midpoint(a, a+2) == a+1 );
+ VERIFY( std::midpoint(a, a+3) == a+1 );
+ VERIFY( std::midpoint(a, a+4) == a+2 );
+ VERIFY( std::midpoint(a+1, a) == a+1 );
+ VERIFY( std::midpoint(a+2, a) == a+1 );
+ VERIFY( std::midpoint(a+3, a) == a+2 );
+ VERIFY( std::midpoint(a+4, a) == a+2 );
+}
+
+int main()
+{
+ test01();
+}