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,
@@ -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
0 commit comments