最近code golfing post询问了在C中快速实现的可能性(假设n
是无符号整数):
if (n==6 || n==8 || n==10 || n==12 || n==14 || n==16 || n==18 || n==20)
一种可能的简化方法是观察数字a[]={6,8,10,12,14,16,18,20}
形成 arithmetic progression ,从而改变范围,然后使用一些bitwise tricks
if (((n - 6) & 14) + 6 == n)
导致更短(可能确实更有效)的实现,如John Bollinger的answered。
现在我问的是
的类似优雅(并且希望同样有效)的实现 if (n==3 || n==5 || n==11 || n==29 || n==83 || n==245 || n==731 || n==2189)
提示:这次数字a[k]
形成几何级数:a[k]=2+3^k
。
我想在一般情况下,除了对数字a[k]
进行排序,然后进行对数搜索以测试n
是否是排序数组的成员时,我们做得更好。
答案 0 :(得分:25)
if ((n > 2) && (2187 % (n - 2) == 0))
检查(n - 2)
是否为3
并且小于或等于2187
(3为7的幂)
作为概括,要检查是否有任何无符号整数n
是素数k
的幂,您可以检查n
是否除以k
的最大幂{可以存储在无符号整数中。
答案 1 :(得分:8)
这与recognizing a power of three非常相似,您可以调整this solution:
bool test(unsigned x) {
x -= 2;
if (x > 2187)
return 0;
if (x > 243)
x *= 0xd2b3183b;
return x <= 243 && ((x * 0x71c5) & 0x5145) == 0x5145;
}
在给定范围内,可以进一步简化(通过蛮力找到):
bool test2(unsigned x) {
x -= 2;
return x <= 2187 && (((x * 0x4be55) & 0xd2514105) == 5);
}
答案 2 :(得分:5)
提示:这次数字
a[k]
形成几何级数:a[k]=2+3^k
。
n = 2 + 3^k
n - 2 = 3^k
(n - 2) / 3^k = 1
(n - 2) % 3^k = 0
k = 0 ~ n-2 = 3^0 = 1, n = 3
k = 1 ~ n-2 = 3^1 = 3, n = 5
k = 2 ~ n-2 = 3^3 = 9, n = 11
if (n > 2 && isPow(n-2, 3))
定义函数isPow(x,y)
bool isPow(unsigned long x, unsigned int y)
{
while (x % y == 0)
{
x /= y;
}
return x == 1;
}
n = n ~ n-2 = 3^k/3 = 3^(k-1)/3 = .. = 3^1/3 = 1%3 != 0
n = 11 ~ n-2 = 9/3 = 3/3 = 1%3 != 0
n = 5 ~ n-2 = 3/3 = 1%3 != 0
n = 3 ~ n-2 = 1%3 != 0
同样我们可以扣除k
..
int k = findK(n-2, 3);
int findK(unsigned long x, unsigned int y)
{
unsigned int k = 0;
while (x % y == 0)
{
x /= y;
k++;
}
if (x == 1) return k;
else return (-1);
}
n - 2 = 3 * 3^(k-1) for k > 0
(n - 2) / 3 = 3^(k-1)
(n - 2) / 3 / 3 = 3^(k-2)
(n - 2) / 3 / 3 / 3 = 3^(k-3)
(n - 2) / 3 / 3 / 3 / 3 = 3^(k-4)
..
(n - 2) / 3 / 3 / ..i times = 3^(k-i)
..
(n - 2) / 3 / 3 / ..k times = 3^0 = 1
答案 3 :(得分:3)
在相关帖子中发现了类似的问题:
您可以使用std::find
bool found = (std::find(my_var.begin(), my_var.end(), my_variable) != my_var.end());
// my_var is a list of elements.
(请确保包含&lt; algorithm&gt;)。
对于这类东西,在99%的情况下,有一个图书馆为你完成这项工作。
答案 4 :(得分:3)
执行此类操作的一种非常有效的方法是使用集合,尤其是unordered_set
。作为哈希表,搜索是平均常数,最差线性。它也比一系列条件更优雅,并且可以很好地扩展。
只需插入要比较的值,然后count
设置中的值。如果找到,它是您测试的值之一。
std::unordered_set< int > values;
values.insert( 3 );
values.insert( 5 );
values.insert( 11 );
values.insert( 29 );
values.insert( 83 );
values.insert( 245 );
values.insert( 731 );
values.insert( 2189 );
...
if( values.count( input ) )
std::cout << "Value is in set.\n";
else
std::cout << "Value is NOT in set.\n";
答案 5 :(得分:0)
以下是我提出的建议:
bool b;
if (n >= 3 && n <= 2189)
{
double d = std::log(n - 2)/std::log(3); // log₃(n - 2)
b = std::trunc(d) == d; // Checks to see if this is an integer
// If ‘b’ then ‘n == a[log₃(n - 2)]’
}
else b = false;
if (b)
{
// your code
}
由于数字n
是一个小整数,浮点不准确应该不是问题。
当然,它不会像整数运算一样快,它不适合表达式,它可能比某种数组搜索更快,特别是如果你在哪里增加最大值n
值。
编辑我测试了我的代码(未启用优化),平均而言(对于所有小于或等于2189的n),我的版本耗时185.849 ns,而||
版本占用了116.546 ns ,(多次运行我的程序产生类似的结果)所以这不会更快。
同样出于某些奇怪的原因,它会在b
时将false
设置为n == 245
,(它应该是真的)。