将 "__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] 范围的浮点值的主要内容,如果未能解决你的问题,请参考以下文章

将 __m256i 存储为整数

将 __m256i 存储为整数

如何将标志从一个 __m256 中的浮点数复制到另一个 __m256 中? [复制]

将 __m256i 设置为两个 __m128i 值的值

将 __m256i 设置为两个 __m128i 值的值

将 __m256 拆分为两个 __m128 寄存器