内容主要来源:http://stackoverflow.com/questions/11694546/divide-a-number-by-3-without-using-operators 。根据此论坛进行整理。
在不使用*、/、+、-、%操作符的情况下,如何求一个数的1/3?
There is a simple function I found here. But it's using the+
operator, so you have to add the values with the bit-operators:
// replaces the + operator 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; }
As Jim commented this works because:
原理: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
Idiotic conditions call for an idiotic solution:
#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; }
If also the decimal part is needed, just declareresult
asdouble
and add to it the result offmod(number,divisor)
.
Explanation of how it works
fwrite
writes number
bytes (number being 123456 in the example above).rewind
resets the file pointer to the front of the file.fread
reads a maximum ofnumber
"records" that aredivisor
in length from the file, and returns the number of elements it read.If you write 30 bytes then read back the file in units of 3, you get 10 "units". 30 / 3 = 10
log(pow(exp(number),0.33333333333333333333)) /* :-) */
Improved version:
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() is a standard C function. printf("%d\n", r.quot); return 0; }
Use inline assembler:
#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); }
Use itoa to convert to base 3 string.Drop last trit and convert back to base 10.
// Note: itoa is non-standard but actual implementations // 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++; // that's not the + operator! floor = r; r++; // neither is this. } return floor; }Edit: go on an replace the ++ operator as well(替换掉上面算法的++运算符):
unsigned inc(unsigned x) { for (unsigned mask = 1; mask; mask <<= 1) { if (mask & x) x &= ~mask; else return x & mask; } return 0; // overflow (note that both x and mask are 0 here) }Edit2:Slightly faster Version(这个版本更快一些:):
unsigned add(char const zero[], unsigned const x, unsigned const y) { // this exploits that &foo[bar] == foo+bar if foo is of type char* 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; }
(implement a multiplication function using a similar trick to use the0x55555556
trick proposed)
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); }First, note that
1/3 = 1/4 + 1/16 + 1/64 + ...Now, the rest is simple!
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 + ...
Now all we have to do is add together these bit shifted values of a! Oops! We can't add though, so instead, we'll have to write an add function using bit-wise operators! If you're familiar with bit-wise operators, my solution should look fairly simple... but just in-case you aren't, I'll walk through an example at the end.
Another thing to note is that first I shift left by 30! This is to make sure that the fractions don't get rounded off.
11 + 6 1011 + 0110 sum = 1011 ^ 0110 = 1101 carry = (1011 & 0110) << 1 = 0010 << 1 = 0100 Now you recurse! 1101 + 0100 sum = 1101 ^ 0100 = 1001 carry = (1101 & 0100) << 1 = 0100 << 1 = 1000 Again! 1001 + 1000 sum = 1001 ^ 1000 = 0001 carry = (1001 & 1000) << 1 = 1000 << 1 = 10000 One last time! 0001 + 10000 sum = 0001 ^ 10000 = 10001 = 17 carry = (0001 & 10000) << 1 = 0 Done!It's simply carry addition that you learned as a child!
111 1011 +0110 ----- 10001This implementation failed because we can not add all terms of the equation:
a / 3 = a/4 + a/4^2 + a/4^3 + ... + a/4^i + ... = f(a, i) + a * 1/3 * 1/4^i f(a, i) = a/4 + a/4^2 + ... + a/4^iSuppose the reslut of
div_by_3(a)
= x, thenx <= floor(f(a, i)) < a / 3
. Whena = 3k
, we get wrong answer.
Yet another solution. This should handle all ints (including negative ints) except the min value of an int, which would need to be handled as a hard coded exception. This basically does division by subtraction but only using bit operators (shifts, xor, & and complement). For faster speed, it subtracts 3 * (decreasing powers of 2). In c#, it executes around 444 of these DivideBy3 calls per millisecond (2.2 seconds for 1,000,000 divides), so not horrendously slow, but no where near as fast as a simple x/3. By comparison, Coodey's nice solution is about 5 times faster than this one.
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; }This is c# because that's what I had handy, but differences from c should be minor.
Using Ada and multithreading:
with Ada.Text_IO; procedure Divide_By_3 is protected type Divisor_Type is entry Poke; entry Finish; private entry Release; entry Stop_Emptying; Emptying : Boolean := False; end Divisor_Type; protected type Collector_Type is entry Poke; entry Finish; private Emptying : Boolean := False; end Collector_Type; task type Input is end Input; task type Output is end Output; protected body Divisor_Type is entry Poke when not Emptying and Stop_Emptying'Count = 0 is begin requeue Release; end Poke; entry Release when Release'Count >= 3 or Emptying is New_Output : access Output; begin if not Emptying then New_Output := new Output; Emptying := True; requeue Stop_Emptying; end if; end Release; entry Stop_Emptying when Release'Count = 0 is begin Emptying := False; end Stop_Emptying; entry Finish when Poke'Count = 0 and Release'Count < 3 is begin Emptying := True; requeue Stop_Emptying; end Finish; end Divisor_Type; protected body Collector_Type is entry Poke when Emptying is begin null; end Poke; entry Finish when True is begin Ada.Text_IO.Put_Line (Poke'Count'Img); Emptying := True; end Finish; end Collector_Type; Collector : Collector_Type; Divisor : Divisor_Type; task body Input is begin Divisor.Poke; end Input; task body Output is begin Collector.Poke; end Output; Cur_Input : access Input; -- Input value: Number : Integer := 18; begin for I in 1 .. Number loop Cur_Input := new Input; end loop; Divisor.Finish; Collector.Finish; end Divide_By_3;========================================================= 转载请注明出处:http://blog.csdn.net/songzitea/article/details/12987671