Skip to content
Snippets Groups Projects
Commit 95f5932b authored by namark's avatar namark
Browse files

clever midpoint now for integers,

along with way, wayback, halfway, halfwayback and "improved" average.
parent 683852b2
No related branches found
No related tags found
No related merge requests found
...@@ -273,40 +273,107 @@ namespace simple::support ...@@ -273,40 +273,107 @@ namespace simple::support
template <typename... Numbers> template <typename... Numbers>
[[nodiscard]] constexpr [[nodiscard]] constexpr
auto average(Numbers... n) auto average(Numbers... n)
//TODO: noexcept account for return value construction //TODO: noexcept account for return value and default construction
//TODO: cast size to result type of sum instead of int
noexcept(noexcept((n + ...) / int(sizeof...(n)))) noexcept(noexcept((n + ...) / int(sizeof...(n))))
{ {
return (n + ...) / int(sizeof...(n)); using Sum = decltype((n + ...));
return (n + ...) / (Sum{} + sizeof...(n));
}
template <typename Number, typename Ratio>
[[nodiscard]] constexpr
Number way(Number from, Number to, Ratio ratio)
noexcept(noexcept(Number(from + (to - from)*ratio)))
{
return from + (to - from)*ratio;
}
template <typename Number, typename Ratio>
[[nodiscard]] constexpr
Number wayback(Number from, Number to, Ratio ratio)
noexcept(noexcept(Number(from - (from - to)*ratio)))
{
return from - (from - to)*ratio;
} }
template <typename Number> template <typename Number>
[[nodiscard]] constexpr [[nodiscard]] constexpr
Number midpoint(Number a, Number b) Number halfway(Number from, Number to)
noexcept(noexcept(Number(a + (b - a)/2))) // TODO: implement in terms of way with rational 1/2
noexcept(noexcept(Number(from - (from - to)/2)))
{ {
return a + (b - a)/2; return from + (to - from)/2;
}
template <typename Number>
[[nodiscard]] constexpr
Number halfwayback(Number from, Number to)
// TODO: implement in terms of wayback with rational 1/2
noexcept(noexcept(Number(from - (from - to)/2)))
{
return from - (from - to)/2;
}
template <typename Integer,
typename Unsigned = std::make_unsigned_t<Integer>>
[[nodiscard]] constexpr
Integer midpoint(Integer a, Integer b)
// noexcept(noexcept(TODO))
{
using std::numeric_limits;
static_assert(
numeric_limits<Unsigned>::max() >=
Unsigned(numeric_limits<Integer>::max()),
"Unsigned includes Integer"
);
static_assert(
numeric_limits<Unsigned>::max()/2 <=
numeric_limits<Integer>::max(),
"Halfing Unsigned brings it to positive Integer range"
);
static_assert(std::is_unsigned_v<Integer> ||
Unsigned(numeric_limits<Integer>::max()) <=
Unsigned(-Unsigned(numeric_limits<Integer>::min())),
"Can negate a positive Integer"
);
Unsigned diff = Unsigned(b) - Unsigned(a);
// 2's complement with carry as sign
Unsigned negative_2x = -diff; // neg
negative_2x /= 2; // div
Integer negative = -Integer(negative_2x); // neg
Integer positive = diff / 2;
auto overflew = b < a;
return a + (overflew ? negative : positive);
// TODO: this is for geom::vector
// return a + overflew * idiff + !overflew * diff;
} }
template <typename Unsigned> template <typename Unsigned>
[[nodiscard]] constexpr [[nodiscard]] constexpr
Unsigned midpoint_overflow(Unsigned a, Unsigned b) Unsigned umidpoint(Unsigned a, Unsigned b)
// noexcept(noexcept(TODO)) // noexcept(noexcept(TODO))
{ {
Unsigned diff{}; Unsigned diff{};
bool overflew = sub_overflow(diff,b,a); auto overflew = sub_overflow(diff,b,a);
// manual idiv // manual idiv
Unsigned idiff = -diff; // neg Unsigned idiff = -diff; // neg
idiff /= Unsigned{2}; // div idiff /= Unsigned{2}; // div
idiff = -idiff; // neg idiff = -idiff; // neg
// or... 0 - (0 - diff)/2, this is midpointception! TODO: -_- // or... 0 - (0 - diff)/2, this is midpointception! TODO: -_-
// can't use halfwayback here cause promotion ToT
diff /= Unsigned{2}; diff /= 2;
return a + (overflew ? idiff : diff); return a + (overflew ? idiff : diff);
// return a + overflew * idiff + ~overflew * diff; // return a + overflew * idiff + !overflew * diff;
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
// <numeric> // <numeric>
// template <class _Tp> // template <class _Tp>
// _Tp midpoint_overflow(_Tp __a, _Tp __b) noexcept // _Tp midpoint(_Tp __a, _Tp __b) noexcept
// //
#include <stdint.h> #include <stdint.h>
...@@ -30,44 +30,44 @@ void signed_test() ...@@ -30,44 +30,44 @@ void signed_test()
constexpr T three{3}; constexpr T three{3};
constexpr T four{4}; constexpr T four{4};
// ASSERT_SAME_TYPE(decltype(midpoint_overflow(T(), T())), T); static_assert(std::is_same_v<decltype(midpoint(T(), T())), T>);
// ASSERT_NOEXCEPT( midpoint_overflow(T(), T())); // ASSERT_NOEXCEPT( midpoint(T(), T()));
using limits = std::numeric_limits<T>; using limits = std::numeric_limits<T>;
static_assert(midpoint_overflow(one, three) == two, ""); static_assert(midpoint(one, three) == two, "");
static_assert(midpoint_overflow(three, one) == two, ""); static_assert(midpoint(three, one) == two, "");
assert(midpoint_overflow(zero, zero) == zero); assert(midpoint(zero, zero) == zero);
assert(midpoint_overflow(zero, two) == one); assert(midpoint(zero, two) == one);
assert(midpoint_overflow(two, zero) == one); assert(midpoint(two, zero) == one);
assert(midpoint_overflow(two, two) == two); assert(midpoint(two, two) == two);
assert(midpoint_overflow(one, four) == two); assert(midpoint(one, four) == two);
assert(midpoint_overflow(four, one) == three); assert(midpoint(four, one) == three);
assert(midpoint_overflow(three, four) == three); assert(midpoint(three, four) == three);
assert(midpoint_overflow(four, three) == four); assert(midpoint(four, three) == four);
assert(midpoint_overflow(T( 3), T( 4)) == T(3)); assert(midpoint(T( 3), T( 4)) == T(3));
assert(midpoint_overflow(T( 4), T( 3)) == T(4)); assert(midpoint(T( 4), T( 3)) == T(4));
assert(midpoint_overflow(T(-3), T( 4)) == T(0)); assert(midpoint(T(-3), T( 4)) == T(0));
assert(midpoint_overflow(T(-4), T( 3)) == T(-1)); assert(midpoint(T(-4), T( 3)) == T(-1));
assert(midpoint_overflow(T( 3), T(-4)) == T(0)); assert(midpoint(T( 3), T(-4)) == T(0));
assert(midpoint_overflow(T( 4), T(-3)) == T(1)); assert(midpoint(T( 4), T(-3)) == T(1));
assert(midpoint_overflow(T(-3), T(-4)) == T(-3)); assert(midpoint(T(-3), T(-4)) == T(-3));
assert(midpoint_overflow(T(-4), T(-3)) == T(-4)); assert(midpoint(T(-4), T(-3)) == T(-4));
static_assert(midpoint_overflow(limits::min(), limits::max()) == T(-1), ""); static_assert(midpoint(limits::min(), limits::max()) == T(-1), "");
static_assert(midpoint_overflow(limits::max(), limits::min()) == T( 0), ""); static_assert(midpoint(limits::max(), limits::min()) == T( 0), "");
static_assert(midpoint_overflow(limits::min(), T(6)) == limits::min()/2 + 3, ""); static_assert(midpoint(limits::min(), T(6)) == limits::min()/2 + 3, "");
assert( midpoint_overflow(T(6), limits::min()) == limits::min()/2 + 3); assert( midpoint(T(6), limits::min()) == limits::min()/2 + 3);
assert( midpoint_overflow(limits::max(), T(6)) == limits::max()/2 + 4); assert( midpoint(limits::max(), T(6)) == limits::max()/2 + 4);
static_assert(midpoint_overflow(T(6), limits::max()) == limits::max()/2 + 3, ""); static_assert(midpoint(T(6), limits::max()) == limits::max()/2 + 3, "");
assert( midpoint_overflow(limits::min(), T(-6)) == limits::min()/2 - 3); assert( midpoint(limits::min(), T(-6)) == limits::min()/2 - 3);
static_assert(midpoint_overflow(T(-6), limits::min()) == limits::min()/2 - 3, ""); static_assert(midpoint(T(-6), limits::min()) == limits::min()/2 - 3, "");
static_assert(midpoint_overflow(limits::max(), T(-6)) == limits::max()/2 - 2, ""); static_assert(midpoint(limits::max(), T(-6)) == limits::max()/2 - 2, "");
assert( midpoint_overflow(T(-6), limits::max()) == limits::max()/2 - 3); assert( midpoint(T(-6), limits::max()) == limits::max()/2 - 3);
} }
template <typename T> template <typename T>
...@@ -79,46 +79,69 @@ void unsigned_test() ...@@ -79,46 +79,69 @@ void unsigned_test()
constexpr T three{3}; constexpr T three{3};
constexpr T four{4}; constexpr T four{4};
// ASSERT_SAME_TYPE(decltype(midpoint_overflow(T(), T())), T); static_assert(std::is_same_v<decltype(midpoint(T(), T())), T>);
// ASSERT_NOEXCEPT( midpoint_overflow(T(), T())); // ASSERT_NOEXCEPT( midpoint(T(), T()));
using limits = std::numeric_limits<T>; using limits = std::numeric_limits<T>;
const T half_way = (limits::max() - limits::min())/2; const T half_way = (limits::max() - limits::min())/2;
static_assert(midpoint_overflow(one, three) == two, ""); static_assert(midpoint(one, three) == two, "");
static_assert(midpoint_overflow(three, one) == two, ""); static_assert(midpoint(three, one) == two, "");
assert(midpoint_overflow(zero, zero) == zero); assert(midpoint(zero, zero) == zero);
assert(midpoint_overflow(zero, two) == one); assert(midpoint(zero, two) == one);
assert(midpoint_overflow(two, zero) == one); assert(midpoint(two, zero) == one);
assert(midpoint_overflow(two, two) == two); assert(midpoint(two, two) == two);
assert(midpoint_overflow(one, four) == two); assert(midpoint(one, four) == two);
assert(midpoint_overflow(four, one) == three); assert(midpoint(four, one) == three);
assert(midpoint_overflow(three, four) == three); assert(midpoint(three, four) == three);
assert(midpoint_overflow(four, three) == four); assert(midpoint(four, three) == four);
assert(midpoint_overflow(limits::min(), limits::max()) == T(half_way)); assert(midpoint(limits::min(), limits::max()) == T(half_way));
assert(midpoint_overflow(limits::max(), limits::min()) == T(half_way + 1)); assert(midpoint(limits::max(), limits::min()) == T(half_way + 1));
static_assert(midpoint_overflow(limits::min(), T(6)) == limits::min()/2 + 3, ""); static_assert(midpoint(limits::min(), T(6)) == limits::min()/2 + 3, "");
assert( midpoint_overflow(T(6), limits::min()) == limits::min()/2 + 3); assert( midpoint(T(6), limits::min()) == limits::min()/2 + 3);
assert( midpoint_overflow(limits::max(), T(6)) == half_way + 4); assert( midpoint(limits::max(), T(6)) == half_way + 4);
static_assert(midpoint_overflow(T(6), limits::max()) == half_way + 3, ""); static_assert(midpoint(T(6), limits::max()) == half_way + 3, "");
static_assert(std::is_same_v<decltype(umidpoint(T(), T())), T>);
// ASSERT_NOEXCEPT( midpoint(T(), T()));
static_assert(umidpoint(one, three) == two, "");
static_assert(umidpoint(three, one) == two, "");
assert(umidpoint(zero, zero) == zero);
assert(umidpoint(zero, two) == one);
assert(umidpoint(two, zero) == one);
assert(umidpoint(two, two) == two);
assert(umidpoint(one, four) == two);
assert(umidpoint(four, one) == three);
assert(umidpoint(three, four) == three);
assert(umidpoint(four, three) == four);
assert(umidpoint(limits::min(), limits::max()) == T(half_way));
assert(umidpoint(limits::max(), limits::min()) == T(half_way + 1));
static_assert(umidpoint(limits::min(), T(6)) == limits::min()/2 + 3, "");
assert( umidpoint(T(6), limits::min()) == limits::min()/2 + 3);
assert( umidpoint(limits::max(), T(6)) == half_way + 4);
static_assert(umidpoint(T(6), limits::max()) == half_way + 3, "");
} }
int main(int, char**) int main(int, char**)
{ {
// signed_test<signed char>(); signed_test<signed char>();
// signed_test<short>(); signed_test<short>();
// signed_test<int>(); signed_test<int>();
// signed_test<long>(); signed_test<long>();
// signed_test<long long>(); signed_test<long long>();
//
// signed_test<int8_t>(); signed_test<int8_t>();
// signed_test<int16_t>(); signed_test<int16_t>();
// signed_test<int32_t>(); signed_test<int32_t>();
// signed_test<int64_t>(); signed_test<int64_t>();
unsigned_test<unsigned char>(); unsigned_test<unsigned char>();
unsigned_test<unsigned short>(); unsigned_test<unsigned short>();
...@@ -137,7 +160,7 @@ int main(int, char**) ...@@ -137,7 +160,7 @@ int main(int, char**)
#endif #endif
// int_test<char>(); // int_test<char>();
// signed_test<ptrdiff_t>(); signed_test<ptrdiff_t>();
unsigned_test<size_t>(); unsigned_test<size_t>();
return 0; return 0;
......
// Copyright (C) 2019-2020 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/>.
#include <climits>
#include <cassert>
#include "simple/support/algorithm.hpp"
using simple::support::midpoint;
static_assert(std::is_same_v<decltype(midpoint(0, 1)), int>);
static_assert(noexcept(midpoint(1, 2)));
struct test_type { };
template<typename T> decltype(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( midpoint(0, 0) == 0 );
static_assert( midpoint(1, 1) == 1 );
static_assert( midpoint(0, 1) == 0 );
static_assert( midpoint(1, 0) == 1 );
static_assert( midpoint(0, 2) == 1 );
static_assert( midpoint(3, 2) == 3 );
static_assert( midpoint(-5, 4) == -1 );
static_assert( midpoint(5, -4) == 1 );
static_assert( midpoint(-5, -4) == -5 );
static_assert( midpoint(-4, -5) == -4 );
static_assert( midpoint(INT_MIN, INT_MAX) == -1 );
static_assert( midpoint(INT_MAX, INT_MIN) == 0 );
static_assert( midpoint(INT_MAX, INT_MAX) == INT_MAX );
static_assert( midpoint(INT_MAX, INT_MAX-1) == INT_MAX );
static_assert( midpoint(INT_MAX-1, INT_MAX-1) == INT_MAX-1 );
static_assert( midpoint(INT_MAX-1, INT_MAX) == INT_MAX-1 );
static_assert( midpoint(INT_MAX, INT_MAX-2) == INT_MAX-1 );
static_assert( midpoint(0u, 0u) == 0 );
static_assert( midpoint(0u, 1u) == 0 );
static_assert( midpoint(1u, 0u) == 1 );
static_assert( midpoint(0u, 2u) == 1 );
static_assert( midpoint(3u, 2u) == 3 );
static_assert( midpoint(0u, UINT_MAX) == UINT_MAX/2 );
static_assert( midpoint(UINT_MAX, 0u) == (UINT_MAX/2 + 1) );
static_assert( midpoint(UINT_MAX, UINT_MAX) == UINT_MAX );
static_assert( midpoint(UINT_MAX, UINT_MAX-1) == UINT_MAX );
static_assert( midpoint(UINT_MAX-1, UINT_MAX-1) == UINT_MAX-1 );
static_assert( midpoint(UINT_MAX-1, UINT_MAX) == UINT_MAX-1 );
static_assert( midpoint(UINT_MAX, UINT_MAX-2) == UINT_MAX-1 );
static_assert( midpoint<short>(0, 0) == 0 );
static_assert( midpoint<short>(0, 1) == 0 );
static_assert( midpoint<short>(1, 0) == 1 );
static_assert( midpoint<short>(0, 2) == 1 );
static_assert( midpoint<short>(3, 2) == 3 );
static_assert( midpoint<short>(-5, 4) == -1 );
static_assert( midpoint<short>(5, -4) == 1 );
static_assert( midpoint<short>(-5, -4) == -5 );
static_assert( midpoint<short>(-4, -5) == -4 );
static_assert( midpoint<short>(SHRT_MIN, SHRT_MAX) == -1 );
static_assert( midpoint<short>(SHRT_MAX, SHRT_MIN) == 0 );
static_assert( midpoint<short>(SHRT_MAX, SHRT_MAX) == SHRT_MAX );
static_assert( midpoint<short>(SHRT_MAX, SHRT_MAX-1) == SHRT_MAX );
static_assert( midpoint<short>(SHRT_MAX-1, SHRT_MAX-1) == SHRT_MAX-1 );
static_assert( midpoint<short>(SHRT_MAX-1, SHRT_MAX) == SHRT_MAX-1 );
static_assert( midpoint<short>(SHRT_MAX, SHRT_MAX-2) == SHRT_MAX-1 );
static_assert( midpoint<signed char>(0, 0) == 0 );
static_assert( midpoint<signed char>(1, 1) == 1 );
static_assert( midpoint<signed char>(0, 1) == 0 );
static_assert( midpoint<signed char>(1, 0) == 1 );
static_assert( midpoint<signed char>(0, 2) == 1 );
static_assert( midpoint<signed char>(3, 2) == 3 );
static_assert( midpoint<signed char>(-5, 4) == -1 );
static_assert( midpoint<signed char>(5, -4) == 1 );
static_assert( midpoint<signed char>(-5, -4) == -5 );
static_assert( midpoint<signed char>(-4, -5) == -4 );
static_assert( midpoint<signed char>(SCHAR_MIN, SCHAR_MAX) == -1 );
static_assert( midpoint<signed char>(SCHAR_MAX, SCHAR_MIN) == 0 );
static_assert( midpoint<signed char>(SCHAR_MAX, SCHAR_MAX) == SCHAR_MAX );
static_assert( 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)
assert( midpoint(a, b) == midpoint<int>(a, b) );
}
int main()
{
test01();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment