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

問:在不使用*、/、+、-、%操作符的情況下,如何求一個數的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;  

原理: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.     FILE * fp=fopen("temp.dat","w+b"); 
  5.     int number=12346; 
  6.     int divisor=3; 
  7.     char * buf = calloc(number,1); 
  8.     fwrite(buf,number,1,fp); 
  9.     rewind(fp); 
  10.     int result=fread(buf,divisor,number,fp); 
  11.     printf("%d / %d = %d", number, divisor, result); 
  12.     free(buf); 
  13.     fclose(fp); 
  14.     return 0; 

第三種方法:

  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.     int num = 1234567; 
  5.     int den = 3; 
  6.     div_t r = div(num,den); // div()是標準C語言函數
  7.     printf("%d\n", r.quot); 
  8.     return 0; 

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

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

第六種方法:

  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 

第七種方法:

  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; 

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

  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)

這個版本更快一些:

  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; 

第八種方法:實現乘法

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

第九種方法:極限

  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); 

原理:

因爲, 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. public static int Negate(int a) { 
  19.     return Add(~a, 1); 
  20. public static int Add(int a, int b) { 
  21.     int x = 0
  22.     x = a ^ b; 
  23.     while ((a & b) != 0) { 
  24.         b = (a & b) << 1
  25.         a = x
  26.         x = a ^ b; 
  27.     } 
  28.     return x; 
發佈了34 篇原創文章 · 獲贊 7 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章