Skip to content

Commit ce2facf

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

3 files changed

Lines changed: 60 additions & 21 deletions

File tree

inst/include/pmt/impl_paired_pmt.hpp

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
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,
621
NumericVector y,
722
T&& statistic_func,
8-
const double n_permu
9-
)
23+
const double n_permu)
1024
{
1125
Stat<progress> statistic_container;
1226

@@ -17,7 +31,7 @@ RObject impl_paired_pmt(
1731

1832
R_xlen_t n = x.size();
1933

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

2236
#ifdef SETJMP
2337
SETJMP(statistic_func)
@@ -37,7 +51,7 @@ RObject impl_paired_pmt(
3751
statistic_container.switch_ptr();
3852
if (n_permu == 0) {
3953
R_xlen_t swapped = 0;
40-
for (R_xlen_t i = 0; i < n; i = swapped & (1 << i) ? 0 : i + 1) {
54+
for (R_xlen_t i = 0; i < n; i = swapped & (R_xlen_t{ 1 } << i) ? 0 : i + 1) {
4155
if (i == 0) {
4256
paired_update();
4357
}
@@ -46,11 +60,35 @@ RObject impl_paired_pmt(
4660
swapped ^= (1 << i);
4761
}
4862
} else {
49-
do {
50-
for (R_xlen_t i = 0; i < n; i++) {
51-
swap_if(unif_rand() > 0.5, x[i], y[i]);
63+
const R_xlen_t full_n = (n / 32) * 32;
64+
65+
auto unif_rand_u32 = []() -> std::uint32_t {
66+
return unif_rand() * 4294967296.0;
67+
};
68+
69+
auto do_flip = [x, y](R_xlen_t start, std::uint32_t flip) mutable {
70+
while (flip) {
71+
R_xlen_t i = start + countr_zero_u32(flip);
72+
std::swap(x[i], y[i]);
73+
flip &= flip - 1;
5274
}
53-
} while (paired_update());
75+
};
76+
77+
if (n == full_n) {
78+
do {
79+
for (R_xlen_t b = 0; b < full_n; b += 32) {
80+
do_flip(b, unif_rand_u32());
81+
}
82+
} while (paired_update());
83+
} else {
84+
const std::uint32_t tail_mask = (std::uint32_t { 1 } << (n - full_n)) - 1u;
85+
do {
86+
for (R_xlen_t b = 0; b < full_n; b += 32) {
87+
do_flip(b, unif_rand_u32());
88+
}
89+
do_flip(full_n, unif_rand_u32() & tail_mask);
90+
} while (paired_update());
91+
}
5492
}
5593
}
5694

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)