導讀:算法一直是程序員進階的一道龍門,通常算法都是為了更高效地解決問題而創造的,但也有的只是出于學術性,并不在意其實際意義。這是近日在國外技術問答網站stackoverflow的一個熱門問題,不知道你能給出幾種解決方法?
問:在不使用*、/、+、-、%操作符的情況下,如何求一個數的1/3?(用C語言實現)
第一種方法:使用位操作符并實現“+”操作
- //?替換加法運算符?
- int?add(int?x,?int?y)?{?
- ????int?a,?b;?
- ????do?{?
- ????????a?=?x?&?y;?
- ????????b?=?x?^?y;?
- ????????x?=?a?<<?1;?
- ????????y?=?b;?
- ????}?while?(a);?
- ????return?b;?
- }?
- ?
- int?divideby3?(int?num)?{?
- ????int?sum?=?0;?
- ????while?(num?>?3)?{?
- ????????sum?=?add(num?>>?2,?sum);?
- ????????num?=?add(num?>>?2,?num?&?3);?
- ????}?
- ????if?(num?==?3)?
- ????????sum?=?add(sum,?1);?
- ????return?sum;??
- }?
原理: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
第二種方法:
- #include?<stdio.h>?
- #include?<stdlib.h>?
- int?main()?
- {?
- ????FILE?*?fp=fopen("temp.dat","w+b");?
- ????int?number=12346;?
- ????int?divisor=3;?
- ????char?*?buf?=?calloc(number,1);?
- ????fwrite(buf,number,1,fp);?
- ????rewind(fp);?
- ????int?result=fread(buf,divisor,number,fp);?
- ????printf("%d?/?%d?=?%d",?number,?divisor,?result);?
- ????free(buf);?
- ????fclose(fp);?
- ????return?0;?
- }?
第三種方法:
- log(pow(exp(number),0.33333333333333333333))?/*?:-)?*/?
增強版:
- log(pow(exp(number),sin(atan2(1,sqrt(8)))))??
第四種方法:
- #include?<stdio.h>?
- #include?<stdlib.h>?
- int?main(int?argc,?char?*argv[])?
- {?
- ????int?num?=?1234567;?
- ????int?den?=?3;?
- ????div_t?r?=?div(num,den);?//?div()是標準C語言函數
- ????printf("%d\n",?r.quot);?
- ????return?0;?
- }?
第五種方法:使用內聯匯編
- #include?<stdio.h>?
- int?main()?{?
- ??int?dividend?=?-42,?divisor?=?3,?quotient,?remainder;?
- ?
- ??__asm__?(?"movl???%2,?%%edx;"?
- ????????????"sarl??$31,?%%edx;"?
- ????????????"movl???%2,?%%eax;"?
- ????????????"movl???%3,?%%ebx;"?
- ????????????"idivl??????%%ebx;"?
- ??????????:?"=a"?(quotient),?"=d"?(remainder)?
- ??????????:?"g"??(dividend),?"g"??(divisor)?
- ??????????:?"ebx"?);?
- ?
- ??printf("%i?/?%i?=?%i,?remainder:?%i\n",?dividend,?divisor,?quotient,?remainder);?
- }?
第六種方法:
- //?注意:?itoa?不是個標準函數,但它可以實現
- //?don't?seem?to?handle?negative?when?base?!=?10?
- int?div3(int?i)?{?
- ??char?str[42];?
- ??sprintf(str,?"%d",?INT_MIN);?//?put?minus?sign?at?str[0]?
- ??if?(i>0)?str[0]?=?'?';???????//?remove?sign?if?positive?
- ??itoa(abs(i),?&str[1],?3);????//?put?ternary?absolute?value?starting?at?str[1]?
- ??str[strlen(&str[1])]?=?'\0';?//?drop?last?digit?
- ??return?strtol(str,?NULL,?3);?//?read?back?result?
- }?
第七種方法:
- unsigned?div_by(unsigned?const?x,?unsigned?const?by)?{?
- ??unsigned?floor?=?0;?
- ??for?(unsigned?cmp?=?0,?r?=?0;?cmp?<=?x;)?{?
- ????for?(unsigned?i?=?0;?i?<?by;?i++)?
- ??????cmp++;?//?這是++操作符,不是+?
- ????floor?=?r;?
- ????r++;?//?這也不是?
- ??}?
- ??return?floor;?
- }?
替換掉上面算法的++運算符:
- unsigned?inc(unsigned?x)?{?
- ??for?(unsigned?mask?=?1;?mask;?mask?<<=?1)?{?
- ????if?(mask?&?x)?
- ??????x?&=?~mask;?
- ????else?
- ??????return?x?&?mask;?
- ??}?
- ??return?0;?//?溢出(注意:這里的x和mask都是0)
- }?
這個版本更快一些:
- unsigned?add(char?const?zero[],?unsigned?const?x,?unsigned?const?y)?{?
- ??//?這是因為:如果foo是char*類型,?&foo[bar]?==?foo+bar
- ??return?(int)(uintptr_t)(&((&zero[x])[y]));?
- }?
- ?
- unsigned?div_by(unsigned?const?x,?unsigned?const?by)?{?
- ??unsigned?floor?=?0;?
- ??for?(unsigned?cmp?=?0,?r?=?0;?cmp?<=?x;)?{?
- ????cmp?=?add(0,cmp,by);?
- ????floor?=?r;?
- ????r?=?add(0,r,1);?
- ??}?
- ??return?floor;?
- }?
第八種方法:實現乘法
- int?mul(int?const?x,?int?const?y)?{?
- ??return?sizeof(struct?{?
- ????char?const?ignore[y];?
- ??}[x]);?
- }?
第九種方法:極限
- public?static?int?div_by_3(long?a)?{?
- ????a?<<=?30;?
- ????for(int?i?=?2;?i?<=?32?;?i?<<=?1)?{?
- ????????a?=?add(a,?a?>>?i);?
- ????}?
- ????return?(int)?(a?>>?32);?
- }?
- ?
- public?static?long?add(long?a,?long?b)?{?
- ????long?carry?=?(a?&?b)?<<?1;?
- ????long?sum?=?(a?^?b);?
- ????return?carry?==?0???sum?:?add(carry,?sum);?
- }?
原理:
因為, 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 + ...
第十種方法:
- public?static?int?DivideBy3(int?a)?{?
- ????bool?negative?=?a?<?0;?
- ????if?(negative)?a?=?Negate(a);?
- ????int?result;?
- ????int?sub?=?3?<<?29;?
- ????int?threes?=?1?<<?29;?
- ????result?=?0;?
- ????while?(threes?>?0)?{?
- ????????if?(a?>=?sub)?{?
- ????????????a?=?Add(a,?Negate(sub));?
- ????????????result?=?Add(result,?threes);?
- ????????}?
- ????????sub?>>=?1;?
- ????????threes?>>=?1;?
- ????}?
- ????if?(negative)?result?=?Negate(result);?
- ????return?result;?
- }?
- public?static?int?Negate(int?a)?{?
- ????return?Add(~a,?1);?
- }?
- public?static?int?Add(int?a,?int?b)?{?
- ????int?x?=?0;?
- ????x?=?a?^?b;?
- ????while?((a?&?b)?!=?0)?{?
- ????????b?=?(a?&?b)?<<?1;?
- ????????a?=?x;?
- ????????x?=?a?^?b;?
- ????}?
- ????return?x;?
- }?
注:本例是C#實現,因為作者更熟悉C#,但本題更傾向于算法,所以語言并不是太重要吧?(當然只是在不使用語言特性的前提下。)
如果你還想了解更多的方法可以點擊這里。