将“__m256 with random-bits”转换为 [0, 1] 范围的浮点值
Posted
技术标签:
【中文标题】将“__m256 with random-bits”转换为 [0, 1] 范围的浮点值【英文标题】:Convert "__m256 with random-bits" into float values of [0, 1] range 【发布时间】:2020-12-31 08:20:34 【问题描述】:我有一个包含随机位的 __m256
值。
我想“解释”它,以获得另一个拥有 float
的 __m256
统一 [0.0f, 1.0f]
范围内的值。
计划使用:
__m256 randomBits = /* generated random bits, uniformly distribution */;
__m256 invFloatRange = _mm256_set1_ps( numeric_limits<float>::min() ); //min is a smallest increment of float precision
__m256 float01 = _mm256_mul(randomBits, invFloatRange);
//float01 is now ready to be used
问题 1:
但是,在极少数情况下,randomBits
的所有位都为 1,因此是 NAN,这会导致问题吗?
我能做些什么来保护自己免受这种伤害?
我希望float01
始终是可用的号码
问题 2:
使用上述方法获得 [0 到 1] 范围后会保持一致吗?我知道浮点数在不同幅度下具有不同的精度
【问题讨论】:
将randomBits
视为unit32,然后除以uint32 max(确保先转换为float)?即使没有 nan 和 infinity 的问题,浮点数中的随机位也不会给出均匀分布
@AlanBirtles 能否请您说明如何使用_mm256
指令来完成? uint32 的范围(与浮点数不同)与我所看到的不同。也许我们应该使用 int32 并屏蔽掉减号?这也应该消除发生 NaN 的任何可能性
实际上,按pow(2,-31)
缩放(这会在[-1, +1)
中获取数字)然后屏蔽符号位可能会更好一些。您只会丢失 1 位生成的数字,而不是 8 位。
uint32 到浮点数的转换见here。
@Kari 你看到了吗? ***.com/q/54869672/126995
【参考方案1】:
将 int32_t 重新解释为浮点数,可以
auto const one = _mm256_set1_epi32(0x7f800000);
a = _mm256_and_si256(a, _mm256_set1_epi32(0x007fffff));
a = _mm256_or_si256(a, one);
return _mm256_sub_ps(_mm256_castsi256_ps(a), _mm256_castsi256_ps(one));
and/or 序列将重用输入序列的 23 个 LSB,以在 1.0f
【讨论】:
这将永远不会生成小于 1 epsilon 的浮点数。如果您以某种方式使用了 31 位或 32 位随机性(例如,使用 uint 或 int->float 转换,然后乘以 2^-31),您将四舍五入到最接近的倍数,例如32 对于大浮点数,但每个小的随机整数仍然可以映射到不同的小浮点数,因此您有超过 2^24 个可能的结果,但仍然我认为均匀分布。 嗯,也不确定这个想法是否完美。 mumble.net/~campbell/2014/04/28/uniform-random-float【参考方案2】:正如@Soonts 所指出的,可以在 [0, 1] 范围内统一创建浮点数:
https://***.com/a/54873925/9007125
我最终使用了以下答案:
https://***.com/a/54893167/9007125
//converts __m256i values into __m256 values, that contains floats in [0,1] range.
//https://***.com/a/54893167/9007125
inline void int_rand_int_toFloat01( const __m256i* m256i_vals,
__m256* m256f_vals) //<-- stores here.
const static __m256 c = _mm256_set1_ps(0x1.0p-24f); // or (1.0f / (uint32_t(1) << 24));
__m256i* rnd = ((__m256i*)m256i_vals);
__m256* output = ((__m256*)m256f_vals);
// remember that '_mm256_cvtepi32_ps' will convert 32-bit ints into a 32-bit floats
__m256 converted = _mm256_cvtepi32_ps(_mm256_srli_epi32(*rnd, 8));
*output = _mm256_mul_ps( converted, c);
【讨论】:
你不需要指针转换你的函数参数;它们已经具有您分配的相同类型。如果您确实想将一种矢量类型重新解释为另一种,请使用_mm256_castps_si256
或其他任何东西。 (尽管指针转换对此是安全的,但仅适用于像 __m256i
这样的内在类型,而不是 int
,因为内在类型就像 char*
并且可以合法地为任何东西加上别名,而不管严格的别名规则如何 - 在 GCC 中它们是用__attribute__((may_alias))
定义。以上是关于将“__m256 with random-bits”转换为 [0, 1] 范围的浮点值的主要内容,如果未能解决你的问题,请参考以下文章