模板编程 实例2 素数判定
2014-02-14 16:16
309 查看
原理
最基本的素数判断算法,伪代码如下:function IsPrime(n)if n == 1 then return falseif n == 2 then return truefor each m from 2 if m * m > n then return true if n mod m = 0 then return false m := m + 1复杂度为O(sqrt(n))的算法,主要的逻辑为循环。模板元编程是以递归的逻辑形式来实现循环算法;因此必须先明确两件事:有几个变量参与,以及循环的终止条件是什么。这个算法显然有2个变量参与运算:一个是n,另一个是m。我们令m从2开始递增,直到达到循环终止条件。基本框架
template<uint n, uint m>struct TEST{
const static uint r = TEST<n, nextM>::r; //nextM为下一个M,暂不实现。在这里用递归结构代替了循环
};
template<uint n>struct ISPRIME{
const static uint r = TEST<n, 2>::r; //从2开始,依次判断每一个可能的m取值,判断代码暂未实现。
};
template<>struct ISPRIME<1>{ //对于算法不能计算的特殊值1,判断为0
const static uint r = 0;
};
template<>struct ISPRIME<2>{ //对于算法不能计算的特殊值2,判断为1
const static uint r = 1;
};循环的终止条件是:m的平方大于n或可以整除n。当满足终止条件时,向模板参数传递一个特殊值,并在偏特化中处理这个值,那么递归逻辑就终止了。而判断是否满足终止条件,则需进行逻辑和算术运算。
改写后的框架
template<uint n, uint m>struct TEST{
// if (n % m == 0) n = 0;
// if (m * m > n) m = 0; else ++m;
const static uint r = TEST<n, m>::r; //上面两行代码不能写在此处,仅说明逻辑。实际的语法下文再做介绍
};
template<uint m>struct TEST<0, m>{ //n为0的情况
const static uint r = 0; //即在非特化的模板代码中,n可以被m整除,因此n被赋值为0,故为合数
};
template<uint n>struct TEST<n, 0>{ //m为0的情况
const static uint r = 1; //即在非特化的模板代码中,m * m > n,因此n不能被任何比它小的数整除,故为素数
};
template<uint n>struct ISPRIME{
const static uint r = TEST<n, 2>::r; //从2开始,依次判断每一个可能的m取值,判断代码暂未实现。
};
template<>struct ISPRIME<1>{ //对于算法不能计算的特殊值1,判断为0
const static uint r = 0;
};
template<>struct ISPRIME<2>{ //对于算法不能计算的特殊值2,判断为1
const static uint r = 1;
};
实现
只要用模板的参数推导实现取模的算术运算和上面框架中的两个逻辑判断即可#include <iostream>
typedef unsigned int uint;
template<uint n, uint m>struct NEXTN{
const static uint r = ((n % m != 0) * n);
};
template<uint n, uint m>struct NEXTM{
const static uint r = (m * m <= n ? (m + 1) : 0);
};
template<uint n, uint m>struct TEST{
const static uint r = TEST<NEXTN<n, m>::r, NEXTM<n, m>::r>::r;
};
template<uint m>struct TEST<0, m>{
const static uint r = 0;
};
template<uint n>struct TEST<n, 0>{
const static uint r = 1;
};
template<uint n>struct ISPRIME{
const static uint r = TEST<n, 2>::r;
};
template<>struct ISPRIME<1>{
const static uint r = 0;
};
template<>struct ISPRIME<2>{
const static uint r = 1;
};
int main()
{
int primes[] = {
ISPRIME<1>::r, ISPRIME<2>::r, ISPRIME<3>::r, ISPRIME<4>::r,
ISPRIME<5>::r, ISPRIME<6>::r, ISPRIME<7>::r, ISPRIME<8>::r,
ISPRIME<9>::r, ISPRIME<10>::r, ISPRIME<11>::r, ISPRIME<12>::r,
ISPRIME<13>::r, ISPRIME<14>::r, ISPRIME<15>::r, ISPRIME<16>::r,
};
for (int i = 0; i < sizeof(primes) / sizeof(primes[0]); ++i)
std::cout << i + 1 << (primes[i] ? " YES" : " NO") <<std::endl;
return 0;
}
另一实现参考酷壳的博文:http://coolshell.cn/articles/3738.html#more-3738
相关文章推荐
- 修改php.ini配置PHP扩展模块教程
- 解决Struts2 json-plugin Date或Timestamp等日期格式带T的问题
- Java 枚举7常见种用法
- ASP.NET 使用mode=”InProc”方式保存Session老是丢失,无奈改成StateServer 模式。
- Asp.net中params关键字的用法
- GitHub详细教程
- PHP限制字符串显示长度
- VC++实现打印功能相关
- java自带线程池和队列详细讲解
- MapReduce编程
- 关于java中List、Set、Map的一些总结
- (int&)a和(int)a的区别 - c语言
- 绝对的无root,首发用于logo上文字的字体终于出现在手机上了
- 提高你的代码稳定性与可读性-lint工具
- java jmenu的替代方案
- android学习——NDK入门 windows下安装cygwin 与 Eclipse使用CDT 自动编译
- ASP.NET MVC+Nhibernate+bootcss实现权限管理系列[完全免费和开源] 序
- PHP 配合Cross-Origin Resource Sharing实现跨域 使用心得
- Effecive C++ 解析2
- 玩一个Tennis TDD的编程操练游戏