Skip to content

Commit e6b58e5

Browse files
committed
less unif_rand() in impl_paired_pmt
1 parent c72b0c0 commit e6b58e5

3 files changed

Lines changed: 59 additions & 19 deletions

File tree

inst/include/pmt/impl_paired_pmt.hpp

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
#pragma once
22

3+
#include <cstdint>
4+
5+
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T> && sizeof(T) == 4>>
6+
int countr_zero_u32(T x)
7+
{
8+
static constexpr std::array<int, 32> multiply_debruijn_bit_position = {
9+
0, 1, 28, 2, 29, 14, 24, 3,
10+
30, 22, 20, 15, 25, 17, 4, 8,
11+
31, 27, 13, 23, 21, 19, 16, 7,
12+
26, 12, 18, 6, 11, 5, 10, 9
13+
};
14+
15+
return multiply_debruijn_bit_position[static_cast<std::uint32_t>((x & -x) * 0x077CB531U) >> 27];
16+
}
17+
318
template <bool progress, typename T>
419
RObject impl_paired_pmt(
520
NumericVector x,
@@ -17,7 +32,7 @@ RObject impl_paired_pmt(
1732

1833
R_xlen_t n = x.size();
1934

20-
statistic_container.allocate(1, n_permu != 0 ? n_permu : 1 << n);
35+
statistic_container.allocate(1, n_permu != 0 ? n_permu : R_xlen_t{ 1 } << n);
2136

2237
#ifdef SETJMP
2338
SETJMP(statistic_func)
@@ -37,7 +52,7 @@ RObject impl_paired_pmt(
3752
statistic_container.switch_ptr();
3853
if (n_permu == 0) {
3954
R_xlen_t swapped = 0;
40-
for (R_xlen_t i = 0; i < n; i = swapped & (1 << i) ? 0 : i + 1) {
55+
for (R_xlen_t i = 0; i < n; i = swapped & (R_xlen_t{ 1 } << i) ? 0 : i + 1) {
4156
if (i == 0) {
4257
paired_update();
4358
}
@@ -46,11 +61,35 @@ RObject impl_paired_pmt(
4661
swapped ^= (1 << i);
4762
}
4863
} else {
49-
do {
50-
for (R_xlen_t i = 0; i < n; i++) {
51-
swap_if(unif_rand() > 0.5, x[i], y[i]);
64+
const R_xlen_t full_n = (n / 32) * 32;
65+
66+
auto unif_rand_u32 = []() -> std::uint32_t {
67+
return unif_rand() * 4294967296.0;
68+
};
69+
70+
auto do_flip = [x, y](R_xlen_t start, std::uint32_t flip) mutable {
71+
while (flip) {
72+
R_xlen_t i = start + countr_zero_u32(flip);
73+
std::swap(x[i], y[i]);
74+
flip &= flip - 1;
5275
}
53-
} while (paired_update());
76+
};
77+
78+
if (n == full_n) {
79+
do {
80+
for (R_xlen_t b = 0; b < full_n; b += 32) {
81+
do_flip(b, unif_rand_u32());
82+
}
83+
} while (paired_update());
84+
} else {
85+
const std::uint32_t tail_mask = (std::uint32_t { 1 } << (n - full_n)) - 1u;
86+
do {
87+
for (R_xlen_t b = 0; b < full_n; b += 32) {
88+
do_flip(b, unif_rand_u32());
89+
}
90+
do_flip(full_n, unif_rand_u32() & tail_mask);
91+
} while (paired_update());
92+
}
5493
}
5594
}
5695

inst/include/pmt/impl_twosample_pmt.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
#pragma once
22

3+
#include <cstring>
4+
5+
template <typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
6+
void swap_if(bool c, T& a, T& b) noexcept
7+
{
8+
struct alignas(T) {
9+
unsigned char value[sizeof(T)];
10+
} buffer[2];
11+
std::memcpy(buffer[1].value, &b, sizeof(T));
12+
std::memcpy(buffer[0].value, &a, sizeof(T));
13+
std::memcpy(&a, buffer[c].value, sizeof(T));
14+
std::memcpy(&b, buffer[1 - c].value, sizeof(T));
15+
}
16+
317
template <bool progress, typename T>
418
RObject impl_twosample_pmt(
519
NumericVector x,

inst/include/pmt/permutation.hpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
#pragma once
22

33
#include <algorithm>
4-
#include <cstring>
54
#include <functional>
65
#include <iterator>
76
#include <type_traits>
87
#include <unordered_map>
98

10-
template <typename T, typename = std::enable_if_t<std::is_trivially_copyable<T>::value>>
11-
void swap_if(bool c, T& a, T& b) noexcept
12-
{
13-
struct alignas(T) {
14-
unsigned char value[sizeof(T)];
15-
} buffer[2];
16-
std::memcpy(buffer[1].value, &b, sizeof(T));
17-
std::memcpy(buffer[0].value, &a, sizeof(T));
18-
std::memcpy(&a, buffer[c].value, sizeof(T));
19-
std::memcpy(&b, buffer[1 - c].value, sizeof(T));
20-
}
21-
229
template <typename T>
2310
void random_shuffle(T first, T last)
2411
{

0 commit comments

Comments
 (0)