C++ 将随机整数转换为范围[min,max],无需分支
我得到了一个生成随机字节数组的方法。它是C++的均匀分布和STD文库的MeSouthWistor的6倍。 数组的计数可以被4整除,因此可以将其解释为整数数组。将每个条目转换为整数,将生成范围为C++ 将随机整数转换为范围[min,max],无需分支,c++,bit-manipulation,simd,avx2,C++,Bit Manipulation,Simd,Avx2,我得到了一个生成随机字节数组的方法。它是C++的均匀分布和STD文库的MeSouthWistor的6倍。 数组的计数可以被4整除,因此可以将其解释为整数数组。将每个条目转换为整数,将生成范围为[INT\u MIN,INT\u MAX]的值。但是如何将这些整数值转换为介于我自己的[min,max]之间的值呢 我想避免任何if-else,以避免分支 也许我应该应用一些位逻辑,在每个数字中丢弃不相关的位?(因为所有剩余的未屏蔽位都将是0或1)。如果我可以提取最大值中的最高有效位,我可以在整数中屏蔽任
[INT\u MIN,INT\u MAX]
的值。但是如何将这些整数值转换为介于我自己的[min,max]
之间的值呢
我想避免任何if-else,以避免分支
也许我应该应用一些位逻辑,在每个数字中丢弃不相关的位?(因为所有剩余的未屏蔽位都将是0或1)。如果我可以提取最大值中的最高有效位,我可以在整数中屏蔽任何比该位更重要的位 例如,如果我希望我的
max
为17,则它是二进制形式的0000001
。也许我的面具会看起来像0001111
?然后我可以将其应用于数组中的所有数字
但是,这个掩码是错误的……它实际上允许的值最多为(1+2+4+8+16)
:(
我能做什么?还有,如何处理min
编辑
我在我的应用程序的每一帧都生成数百万个数字,用于神经网络。我设法使用AXV2对浮点变量(使用),但也需要使整数工作。核心思想是使用模而不是按位掩码,这在非2次幂的情况下是无用的。无分支也是一个有点奇怪的要求。你想要的是“足够快”,而不是“无分支和按位掩码” 假设我们有一个函数
int rand();
如果max
的形式为2^n-1
,则
rand()%(最大值+1)
将统一生成一个范围为[0,max]
的随机整数。这是因为整数的总数是2的幂
现在,如果min
和max
是max-min
的形式2^n-1
,那么
(rand()%(最大最小值+1))+min
将统一生成范围[min,max]
内的随机整数
但是当max-min
不是2^n-1
的形式时会发生什么?那么我们就倒霉了。(rand()%(max-min+1))+min
方法仍然会在[min,max]中生成一个随机整数
范围,但不再是一致的。这是为什么?因为当n
是固定的,而不是2的幂,那么给出具体r=x%n
结果的整数总数根据r
而变化
然而,这种方法并不坏。越大的max-min
值越接近均匀分布,在实践中通常就足够好了。而且它非常快,没有分支
另一个例子是
upper=get_upper_power_of_2(max-min)
做
{
tmp=rand()%上限;
}而(tmp>max-min);
结果=tmp+min;
该方法具有很好的一致性,但它没有停止特性,即理论上该算法可能永远不会停止。它也有分支。但在实践中,它停止得非常快(概率很大),因此它是非常常见的算法。例如,它在标准Java库中
当然,当max-min
溢出时(即min
是一个很大的负数时),这两种方法都有一个问题,如果我们切换到无符号整数,然后返回整数,这个问题就可以解决
据我所知,[0,max]中没有生成随机整数的算法
当max
不是2^n-1
来自01
统一生成器的形式时,结果是统一的,并且具有停止特性。我认为不可能存在这样的算法,但我在计算机科学中找不到合适的结果
但是如何将这些整数值转换为介于我自己的[min,max]
之间的值呢
由于范围可能不是2的幂,所以位屏蔽已被禁用,但您已经发现了这一点
模也不存在,它在AVX2中不作为本机操作存在(即使存在,也不一定会使其有效)
还有另一种选择:使用\u mm256\u mul\u epu32
(不幸的是,32位数字没有像16位数字那样的“纯”乘法高,因此我们只能执行50%有用的操作)。其想法是获取输入数字x
(全范围)和所需的范围r
,然后计算r*x/2^32
,其中除法是隐式的(通过取乘积的高半部来实现)
x/2^32
如果被解释为一个有理数,那么它应该是[0.0..1.0]中的一个数字(不包括1.0),乘以r
,然后将范围扩大到[0.0..r
)(不包括r
)。这不是它的计算方式,但这是公式的来源
通过将min
添加到缩放结果中,可以轻松设置范围的最小值
在代码中(经过轻微测试):
它仍然是一个独占范围,无法将完整的[INT\u MIN..INT\u MAX]
作为输出范围处理。甚至无法指定它,它最多只能[INT\u MIN..INT\u MAX)
(或者例如,具有零偏移量的等效范围:[0..-1)
)
它也不是真正统一的,因为同样的原因,简单的基于模的范围缩减不是真正统一的,你不能公平地将
N
大理石除以K
箱子,除非K
恰好将N
平均分割。如果一个值中有2^N个随机位,你可以通过do将其放入一个整数范围ing:
r=((值*(最大-最小值)
__m256i squish(__m256i x, int min, int max) {
__m256i sizeOfRange = _mm256_set1_epi32((unsigned)max - min);
__m256i scaled_even = _mm256_shuffle_epi32(_mm256_mul_epu32(x, sizeOfRange), 0xB1);
__m256i scaled_odd = _mm256_mul_epu32(_mm256_shuffle_epi32(x, 0xB1), sizeOfRange);
__m256i scaled = _mm256_blend_epi32(scaled_even, scaled_odd, 0xAA);
return _mm256_add_epi32(scaled, _mm256_set1_epi32(min));
}
r = _mm256_add_epi16(
_mm256_mulhi_epi16(value, _mm256_set1_epi16(max-min)),
_mm256_set1_epi16(min));