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+
318template <bool progress, typename T>
419RObject 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
0 commit comments