Skip to content

Commit a21f35b

Browse files
committed
More tests
1 parent ecf54d5 commit a21f35b

9 files changed

+408
-278
lines changed

cpp/arcticdb/util/mean.hpp

+63-37
Original file line numberDiff line numberDiff line change
@@ -8,72 +8,98 @@
88

99
namespace arcticdb {
1010

11-
#ifndef _WIN32
11+
#if HAS_VECTOR_EXTENSIONS
12+
13+
template<typename Vec, typename U>
14+
inline void fill_vector(Vec &vec, U value) {
15+
U* p = reinterpret_cast<U*>(&vec);
16+
constexpr size_t count = sizeof(Vec) / sizeof(U);
17+
for (size_t i = 0; i < count; i++) {
18+
p[i] = value;
19+
}
20+
}
1221

1322
template<typename T>
1423
class MeanFinder {
1524
static_assert(is_supported_int<T>::value || is_supported_float<T>::value, "Unsupported type");
16-
1725
public:
1826
static double find(const T* __restrict data, size_t n) {
27+
util::check(n > 0, "Empty array provided");
1928
using VectorType = vector_type<T>;
2029
using AccumVectorType = vector_type<double>;
21-
22-
AccumVectorType vsum = {0.0};
2330
constexpr size_t elements_per_vector = sizeof(VectorType) / sizeof(T);
2431
constexpr size_t doubles_per_vector = sizeof(AccumVectorType) / sizeof(double);
2532
constexpr size_t vectors_per_acc = elements_per_vector / doubles_per_vector;
26-
33+
AccumVectorType vsum;
34+
double* vsum_ptr = reinterpret_cast<double*>(&vsum);
35+
fill_vector<AccumVectorType, double>(vsum, 0.0);
2736
size_t valid_count = 0;
28-
29-
const auto* vdata = reinterpret_cast<const VectorType*>(data);
37+
const VectorType* vdata = reinterpret_cast<const VectorType*>(data);
3038
const size_t vector_len = n / elements_per_vector;
31-
32-
for(size_t i = 0; i < vector_len; i++) {
39+
for (size_t i = 0; i < vector_len; i++) {
3340
VectorType v = vdata[i];
34-
35-
if constexpr(std::is_floating_point_v<T>) {
36-
VectorType mask = v == v;
37-
v = v & mask;
38-
39-
const T* mask_arr = reinterpret_cast<const T*>(&mask);
40-
41-
for(size_t j = 0; j < elements_per_vector; j++) {
42-
if(mask_arr[j] != 0)
43-
++valid_count;
41+
const T* v_arr = reinterpret_cast<const T*>(&v);
42+
if constexpr (std::is_floating_point_v<T>) {
43+
bool has_nan = false;
44+
for (size_t j = 0; j < elements_per_vector; j++) {
45+
if (std::isnan(v_arr[j])) { has_nan = true; break; }
46+
}
47+
if (!has_nan) {
48+
for (size_t chunk = 0; chunk < vectors_per_acc; chunk++) {
49+
size_t base = chunk * doubles_per_vector;
50+
for (size_t j = 0; j < doubles_per_vector; j++) {
51+
if constexpr (std::is_same_v<T, double>)
52+
vsum_ptr[j] += v_arr[base + j];
53+
else
54+
vsum_ptr[j] += static_cast<double>(v_arr[base + j]);
55+
}
56+
}
57+
valid_count += elements_per_vector;
58+
} else {
59+
for (size_t chunk = 0; chunk < vectors_per_acc; chunk++) {
60+
size_t base = chunk * doubles_per_vector;
61+
for (size_t j = 0; j < doubles_per_vector; j++) {
62+
size_t idx = base + j;
63+
if (!std::isnan(v_arr[idx])) {
64+
if constexpr (std::is_same_v<T, double>)
65+
vsum_ptr[j] += v_arr[idx];
66+
else
67+
vsum_ptr[j] += static_cast<double>(v_arr[idx]);
68+
valid_count++;
69+
}
70+
}
71+
}
4472
}
4573
} else {
46-
valid_count += elements_per_vector;
47-
}
48-
49-
const T* v_arr = reinterpret_cast<const T*>(&v);
50-
for(size_t chunk = 0; chunk < vectors_per_acc; chunk++) {
51-
for(size_t j = 0; j < doubles_per_vector; j++) {
52-
size_t idx = chunk * doubles_per_vector + j;
53-
reinterpret_cast<double*>(&vsum)[j] += static_cast<double>(v_arr[idx]);
74+
for (size_t chunk = 0; chunk < vectors_per_acc; chunk++) {
75+
size_t base = chunk * doubles_per_vector;
76+
for (size_t j = 0; j < doubles_per_vector; j++) {
77+
vsum_ptr[j] += static_cast<double>(v_arr[base + j]);
78+
}
5479
}
80+
valid_count += elements_per_vector;
5581
}
5682
}
57-
5883
double total = 0.0;
59-
const auto* sum_arr = reinterpret_cast<const double*>(&vsum);
60-
for(size_t i = 0; i < doubles_per_vector; i++) {
61-
total += sum_arr[i];
84+
for (size_t j = 0; j < doubles_per_vector; j++) {
85+
total += vsum_ptr[j];
6286
}
63-
6487
const T* remain = data + (vector_len * elements_per_vector);
65-
for(size_t i = 0; i < n % elements_per_vector; i++) {
66-
if constexpr(std::is_floating_point_v<T>) {
67-
if (remain[i] == remain[i]) { // Not NaN
68-
total += static_cast<double>(remain[i]);
88+
size_t rem = n % elements_per_vector;
89+
for (size_t i = 0; i < rem; i++) {
90+
if constexpr (std::is_floating_point_v<T>) {
91+
if (!std::isnan(remain[i])) {
92+
if constexpr (std::is_same_v<T, double>)
93+
total += remain[i];
94+
else
95+
total += static_cast<double>(remain[i]);
6996
valid_count++;
7097
}
7198
} else {
7299
total += static_cast<double>(remain[i]);
73100
valid_count++;
74101
}
75102
}
76-
77103
return valid_count > 0 ? total / static_cast<double>(valid_count) : 0.0;
78104
}
79105
};

cpp/arcticdb/util/min_max_float.hpp

+42-72
Original file line numberDiff line numberDiff line change
@@ -7,106 +7,76 @@
77
#include <arcticdb/util/vector_common.hpp>
88

99
namespace arcticdb {
10-
#ifndef _WIN32
1110

12-
template<typename T>
13-
class FloatMinFinder {
11+
#if HAS_VECTOR_EXTENSIONS
12+
13+
template<typename T, typename Comparator>
14+
class FloatExtremumFinder {
1415
static_assert(is_supported_float<T>::value, "Type must be float or double");
1516
static_assert(std::is_floating_point_v<T>, "Type must be floating point");
16-
1717
public:
1818
static T find(const T* data, size_t n) {
19+
if (n == 0)
20+
return Comparator::identity();
1921
using vec_t = vector_type<T>;
20-
21-
vec_t vmin;
22-
for(size_t i = 0; i < sizeof(vec_t)/sizeof(T); i++) {
23-
reinterpret_cast<T*>(&vmin)[i] = std::numeric_limits<T>::infinity();
24-
}
22+
constexpr size_t lane_count = sizeof(vec_t) / sizeof(T);
23+
vec_t vext;
24+
for (size_t i = 0; i < lane_count; i++)
25+
reinterpret_cast<T*>(&vext)[i] = Comparator::identity();
2526

2627
const vec_t* vdata = reinterpret_cast<const vec_t*>(data);
27-
const size_t elements_per_vector = sizeof(vec_t) / sizeof(T);
28-
const size_t vlen = n / elements_per_vector;
29-
30-
for(size_t i = 0; i < vlen; i++) {
28+
size_t vlen = n / lane_count;
29+
for (size_t i = 0; i < vlen; i++) {
3130
vec_t v = vdata[i];
32-
vmin = (v < vmin) ? v : vmin;
31+
if constexpr (Comparator::is_min)
32+
vext = (v < vext) ? v : vext;
33+
else
34+
vext = (v > vext) ? v : vext;
3335
}
34-
35-
T min_val = std::numeric_limits<T>::infinity();
36-
const T* min_arr = reinterpret_cast<const T*>(&vmin);
37-
for(size_t i = 0; i < elements_per_vector; i++) {
38-
if (min_arr[i] == min_arr[i]) { // Not NaN
39-
min_val = std::min(min_val, min_arr[i]);
40-
}
36+
T result = Comparator::identity();
37+
const T* lanes = reinterpret_cast<const T*>(&vext);
38+
for (size_t i = 0; i < lane_count; i++) {
39+
if (lanes[i] == lanes[i])
40+
result = Comparator::compare(lanes[i], result);
4141
}
42-
43-
const T* remain = data + (vlen * elements_per_vector);
44-
for(size_t i = 0; i < n % elements_per_vector; i++) {
45-
if (remain[i] == remain[i]) { // Not NaN
46-
min_val = std::min(min_val, remain[i]);
47-
}
42+
const T* remain = data + (vlen * lane_count);
43+
size_t remain_count = n % lane_count;
44+
for (size_t i = 0; i < remain_count; i++) {
45+
if (remain[i] == remain[i])
46+
result = Comparator::compare(remain[i], result);
4847
}
49-
50-
return min_val;
48+
return result;
5149
}
5250
};
5351

5452
template<typename T>
55-
class FloatMaxFinder {
56-
static_assert(is_supported_float<T>::value, "Type must be float or double");
57-
static_assert(std::is_floating_point_v<T>, "Type must be floating point");
58-
59-
public:
60-
static T find(const T* data, size_t n) {
61-
using vec_t = vector_type<T>;
62-
63-
vec_t vmax;
64-
for(size_t i = 0; i < sizeof(vec_t)/sizeof(T); i++) {
65-
reinterpret_cast<T*>(&vmax)[i] = -std::numeric_limits<T>::infinity();
66-
}
67-
68-
const vec_t* vdata = reinterpret_cast<const vec_t*>(data);
69-
const size_t elements_per_vector = sizeof(vec_t) / sizeof(T);
70-
const size_t vlen = n / elements_per_vector;
71-
72-
for(size_t i = 0; i < vlen; i++) {
73-
vec_t v = vdata[i];
74-
vmax = (v > vmax) ? v : vmax;
75-
}
76-
77-
T max_val = -std::numeric_limits<T>::infinity();
78-
const T* max_arr = reinterpret_cast<const T*>(&vmax);
79-
for(size_t i = 0; i < elements_per_vector; i++) {
80-
if (max_arr[i] == max_arr[i]) { // Not NaN
81-
max_val = std::max(max_val, max_arr[i]);
82-
}
83-
}
84-
85-
const T* remain = data + (vlen * elements_per_vector);
86-
for(size_t i = 0; i < n % elements_per_vector; i++) {
87-
if (remain[i] == remain[i]) { // Not NaN
88-
max_val = std::max(max_val, remain[i]);
89-
}
90-
}
53+
struct FloatMinComparator {
54+
static constexpr bool is_min = true;
55+
static T identity() { return std::numeric_limits<T>::infinity(); }
56+
static T compare(T a, T b) { return std::min(a, b); }
57+
};
9158

92-
return max_val;
93-
}
59+
template<typename T>
60+
struct FloatMaxComparator {
61+
static constexpr bool is_min = false;
62+
static T identity() { return -std::numeric_limits<T>::infinity(); }
63+
static T compare(T a, T b) { return std::max(a, b); }
9464
};
9565

9666
template<typename T>
97-
T find_float_min(const T *data, size_t n) {
98-
return FloatMinFinder<T>::find(data, n);
67+
T find_float_min(const T* data, size_t n) {
68+
return FloatExtremumFinder<T, FloatMinComparator<T>>::find(data, n);
9969
}
10070

10171
template<typename T>
102-
T find_float_max(const T *data, size_t n) {
103-
return FloatMaxFinder<T>::find(data, n);
72+
T find_float_max(const T* data, size_t n) {
73+
return FloatExtremumFinder<T, FloatMaxComparator<T>>::find(data, n);
10474
}
10575

10676
#else
10777

10878
template<typename T>
109-
typename std::enable_if<std::is_integral<T>::value, T>::type
79+
typename std::enable_if<std::is_floating_point<T>::value, T>::type
11080
find_float_min(const T *data, size_t n) {
11181
return *std::min_element(data, data + n);
11282
}

0 commit comments

Comments
 (0)