如何快速评估零集
How to evaluate zero sets fast?
这篇最近的代码高尔夫帖子询问了在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}
形成算术级数,因此移动范围,然后使用一些位技巧
if (((n - 6) & 14) + 6 == n)
正如John Bollinger所回答的那样,这会导致更短(而且可能更高效)的实现。
现在我在问类似优雅(希望同样高效)的实现是什么
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
是否是排序数组的成员,这是最好的选择。
if ((n > 2) && (2187 % (n - 2) == 0))
检查(n - 2)
是否是3
的幂并且小于或等于2187
(3到7的幂)
一般来说,要检查任何无符号整数n
是否是素数k
的幂,可以检查n
是否除以可以存储在无符号整数中的k
的最大幂。
这与识别三次方非常相似,例如,您可以调整此解决方案:
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);
}
提示:这一次数字
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
在相关帖子中发现了类似的问题:您可以使用std::find
bool found = (std::find(my_var.begin(), my_var.end(), my_variable) != my_var.end());
// my_var is a list of elements.
(请确保包含<algorithm>)。
对于这种东西,在99%的情况下,有一个图书馆为你做这项工作。
做这类事情的一种非常有效的方法是使用集合,尤其是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";
以下是我的想法:
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
值。
EDIT我测试了我的代码(没有启用优化),平均而言(对于小于或等于2189的所有n),我的版本耗时185.849 ns,而||
版本耗时116.546 ns,(多次运行我的程序会产生类似的结果),所以这并不快。同样由于一些奇怪的原因,它在n == 245
时将b
设置为false
(这应该是真的)。
- 当回溯以零开始时,如何调试崩溃
- 大量序列中核苷酸类型的快速计数
- 为什么比较运算符如此快速
- 在没有太多条件句的情况下,我如何避免被零除
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 矩阵向量乘法(cublasDgemv)返回零
- OpenCV C++.快速计算混淆矩阵
- 有没有一种快速的方法可以将类的所有静态成员归零?
- 如何在快速排序算法中使已排序数组的交换次数为零
- 对齐方式与指针中尾随零的数量有何关系
- C++多集与结构只擦除一个,快速(过载?
- 如何快速评估零集
- 如何对并集进行零初始化
- 通过作弊快速比较大于零的 IEEE 浮点数
- 为什么位集的构造函数有参数字符串::charT 零,字符串::charT one)
- c++快速位集短路位操作
- 2位集之间的快速汉明距离
- 整数的快速集合并集
- 将 '0 1 1 0 1' 格式的字符串快速转换为位集