【问题标题】:Calculating Highest Power of 2 That Evenly Divides a Number in C计算 2 的最大幂,它可以在 C 中整除一个数
【发布时间】:2023-03-30 11:03:01
【问题描述】:

我需要编写一些逻辑来确定,给定一个偶数。将其平分的二的最高幂。 Input % 2^n == 0 的 2^n 的最大值是多少?

IE:
输入 -> 输出

4  (0100)  -> 4

8  (1000)  -> 8

12 (1100)  -> 4

14 (1110)  -> 2

24 (11000) -> 8

etc....

看起来有一些按位逻辑可以解决:当查看二进制输入时,最右边的一位似乎是解决方案。如何在 C 中确定这个值?是否有另一种可能更容易的解决方案?

谢谢- 乔纳森

【问题讨论】:

    标签: c bit-manipulation


    【解决方案1】:

    2^n 形式的数字以二进制形式写为 1,后跟一系列 0 或多个 0。 例如,1、10、100、1000……等都是 2 的幂。

    要获得除以给定数字的 2 的最高幂,您可以执行以下两个步骤:

    1. 以二进制形式写入数字。例如,如果数字是 168,则写 10101000。

    2. 删除右侧第一个位之前包含 1 的所有位。在 168 的情况下,删除 10101000 的第一部分后剩下的是 1000(= 十进制的 8)。

    剩下的是你的结果 - 即除以数字的 2 的最高幂。

    以编程方式,让 x 是您的输入数字。那么您想要的输出将是:x - (x ^ (x-1))

    解释:

    x ^ (x-1) [意思是 x XOR x-1] 从 LSB(最低有效位)一侧去掉第一个 1

    x - (x ^ (x-1)) 去掉剩余部分,只保留 LSB 端的前 1。

    【讨论】:

      【解决方案2】:

      如果你愿意假设 2 的补码算法:

      x & -x

      如果您经常做这种事情(或者即使您只是觉得它很有趣),请给自己找一本《黑客的喜悦》一书。

      edit: avakar 正确地指出,如果类型是无符号的,这不依赖于 2 的补码。标准的相关部分是§6.2.5,第 9 段:

      涉及无符号的计算 操作数永远不会溢出,因为 无法表示的结果 得到的无符号整数类型是 减少模数是一 大于最大值 可以用结果来表示 输入。

      “大于最大值”为特别不正当的实现(特别是不使用二进制的实现)留出了一些回旋余地,但您不太可能遇到这种情况。

      【讨论】:

      • +1。作为记录,您不必假设 2 的补码。只要x 是无符号算术类型,这将适用于任何架构。
      • 假设我们有一个带有 1 补码算法的 32 位类型:如果 x 是 1,那么 -x0xfffffffe,而 x & -x 是 0,这不是提问者想要的答案.正如 J.F. Sebastian 所说,您可以通过使用 x & (~x+1) 来解决这个问题,这只是将 2 的补语否定扩展为两个操作。
      • (~x + 1) 是补码否定,即。
      • 没有。对于未签名的x,对于某些k-x 将是2^k-x。在您的示例中,k 将是 32,-x 将是 0xffffffff。同样,unsigned 是这里的关键,签名的x 的所有赌注都已关闭。
      【解决方案3】:

      我们可以用(~x + 1)替换(-x)

      x & (~x+1) 
      

      Low Level Bit Hacks You Absolutely Must Know提供详细解释。

      【讨论】:

      • 注意 (~x+1) 是 -x 在 2 的补码中的定义。这使得这个答案比 x & (-x) 稍微好一点,因为 (~x+1) 只取决于使用直接二进制算术的机器,这在当今几乎是给定的(但并非总是如此!)。
      【解决方案4】:

      不使用浮点运算:

      ((x ^ (x - 1)) >> 1) + 1
      

      简化和边缘情况留给读者练习。

      【讨论】:

      • X = 24 (24 ^ 23) = 24623 24623 >> 1 = 12311 12311 + 1 = 12312 我计算错了吗?
      • 乔纳森:^ 是 XOR,所以 (24 ^ 23) 是 15。
      • 顺便说一句,如果 x 是无符号的,那么我相信唯一需要特殊处理的边缘情况是零。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多