/* ------------------------------------------------------------------------- *//* *//*收入。用Schroeppel方法求逆C-幂*//*gnu多精度库(gnu mp/GMP)的示例应用程序*//*由Antti Karttunen编码,1998年10月29日,置于公共领域*//* *//*参考文献:*//* *//*乘法器(/2)和掩码序列,以及示例序列*//*现在可以从尼尔·J·A·斯隆的*//*整数序列百科全书,如A036213、A036214和A036215*//*并可通过以下URL访问:*//* *//* http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=036213 *//* http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=036214 *//* http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=036215 *//* *//*GNU MP库:*//* http://www.matematik.su.se网站/~tege/gmp/*//* *//**//*包含CGAL_Gmpz的几何计算的CGAL C++库*//*包装器类(除非需要一些语法加糖,否则不需要):*//* http://www.risc.uni-linz.ac.at/projects/basic/cgal/doc_html-0.9/reference/ref-manual3/Chapter_Numbertype.html *//* *//*在HAKMEM的第167项(奇偶校验、计数、反向位)中*//*网址:http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item167 *//*R.施罗佩尔[rcs@cs.arizona.edu]给出了n=3和4的值*//*用于分别反转6位和8位的乘法器、掩码和除数*//*DECsystem-10/20处理器参考手册中也提到了这一点*//*AA-H391A-TK,第2章,用户操作,第2.15节:*//*编程示例:反转数字顺序*//* *//* ------------------------------------------------------------------------- */#包括#包括#包括/*仅当使用CGAL库的语法加糖包装类时才使用这些:#包括#包括类型定义CGAL_Gmpz Z;*//*2*n位的位反转乘法器:22n+2n2 - 12 * --------------2个2 - 12*n位的位反转掩码:2 22n+3n+1 2n-n-1n 2-1(4n+1)2-12 * -------------- + 2 * --------------2n+1 2n+12 - 1 2 - 1第一项是最左边的(n+1)位(原始)第二个术语用于“覆盖”的其余(n-1)位。n个将2作为一个公因数,我们得到:2 22n+3n+1 2n+2n 3n+1n 2+2-2-12 * --------------------------------2n+12 - 12*n位的位反转除数:2n+22 - 1*//*2*n位的位反转乘法器:22n+2n2 - 12 * --------------2个2 - 1*/#定义twos_power(n)(((unsigned long int)1)<<(n))void bit_reversing_multiplier(mpz_t result,unsigned long int n)/*对于2*n位*/{mpz_t分子、分母;mpz_init_set_ui(分子,0);mpz_init_set_ui(分母,0);mpz_setbit(分子,2*((n+1)*(n)));mpz_sub_ui(分子,分子,1);mpz设置位(分母,2*(n));mpz_sub_ui(分母,分母,1);mpz_tdiv_q(结果、分子、分母);mpz_mul_2exp(结果,结果,1);/*乘以2**1,即2*/mpz_clear(分子);mpz_clear(分母);}/* 2 22n+3n+1 2n+2n3n+1n 2+2-2-12 * --------------------------------2n+12-1*/void bit_reversing_mask(mpz_t result,unsigned long int n)/*对于2*n位*/{mpz_t分子、分母、辅助;mpz_init_set_ui(分子,0);mpz_init_set_ui(分母,0);mpz_setbit(分子,(2*(n*n))+(3*n)+1));mpz_setbit(分子,(2*(n*n))+(2*n);/*此快捷方式在32位计算机中仅在n=10(3*10+1=31)以下有效:mpz_sub_ui(分子,分子,(twos_power((3*n)+1)+1));因此,我们使用以下三个调用:*/mpz_init_set_ui(辅助,0);mpz设置位(辅助,(3*n)+1);mpz_sub(分子、分子、辅助);mpz_sub_ui(分子,分子,1);mpz_setbit(分母,((2*(n))+1));mpz_sub_ui(分母,分母,1);mpz_tdiv_q(结果、分子、分母);mpz_mul_2exp(结果,结果,n);/*乘以2**n*/mpz_clear(分子);mpz_clear(分母);mpz_clear(辅助);}/*2*n位的位反转除数:2n+22 - 1*/void bit_reversing_divisor(mpz_t result,unsigned long int n)/*对于2*n位*/{mpz_set_ui(结果,0);mpz设置位(结果,(2*n)+2));mpz_sub_ui(结果,结果,1);}int main(int argc,char**argv){mpz_t第n次幂、乘数、掩码、除数、功、功2;无符号long int n,count,i,j,binlength;int基数=10;如果(argc<3){fprintf(标准错误,“用法:%s n count[base]\n”,*argv);出口(1);}n=原子醇(*(argv+1));如果(mpz_init_set_str(n次幂,*(argv+1),10)<0){fprintf(标准错误,“%s:请给出一个有效的整数(十进制),而不是:\”%s\“\n”“,*argv,*(argv+1));出口(1);}计数=atol(*(argv+2));如果(argc>3){基数=atoi(*(argv+3));}mpz_init(乘数);/*。ptr()->mpZ*/mpz_init(掩码);mpz_init(除数);mpz_init(工作);mpz_init(工作2);/*输出为:i n次幂(长度)*乘数和掩码%除数/[1|2]=n次幂反向*/对于(i=1;i<=计数;i++,mpz_mul_ui(nth_power,nth_power,n))/*nth_power*=n*/{打印(“%3lu.”,i);mpz_out_str(标准输出,基本,第n次功率);binlength=mpz_sizeinbase(n次幂,2);j=(箱长+1)/2;printf(“(%lu.%lu.)*”,binlength,j);位反转乘法器(乘法器,j);mpz_out_str(标准输出,基数,乘数);位反转掩码(掩码,j);printf(“&”);mpz_out_str(标准输出,基本,掩码);位反转除数(除数,j);打印(“%%”);mpz_out_str(标准输出,基数,除数);/*功=(((n次幂*乘数)&mask)%除数)*/mpz_mul(功,n次幂,乘数);/*功=n次幂*乘数*/mpz_and(工作,工作,掩码);/*work=掩码*/mpz_mod(功,功,除数);/*功%=除数*/if(binlength&1)/*长度为奇数,因此我们必须右移一次*/{printf(“/2”);mpz_tdiv_q_2exp(工作,工作,1);/*功>>=1*/}else{printf(“/1”);}printf(“=”);mpz_out_str(标准输出,基本,工作);如果(n){mpz_tdiv_qr_ui(工作,工作2,工作,n);打印f(“/%lu=”,n);mpz_out_str(标准输出、基准、工作);打印f(“%%%lu=”,n);mpz_out_str(标准输出,基本,工作2);}printf(“\n”);}}