【问题标题】:Efficiently take N lowest bits of GMP mpz_t有效地取 GMP mpz_t 的 N 个最低位
【发布时间】:2021-11-12 14:58:30
【问题描述】:

GMP 类型mpz_tmpz_class C++ 包装器。拥有mpz_class 号码最有效的方法是使用其N 最低位创建另一个mpz_class 号码?

当然可以做下面的屏蔽操作

size_t N = 273; // how many lo bits to take
mpz_class x = ... ; // fill with something...
mpz_class mask = (mpz_class(1) << N) - 1; // mask having N 1-bits
mpz_class result = x & mask; // final result, N lowest bits taken

但是这种屏蔽需要大量不必要的位和操作,并且会减慢代码速度。也许有一些捷径,比如result = x.take_lo(N);

mpz_class 也可能缺少这样的快捷方式,但至少 C API 可能有这个功能?因为任何mpz_class 都可以轻松转换为C 类型mpz_tmpz_t c_num = x.get_mpz_t();,而无需开销。所以我可以只在 C API 中使用 .take_lo(N) 快捷方式。

【问题讨论】:

  • "并减慢代码速度" 如果您编辑答案以向我们展示探查器显示它确实存在并且是您代码中的瓶颈,那就太好了。
  • C APImpz_tdiv_r_2exp:除以 2 的幂并取余数。这就是你想要的,它uses the obvious efficient implementation。似乎值得一试。
  • @Kaihaku 我的代码对这种掩蔽操作很敏感。但是无论如何,当您进行编码时,了解所有最佳可用功能/操作并使用它们是非常好的。这里肯定不需要 AND 操作,您只需将最低 N 位复制到新数字就可以了,不需要 AND。
  • @NateEldredge 谢谢!正是需要的!

标签: c++ c performance bit-manipulation gmp


【解决方案1】:

虽然mpz_class 没有C++ 运算符重载或函数,但您确实可以使用:C API 提供的mpz_tdiv_r_2exp。例如,

mpz_tdiv_r_2exp(result.get_mpz_t(), x.get_mpz_t(), N);

注意:cdivfdiv 变体也可用。

使用mp_bitcnt_t 作为(N) 的类型,或使用static_cast&lt;mp_bitcnt_t&gt;(N) 作为参数,会更可靠——因为mp_bitcnt_t 似乎被无条件定义为unsigned long,这可能 > 不匹配size_t

【讨论】:

  • 您确定您建议的功能比我的解决方案更快并经过优化吗?因为我打开了您的链接文档并在功能下看到了评论 For the 2exp variants the divisor is 2^b. These functions are implemented as right shifts and bit masks. 所以据我所知,它会进行位掩码,因此与我执行许多不需要的 AND 操作相同。
  • 好吧,我写了代码来做时间测量,你的函数出现2.1x 比我的 AND 屏蔽解决方案快几倍。因此,如果您的函数仍然执行 AND 操作,那么至少它会快两倍。所以接受并支持你的答案。谢谢!
  • 正如@NateEldredge 在评论中发布code link 一样,可以通过此链接看到mpz_tdiv_r_2exp 确实不执行AND-ing,只是复制数字的较低数据。所以这是非常理想的。
猜你喜欢
  • 2015-03-25
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 2014-05-20
  • 1970-01-01
  • 2012-10-16
相关资源
最近更新 更多