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

原地址:http://sd.csdn.net/a/20120807/2808268-divide-a-number-by-3-without-operators.html

       導讀:算法一直是程序員進階的一道龍門,通常算法都是爲了更高效地解決問題而創造的,但也有的只是出於學術性,並不在意其實際意義。這是近日在國外技術問答網站stackoverflow的一個熱門問題,不知道你能給出幾種解決方法?

問:在不使用*、/、+、-、%操作符的情況下,如何求一個數的1/3?(用C語言實現)

第一種方法:使用位操作符並實現“+”操作

  1. // 替換加法運算符
  2. int add(int x, int y) {
  3. int a, b;
  4. do {
  5. a = x & y;
  6. b = x ^ y;
  7. x = a << 1;
  8. y = b;
  9. } while (a);
  10. return b;
  11. }
  12. int divideby3 (int num) {
  13. int sum = 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. return sum;
  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. int main()
  4. {
  5. FILE * fp=fopen("temp.dat","w+b");
  6. int number=12346;
  7. int divisor=3;
  8. char * buf = calloc(number,1);
  9. fwrite(buf,number,1,fp);
  10. rewind(fp);
  11. int result=fread(buf,divisor,number,fp);
  12. printf("%d / %d = %d", number, divisor, result);
  13. free(buf);
  14. fclose(fp);
  15. return 0;
  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. int main(int argc, char *argv[])
  4. {
  5. int num = 1234567;
  6. int den = 3;
  7. div_t r = div(num,den); // div()是標準C語言函數
  8. printf("%d\n", r.quot);
  9. return 0;
  10. }

第五種方法:使用內聯彙編

  1. #include <stdio.h>
  2. int main() {
  3. int dividend = -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't seem to handle negative when base != 10
  3. int div3(int i) {
  4. char str[42];
  5. sprintf(str, "%d", INT_MIN); // put minus sign at str[0]
  6. if (i>0) str[0] = ' '; // remove sign if positive
  7. itoa(abs(i), &str[1], 3); // put ternary absolute value starting at str[1]
  8. str[strlen(&str[1])] = '\0'; // drop last digit
  9. return strtol(str, NULL, 3); // read back result
  10. }

第七種方法:

  1. unsigned div_by(unsigned const x, unsigned const by) {
  2. unsigned floor = 0;
  3. for (unsigned cmp = 0, r = 0; cmp <= x;) {
  4. for (unsigned i = 0; i < by; i++)
  5. cmp++; // 這是++操作符,不是+
  6. floor = r;
  7. r++; // 這也不是
  8. }
  9. return floor;
  10. }

替換掉上面算法的++運算符:

  1. unsigned inc(unsigned x) {
  2. for (unsigned mask = 1; mask; mask <<= 1) {
  3. if (mask & x)
  4. x &= ~mask;
  5. else
  6. return x & mask;
  7. }
  8. return 0; // 溢出(注意:這裏的x和mask都是0)
  9. }

這個版本更快一些:

  1. unsigned add(char const zero[], unsigned const x, unsigned const y) {
  2. // 這是因爲:如果foo是char*類型, &foo[bar] == foo+bar
  3. return (int)(uintptr_t)(&((&zero[x])[y]));
  4. }
  5. unsigned div_by(unsigned const x, unsigned const by) {
  6. unsigned floor = 0;
  7. for (unsigned cmp = 0, r = 0; cmp <= x;) {
  8. cmp = add(0,cmp,by);
  9. floor = r;
  10. r = add(0,r,1);
  11. }
  12. return floor;
  13. }

第八種方法:實現乘法

  1. int mul(int const x, int const y) {
  2. return sizeof(struct {
  3. char const ignore[y];
  4. }[x]);
  5. }

第九種方法:極限

  1. public static int div_by_3(long a) {
  2. a <<= 30;
  3. for(int i = 2; i <= 32 ; i <<= 1) {
  4. a = add(a, a >> i);
  5. }
  6. return (int) (a >> 32);
  7. }
  8. public static long add(long a, long b) {
  9. long carry = (a & b) << 1;
  10. long sum = (a ^ b);
  11. return carry == 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. public static int DivideBy3(int a) {
  2. bool negative = a < 0;
  3. if (negative) a = Negate(a);
  4. int result;
  5. int sub = 3 << 29;
  6. int threes = 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. return result;
  18. }
  19. public static int Negate(int a) {
  20. return Add(~a, 1);
  21. }
  22. public static int Add(int a, int b) {
  23. int x = 0;
  24. x = a ^ b;
  25. while ((a & b) != 0) {
  26. b = (a & b) << 1;
  27. a = x;
  28. x = a ^ b;
  29. }
  30. return x;
  31. }

注:本例是C#實現,因爲作者更熟悉C#,但本題更傾向於算法,所以語言並不是太重要吧?(當然只是在不使用語言特性的前提下。)


發佈了58 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章