`
xpp02
  • 浏览: 1010813 次
社区版块
存档分类
最新评论

[算法]不使用*、/、+、-、%操作符求一个数的1/3

 
阅读更多
摘要:算法一直是程序员进阶的一道龙门,通常算法都是为了更高效地解决问题而创造的,但也有的只是出于学术性,并不在意其实际意义。这是近日在国外技术问答网站stackoverflow的一个热门问题,不知道你能给出几种解决方法?

导读:算法一直是程序员进阶的一道龙门,通常算法都是为了更高效地解决问题而创造的,但也有的只是出于学术性,并不在意其实际意义。这是近日在国外技术问答网站stackoverflow的一个热门问题,不知道你能给出几种解决方法?

问:在不使用*、/、+、-、%操作符的情况下,如何求一个数的1/3?(用C语言实现)

第一种方法:使用位操作符并实现“+”操作

  1. //替换加法运算符
  2. intadd(intx,inty){
  3. inta,b;
  4. do{
  5. a=x&y;
  6. b=x^y;
  7. x=a<<1;
  8. y=b;
  9. }while(a);
  10. returnb;
  11. }
  12. intdivideby3(intnum){
  13. intsum=0;
  14. while(num>3){
  15. sum=add(num>>2,sum);
  16. num=add(num>>2,num&3);
  17. }
  18. if(num==3)
  19. sum=add(sum,1);
  20. returnsum;
  21. }

原理:n = 4 * a + b; n / 3 = a + (a + b) / 3; 然后 sum += a, n = a + b 并迭代; 当 a == 0 (n < 4)时,sum += floor(n / 3); i.e. 1, if n == 3, else 0

第二种方法:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. intmain()
  4. {
  5. FILE*fp=fopen("temp.dat","w+b");
  6. intnumber=12346;
  7. intdivisor=3;
  8. char*buf=calloc(number,1);
  9. fwrite(buf,number,1,fp);
  10. rewind(fp);
  11. intresult=fread(buf,divisor,number,fp);
  12. printf("%d/%d=%d",number,divisor,result);
  13. free(buf);
  14. fclose(fp);
  15. return0;
  16. }

第三种方法:

  1. log(pow(exp(number),0.33333333333333333333))/*:-)*/

增强版:

  1. log(pow(exp(number),sin(atan2(1,sqrt(8)))))

第四种方法:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. intmain(intargc,char*argv[])
  4. {
  5. intnum=1234567;
  6. intden=3;
  7. div_tr=div(num,den);//div()是标准C语言函数
  8. printf("%d\n",r.quot);
  9. return0;
  10. }

第五种方法:使用内联汇编

  1. #include<stdio.h>
  2. intmain(){
  3. intdividend=-42,divisor=3,quotient,remainder;
  4. __asm__("movl%2,%%edx;"
  5. "sarl$31,%%edx;"
  6. "movl%2,%%eax;"
  7. "movl%3,%%ebx;"
  8. "idivl%%ebx;"
  9. :"=a"(quotient),"=d"(remainder)
  10. :"g"(dividend),"g"(divisor)
  11. :"ebx");
  12. printf("%i/%i=%i,remainder:%i\n",dividend,divisor,quotient,remainder);
  13. }

第六种方法:

  1. //注意:itoa不是个标准函数,但它可以实现
  2. //don'tseemtohandlenegativewhenbase!=10
  3. intdiv3(inti){
  4. charstr[42];
  5. sprintf(str,"%d",INT_MIN);//putminussignatstr[0]
  6. if(i>0)str[0]='';//removesignifpositive
  7. itoa(abs(i),&str[1],3);//putternaryabsolutevaluestartingatstr[1]
  8. str[strlen(&str[1])]='\0';//droplastdigit
  9. returnstrtol(str,NULL,3);//readbackresult
  10. }

第七种方法:

  1. unsigneddiv_by(unsignedconstx,unsignedconstby){
  2. unsignedfloor=0;
  3. for(unsignedcmp=0,r=0;cmp<=x;){
  4. for(unsignedi=0;i<by;i++)
  5. cmp++;//这是++操作符,不是+
  6. floor=r;
  7. r++;//这也不是
  8. }
  9. returnfloor;
  10. }

替换掉上面算法的++运算符:

  1. unsignedinc(unsignedx){
  2. for(unsignedmask=1;mask;mask<<=1){
  3. if(mask&x)
  4. x&=~mask;
  5. else
  6. returnx&mask;
  7. }
  8. return0;//溢出(注意:这里的x和mask都是0)
  9. }

这个版本更快一些:

  1. unsignedadd(charconstzero[],unsignedconstx,unsignedconsty){
  2. //这是因为:如果foo是char*类型,&foo[bar]==foo+bar
  3. return(int)(uintptr_t)(&((&zero[x])[y]));
  4. }
  5. unsigneddiv_by(unsignedconstx,unsignedconstby){
  6. unsignedfloor=0;
  7. for(unsignedcmp=0,r=0;cmp<=x;){
  8. cmp=add(0,cmp,by);
  9. floor=r;
  10. r=add(0,r,1);
  11. }
  12. returnfloor;
  13. }

第八种方法:实现乘法

  1. intmul(intconstx,intconsty){
  2. returnsizeof(struct{
  3. charconstignore[y];
  4. }[x]);
  5. }

第九种方法:极限

  1. publicstaticintdiv_by_3(longa){
  2. a<<=30;
  3. for(inti=2;i<=32;i<<=1){
  4. a=add(a,a>>i);
  5. }
  6. return(int)(a>>32);
  7. }
  8. publicstaticlongadd(longa,longb){
  9. longcarry=(a&b)<<1;
  10. longsum=(a^b);
  11. returncarry==0?sum:add(carry,sum);
  12. }

原理:

因为, 1/3 = 1/4 + 1/16 + 1/64 + ...

所以,

a/3 = a * 1/3

a/3 = a * (1/4 + 1/16 + 1/64 + ...)

a/3 = a/4 + a/16 + 1/64 + ...

a/3 = a >> 2 + a >> 4 + a >> 6 + ...

第十种方法:

  1. publicstaticintDivideBy3(inta){
  2. boolnegative=a<0;
  3. if(negative)a=Negate(a);
  4. intresult;
  5. intsub=3<<29;
  6. intthrees=1<<29;
  7. result=0;
  8. while(threes>0){
  9. if(a>=sub){
  10. a=Add(a,Negate(sub));
  11. result=Add(result,threes);
  12. }
  13. sub>>=1;
  14. threes>>=1;
  15. }
  16. if(negative)result=Negate(result);
  17. returnresult;
  18. }
  19. publicstaticintNegate(inta){
  20. returnAdd(~a,1);
  21. }
  22. publicstaticintAdd(inta,intb){
  23. intx=0;
  24. x=a^b;
  25. while((a&b)!=0){
  26. b=(a&b)<<1;
  27. a=x;
  28. x=a^b;
  29. }
  30. returnx;
  31. }

注:本例是C#实现,因为作者更熟悉C#,但本题更倾向于算法,所以语言并不是太重要吧?(当然只是在不使用语言特性的前提下。)

如果你还想了解更多的方法可以点击这里


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics