xref: /llvm-project/libcxx/include/__cxx03/__numeric/midpoint.h (revision ce7771902dc50d900de639d499a60486b83f70e0)
1e78f53d1SNikolas Klauser // -*- C++ -*-
2e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
3e78f53d1SNikolas Klauser //
4e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
6e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7e78f53d1SNikolas Klauser //
8e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===//
9e78f53d1SNikolas Klauser 
10*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___NUMERIC_MIDPOINT_H
11*ce777190SNikolas Klauser #define _LIBCPP___CXX03___NUMERIC_MIDPOINT_H
12e78f53d1SNikolas Klauser 
1373fbae83SNikolas Klauser #include <__cxx03/__config>
1473fbae83SNikolas Klauser #include <__cxx03/__type_traits/enable_if.h>
1573fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_floating_point.h>
1673fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_integral.h>
1773fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_null_pointer.h>
1873fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_object.h>
1973fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_pointer.h>
2073fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_same.h>
2173fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_void.h>
2273fbae83SNikolas Klauser #include <__cxx03/__type_traits/make_unsigned.h>
2373fbae83SNikolas Klauser #include <__cxx03/__type_traits/remove_pointer.h>
2473fbae83SNikolas Klauser #include <__cxx03/cstddef>
2573fbae83SNikolas Klauser #include <__cxx03/limits>
26e78f53d1SNikolas Klauser 
27e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
28e78f53d1SNikolas Klauser #  pragma GCC system_header
29e78f53d1SNikolas Klauser #endif
30e78f53d1SNikolas Klauser 
31e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS
3273fbae83SNikolas Klauser #include <__cxx03/__undef_macros>
33e78f53d1SNikolas Klauser 
34e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD
35e78f53d1SNikolas Klauser 
36e78f53d1SNikolas Klauser #if _LIBCPP_STD_VER >= 20
37e78f53d1SNikolas Klauser template <class _Tp>
38e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<is_integral_v<_Tp> && !is_same_v<bool, _Tp> && !is_null_pointer_v<_Tp>, _Tp>
39e78f53d1SNikolas Klauser midpoint(_Tp __a, _Tp __b) noexcept _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK {
40e78f53d1SNikolas Klauser   using _Up                = make_unsigned_t<_Tp>;
41e78f53d1SNikolas Klauser   constexpr _Up __bitshift = numeric_limits<_Up>::digits - 1;
42e78f53d1SNikolas Klauser 
43e78f53d1SNikolas Klauser   _Up __diff     = _Up(__b) - _Up(__a);
44e78f53d1SNikolas Klauser   _Up __sign_bit = __b < __a;
45e78f53d1SNikolas Klauser 
46e78f53d1SNikolas Klauser   _Up __half_diff = (__diff / 2) + (__sign_bit << __bitshift) + (__sign_bit & __diff);
47e78f53d1SNikolas Klauser 
48e78f53d1SNikolas Klauser   return __a + __half_diff;
49e78f53d1SNikolas Klauser }
50e78f53d1SNikolas Klauser 
51e78f53d1SNikolas Klauser template <class _Tp, enable_if_t<is_object_v<_Tp> && !is_void_v<_Tp> && (sizeof(_Tp) > 0), int> = 0>
52e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Tp* midpoint(_Tp* __a, _Tp* __b) noexcept {
53e78f53d1SNikolas Klauser   return __a + std::midpoint(ptrdiff_t(0), __b - __a);
54e78f53d1SNikolas Klauser }
55e78f53d1SNikolas Klauser 
56e78f53d1SNikolas Klauser template <typename _Tp>
57e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr int __sign(_Tp __val) {
58e78f53d1SNikolas Klauser   return (_Tp(0) < __val) - (__val < _Tp(0));
59e78f53d1SNikolas Klauser }
60e78f53d1SNikolas Klauser 
61e78f53d1SNikolas Klauser template <typename _Fp>
62e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr _Fp __fp_abs(_Fp __f) {
63e78f53d1SNikolas Klauser   return __f >= 0 ? __f : -__f;
64e78f53d1SNikolas Klauser }
65e78f53d1SNikolas Klauser 
66e78f53d1SNikolas Klauser template <class _Fp>
67e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<is_floating_point_v<_Fp>, _Fp> midpoint(_Fp __a, _Fp __b) noexcept {
68e78f53d1SNikolas Klauser   constexpr _Fp __lo = numeric_limits<_Fp>::min() * 2;
69e78f53d1SNikolas Klauser   constexpr _Fp __hi = numeric_limits<_Fp>::max() / 2;
70e78f53d1SNikolas Klauser 
71e78f53d1SNikolas Klauser   // typical case: overflow is impossible
72e78f53d1SNikolas Klauser   if (std::__fp_abs(__a) <= __hi && std::__fp_abs(__b) <= __hi)
73e78f53d1SNikolas Klauser     return (__a + __b) / 2; // always correctly rounded
74e78f53d1SNikolas Klauser   if (std::__fp_abs(__a) < __lo)
75e78f53d1SNikolas Klauser     return __a + __b / 2; // not safe to halve a
76e78f53d1SNikolas Klauser   if (std::__fp_abs(__b) < __lo)
77e78f53d1SNikolas Klauser     return __a / 2 + __b; // not safe to halve b
78e78f53d1SNikolas Klauser 
79e78f53d1SNikolas Klauser   return __a / 2 + __b / 2; // otherwise correctly rounded
80e78f53d1SNikolas Klauser }
81e78f53d1SNikolas Klauser 
82e78f53d1SNikolas Klauser #endif // _LIBCPP_STD_VER >= 20
83e78f53d1SNikolas Klauser 
84e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD
85e78f53d1SNikolas Klauser 
86e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS
87e78f53d1SNikolas Klauser 
88*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___NUMERIC_MIDPOINT_H
89