【问题标题】:What is an efficent way to compute floor(log(m / n)), where m and n are integers?什么是计算 floor(log(m / n)) 的有效方法,其中 m 和 n 是整数?
【发布时间】:2020-10-20 02:45:56
【问题描述】:

基本上,正如标题所说。我想知道一种计算floor(log2(x / y)) 的方法,其中x 和y 是非零无符号机器整数,在尽可能少的周期内(尽可能避免使用分支、内存带宽、除法等在像这样的一小段代码中很昂贵)。这里需要准确的(整数)答案。我在考虑如何通过有效地计算来优化Adaptive Shivers Sort 的外循环,因为它需要计算floor(log2(r / c)),其中r 是运行长度,c 是算法的元参数;假设x <= y 的解决方案适用于此类离线版本,其中c 被选择为等于输入的长度,但一般解决方案在其他设置中可能有用。

您可以假设使用 PopCount 和 CountLeadingZeros/CountTrailingZeros、常见的 SSE 样式指令,甚至是浮点计算——但它必须是处理器可以在几个周期内完成的事情。

【问题讨论】:

标签: c assembly optimization micro-optimization


【解决方案1】:

像这样的东西怎么样,部分灵感来自 NXTangl 的评论?将clz 应用于x 和y 并将它们都移位,使它们的前导位位于最高位位置(31 或63)。让k 成为这两个班次之间的差值。现在k 或k-1 是您要查找的结果,您可以通过哪个移位值更大来区分情况。

【讨论】:

  • 这几乎正是我的想法,是的,它应该可以工作。它基本上将问题减少到N - M + floor(log2((x << M) / (y << N)));如果 M 和 N 为整数,则归约为floor(log2(x / y)),如果我们选择 M 和 N 与 clz 使得1/2 <= (x<<M)/(y<<N) < 2,那么我们可以找到floor(log2((x << M) / (y << N)) = (x << M) < (y << N) ? 1 : 0。或者换句话说,N - M - ((x << M) < (y << N))
  • @NXTangl:还要注意<不必是一个分支;只需减去(结果必然比总 int 大小少 1 位)并将最高位向下移动到位置 0 给出要从 N-M 中减去的值。
  • 如果您也想摆脱它,那么记录 2 个数字的除法是一个减法。
【解决方案2】:

好吧,这不是一个正确的答案,但这里有一些有趣的特殊情况。

请记住,对于任何 k,log_k(x/y) = log_k(x) - log_k(y)。现在,

  1. 如果 y 是 2 的幂,则 floor(log_2(x/y)) = floor(log_2(x) - log_2(y)) = floor(log_2(x)) - log_2(y)
  2. 如果 x 是 2 的幂,则 floor(log_2(x/y)) = floor(log_2(x) - log_2(y)) = log_2(x) + floor( -log_2(y)) = log_2( x) - ceil(log_2(y)) =
  3. 如果 n 是非负自然数,则 ceil(log_2(n)) = floor(log_2(2n-1))

因此:

  • 如果 x,y 是 2 的幂,我们有:
    log_2(x/y) = (size_in_bits - ctz(y)) - (size_in_bits - ctz(x)) = ctz(x) - ctz(y)
  • 如果只有 y 是 2 的幂,我们还可以通过参数 (1) 使用 ctz(x) - ctz(y)。
  • 如果只有 x 是 2 的幂,我们可以通过参数 (2)、(3) 使用 ctz(x) - ctz(2*y-1)。

因此,如果您碰巧能够做出这些假设之一 - 或者甚至不是确定地做出它们但具有足够高的概率,那么您将获得相当有效的计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    • 2019-06-17
    相关资源
    最近更新 更多