查找用于提升多精度 uint512_t 的 First Set 指令 (ffs)

Posted

技术标签:

【中文标题】查找用于提升多精度 uint512_t 的 First Set 指令 (ffs)【英文标题】:Find First Set instruction (ffs) for boost multiprecision uint512_t 【发布时间】:2019-10-02 18:36:40 【问题描述】:

我正在开发一种使用__builtin_ffsll()uint64_t 类型的算法。

我想使用 boost 多精度库切换到 512 位字段(我在支持 avx512 的机器上运行)。

有没有和上面提到的内置函数类似的功能?或者,我怎样才能有效地为 512 位整数实现这样的功能?

【问题讨论】:

【参考方案1】:

来自the documentation:

unsigned lsb(const number-or-expression-template-type& x);

返回设置为 1 的最低有效位的(从零开始的)索引。

如果参数是<= 0,则抛出std::range_error

ffs() 是从 1 开始的,所以将 1 加到 lsb() 的返回值将使其等价。编辑:正如所指出的,考虑到传递 0 的情况。

可能是这样的

unsigned ffs512(const boost::multiprecision::uint512_t &n) 
  if (n.is_zero()) 
    return 0;
   else 
    return boost::multiprecision::lsb(n) + 1;
  

【讨论】:

还要注意输入 == 0 的不同行为。似乎lsb 旨在包装诸如 x86 的 bsf 指令之类的东西,该指令仅在输入为零时设置一个标志;它不会将有用的值写入输出寄存器。但是ffs 确实处理了 input==0 的情况,返回了0 512 位整数上的 lsb 是否实际编译为使用 vptestmd / vpcompressd 或类似方法的 AVX512 序列来查找第一个非零 dword,然后使用 vmovd 提取它到tzcnt 的整数寄存器? (或使用 2x 256 位向量来避免将 CPU 置于 512 位 SIMD 模式。)OP 希望这在 x86 上高效,可能是使用 gcc 和/或使用-O3 -march=skylake-avx512 @PeterCordes 我想 GMP 后端调用 mpz_scan1()。对其他人一无所知。 @PeterCordes 我认为 GMP 只有通用版本的 mp[nz]_scan1 因为与乘法或更差的除法和 gcd 相比,它从来都不是限制因素。如果您认为它很有用,并且您可以为大型扫描提供更快的版本,并且不会显着减慢扫描几乎立即找到 1 位的常见情况,您可以尝试将其贡献给 GMP。但实际上 OP 有一个更简单的情况来处理,总是从头开始扫描。而当前的lsb 对他们来说可能已经足够快了。 看起来这个uint512_t 只为cpp_int 后端定义了类型,所以对于这个问题,gmp 后端如何实现它并不重要。

以上是关于查找用于提升多精度 uint512_t 的 First Set 指令 (ffs)的主要内容,如果未能解决你的问题,请参考以下文章

比较 uint64_t 和 float 的数值等价性

64 位数学运算,不会丢失任何数据或精度

如何以二进制形式显示 C++ Boost Library 多精度大整数?

uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结

为啥clang++更喜欢adcx而不是adc

传递变量作为函数参数时由于隐式铸造导致的精度损失