繁体   English   中英

如何在 C 程序中查找 M 是否实际上是 2power(2n) + 1 的 output

[英]how to find if M is actually an output of 2power(2n) + 1 in C program

我在项目中有一个棘手的要求,要求编写 function 如果给定 integer 可表示为2 2n +1 ,则返回值 1 (否则为 0 )。 其中n是任何非负 integer。

int find_pow_2n_1(int M);

例如:当 M=5 时返回 1,因为当 n=1 -> 2 1*2 +1 时,5 是 output。

我正在尝试评估该等式,但它导致日志 function,在谷歌浏览时也无法找到任何类型的提示。

解决方案

int find_pow_2n_1(int M)
{
    return 1 < M && !(M-1 & M-2) && M % 3;
}

解释

首先,我们丢弃小于 2 的值,因为我们知道第一个匹配数是 2。

然后M-1 & M-2测试 M- M-1中是否设置了多个位:

  • M-1不能设置零位,因为M大于 1,所以M-1不为零。
  • 如果M-1设置了一个位,则该位在M-2中为零,并且所有低位都被设置,因此M-1M-2没有共同设置的位,因此M-1 & M-2为零.
  • 如果M-1设置了多个位,则M-2的最低设置位被清除,但更高的设置位保持设置。 所以M-1M-2有共同的设置位,所以M-1 & M-2是非零的。

因此,如果测试!(M-1 & M-2)通过,我们知道M-1是 2 的幂。 所以M比二的幂多一。

我们剩下的问题是这是否是二的偶幂。 我们可以看到,当M是 2 加 1 的偶次幂时,其模 3 的余数为 2,而M是 2 加 1 的奇次幂时,其模 3 的余数为零:

  • 2 0 +1 = 2 模 3 的余数是 2。
  • 2 1 +1 = 3 模 3 的余数为 0。
  • 2 2 +1 = 5 模 3 的余数是 2。
  • 2 3 +1 = 9 模 3 的余数为 0。
  • 2 4 +1 = 17 模 3 的余数是 2。
  • 2 5 +1 = 33 模 3 的余数为 0。

因此,测试M模 3 的余数是否非零的M % 3测试M-1是否是 2 的偶数幂。

该属性只有几个数字:创建一个表查找数组:-)

$ bc
for(n=0;n<33;n++)2^(2*n)+1
2
5
17
65
257
1025
4097
16385
65537
262145
1048577
4194305
16777217
67108865
268435457
1073741825
4294967297
17179869185
68719476737
274877906945
1099511627777
4398046511105
17592186044417
70368744177665
281474976710657
1125899906842625
4503599627370497
18014398509481985
72057594037927937
288230376151711745
1152921504606846977
4611686018427387905
18446744073709551617

上面的最后一个数字是2^64 + 1 ,可能不适合您的实现中的int

所有提出的解决方案都过于复杂或性能不佳。 尝试更简单的一个:

static int is_power_of_2(unsigned long n)
{
  return (n != 0 && ((n & (n - 1)) == 0));
}

static int is_power_of_2n(unsigned long n)
{
  return is_power_of_2(n) && (__builtin_ffsl(n) & 1);
}

int main(void)
{
  int x;

  for (x = -3; x < 20; x++)
    printf("Is %d = 2^2n + 1? %s\n", x, is_power_of_2n(x - 1) ? "Yes" : "no");
  return 0;
}

实现__builtin_ffsl() ,如果您使用的是古老的编译器,我将其作为作业(无需表格或除法即可完成)。

示例: https://wandbox.org/permlink/gMrzZqhuP4onF8ku

在评论@Lundin 的评论时,我意识到您可能会从斯坦福大学读到一组非常不错的小技巧

更新。 正如@grenix注意到的最初的问题是关于直接检查的,可以通过引入一个额外的包装器来使用上面的代码来完成,所以基本上没有任何改变:

...

static int is_power_of_2n_plus_1(unsigned long n)
{
  return is_power_of_2n(n - 1);
}

int main(void)
{
  int x;

  for (x = -3; x < 20; x++)
    printf("Is %d = 2^2n + 1? %s\n", x, is_power_of_2n_plus_1(x) ? "Yes" : "no");
  return 0;
}

在这里,我给你留下一个伪代码(或我没有测试过的代码),我认为它可以帮助你思考解决问题的方法:)

#include <math.h>
#include <stdlib.h>

#define EPSILON 0.000001


int find_pow_2n_1(int M) {
    M--;   // M = pow 2n now
    double val = log2(M);    // gives us 2n
    val /= 2;    // now we have n
    if((val * 10) / 10 - val) <= EPSILON) return 1;   // check whether n is an integer or not
    else return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM