![](/img/trans.png)
[英]Why does my C program that is supposed to output a matrix to the power of n output my matrix to the power of 2^n?
[英]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-1
和M-2
没有共同设置的位,因此M-1 & M-2
为零.M-1
设置了多个位,则M-2
的最低设置位被清除,但更高的设置位保持设置。 所以M-1
和M-2
有共同的设置位,所以M-1 & M-2
是非零的。 因此,如果测试!(M-1 & M-2)
通过,我们知道M-1
是 2 的幂。 所以M
比二的幂多一。
我们剩下的问题是这是否是二的偶幂。 我们可以看到,当M
是 2 加 1 的偶次幂时,其模 3 的余数为 2,而M
是 2 加 1 的奇次幂时,其模 3 的余数为零:
因此,测试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.