blob: 1f20961825b76d3b3b4faf5793070ba07b5bf4ee [file] [log] [blame]
// Copyright (C) 2020-2021 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/>.
// expensive: * [1-9] * *
#include "bits/verify.h"
#include "bits/metahelpers.h"
#include "bits/test_values.h"
#include <random>
template <typename V>
void
test()
{
using T = typename V::value_type;
COMPARE(reduce(V(1)), T(V::size()));
{
V x = 1;
COMPARE(reduce(x, std::multiplies<>()), T(1));
x[0] = 2;
COMPARE(reduce(x, std::multiplies<>()), T(2));
if constexpr (V::size() > 1)
{
x[V::size() - 1] = 3;
COMPARE(reduce(x, std::multiplies<>()), T(6));
}
}
COMPARE(reduce(V([](int i) { return i & 1; })), T(V::size() / 2));
COMPARE(reduce(V([](int i) { return i % 3; })),
T(3 * (V::size() / 3) // 0+1+2 for every complete 3 elements in V
+ (V::size() % 3) / 2 // 0->0, 1->0, 2->1 adjustment
));
if ((1 + V::size()) * V::size() / 2 <= std::__finite_max_v<T>)
{
COMPARE(reduce(V([](int i) { return i + 1; })),
T((1 + V::size()) * V::size() / 2));
}
{
const V y = 2;
COMPARE(reduce(y), T(2 * V::size()));
COMPARE(reduce(where(y > 2, y)), T(0));
COMPARE(reduce(where(y == 2, y)), T(2 * V::size()));
}
{
COMPARE(hmin(V(1)), T(1));
COMPARE(hmax(V(1)), T(1));
const V z([](T i) { return i + 1; });
COMPARE(std::experimental::reduce(z,
[](auto a, auto b) {
using std::min;
return min(a, b);
}),
T(1))
<< "z: " << z;
COMPARE(std::experimental::reduce(z,
[](auto a, auto b) {
using std::max;
return max(a, b);
}),
T(V::size()))
<< "z: " << z;
COMPARE(std::experimental::reduce(where(z > 1, z), 117,
[](auto a, auto b) {
using std::min;
return min(a, b);
}),
T(V::size() == 1 ? 117 : 2))
<< "z: " << z;
COMPARE(hmin(z), T(1));
COMPARE(hmax(z), T(V::size()));
if (V::size() > 1)
{
COMPARE(hmin(where(z > 1, z)), T(2));
COMPARE(hmax(where(z > 1, z)), T(V::size()));
}
COMPARE(hmin(where(z < 4, z)), T(1));
COMPARE(hmax(where(z < 4, z)), std::min(T(V::size()), T(3)));
const V zz = make_value_unknown(z);
COMPARE(hmin(zz), T(1));
COMPARE(hmax(zz), T(V::size()));
if (V::size() > 1)
{
COMPARE(hmin(where(zz > 1, zz)), T(2));
COMPARE(hmax(where(zz > 1, zz)), T(V::size()));
}
COMPARE(hmin(where(zz < 4, zz)), T(1));
COMPARE(hmax(where(zz < 4, zz)), std::min(T(V::size()), T(3)));
}
test_values<V>({}, {1000}, [](V x) {
// avoid over-/underflow on signed integers:
if constexpr (std::is_signed_v<T> && std::is_integral_v<T>)
x /= int(V::size());
// The error in the following could be huge if catastrophic
// cancellation occurs. (e.g. `a-a+b+b` vs. `a+b+b-a`).
// Avoid catastrophic cancellation for floating point:
if constexpr (std::is_floating_point_v<T>)
x = abs(x);
T acc = x[0];
for (size_t i = 1; i < V::size(); ++i)
acc += x[i];
ULP_COMPARE(reduce(x), acc, V::size() / 2).on_failure("x = ", x);
});
}