tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
midpoint.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2021 Tobias Hienzsch
3#ifndef TETL_NUMERIC_MIDPOINT_HPP
4#define TETL_NUMERIC_MIDPOINT_HPP
5
6#include <etl/_concepts/floating_point.hpp>
7#include <etl/_cstddef/ptrdiff_t.hpp>
8#include <etl/_limits/numeric_limits.hpp>
9#include <etl/_numeric/abs.hpp>
10#include <etl/_type_traits/is_integral.hpp>
11#include <etl/_type_traits/is_pointer.hpp>
12#include <etl/_type_traits/is_same.hpp>
13#include <etl/_type_traits/make_unsigned.hpp>
14
15namespace etl {
16
17/// \brief Returns half the sum of a + b. If the sum is odd, the result is
18/// rounded towards a.
19///
20/// \details CppCon 2019: Marshall Clow "midpoint? How Hard Could it Be?"
21/// Integer version was updated to match implementation from libc++.
22///
23/// https://www.youtube.com/watch?v=sBtAGxBh-XI)
24/// https://en.cppreference.com/w/cpp/numeric/midpoint
25///
26/// \ingroup numeric
27template <typename Int>
28 requires(etl::is_integral_v<Int> and not etl::is_same_v<Int, bool>)
29constexpr auto midpoint(Int a, Int b) noexcept -> Int
30{
31 using UInt = etl::make_unsigned_t<Int>;
32
33 auto const shift = static_cast<UInt>(etl::numeric_limits<UInt>::digits - 1);
34 auto const diff = static_cast<UInt>(UInt(b) - UInt(a));
35 auto const sign = static_cast<UInt>(b < a);
36 auto const half = static_cast<UInt>((diff / 2) + (sign << shift) + (sign & diff));
37
38 return a + static_cast<Int>(half);
39}
40
41/// \ingroup numeric
42template <etl::floating_point Float>
43constexpr auto midpoint(Float a, Float b) noexcept -> Float
44{
45 auto const lo = etl::numeric_limits<Float>::min() * 2;
46 auto const hi = etl::numeric_limits<Float>::max() / 2;
47
48 if (etl::abs(a) <= hi and etl::abs(b) <= hi) {
49 return (a + b) / 2;
50 }
51 if (etl::abs(a) < lo) {
52 return a + b / 2;
53 }
54 if (etl::abs(b) < lo) {
55 return a / 2 + b;
56 }
57
58 return a / 2 + b / 2;
59}
60
61/// \ingroup numeric
62template <typename Ptr>
63 requires etl::is_pointer_v<Ptr>
64constexpr auto midpoint(Ptr a, Ptr b) noexcept -> Ptr
65{
66 return a + etl::midpoint(etl::ptrdiff_t(0), b - a);
67}
68
69} // namespace etl
70
71#endif // TETL_NUMERIC_MIDPOINT_HPP
constexpr auto midpoint(Int a, Int b) noexcept -> Int
Returns half the sum of a + b. If the sum is odd, the result is rounded towards a.
Definition midpoint.hpp:29
Definition adjacent_find.hpp:9
Definition numeric_limits.hpp:18