Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Upvote Ira and mbratch, I am simply expanding on their answer to understand how and why it works. </p> <p>It is basically grade school stuff...Remember base 10 multiplies:</p> <pre><code> 1234 * 11 ======= 1234 (1*1234) +12340 (10*1234) ======= 13574 </code></pre> <p>binary makes that much easier because the digits can only be 1 or 0 no 2, 3, 4, etc...</p> <pre><code> 1111 * 11 ========= 1111 (1*1111) +11110 (10*1111) ====== 101101 </code></pre> <p>so if I have some generic bits xyz, multiplied by 5 then</p> <pre><code> xyz * 101 ======== xyz +xyz00 ======= </code></pre> <p>because 5 = 4+1 = 2^2 + 2^0 = 1&lt;&lt;2 + 1&lt;&lt;0 then some variable n*5 = (n&lt;&lt;2) + (n&lt;&lt;0)</p> <p>What is the binary for 1/3rd? Well why not use long division from grade school?</p> <pre><code> 0.01010101 ----------- 11)1.00000000 1 bring down the 1 -0 0 times 3 first digit is a 0 ==== 10 bring down the 0 -00 0 times 3, second digit is 0 ==== 100 bring down the 0 - 11 1 times 3, next digit is a 1 ==== 10 result 1, bring down 0 - 0 0 times 3, next digit is a 0 === 100 result is 2, bring down the 0 - 11 1 times 3, next digit is a 1 ==== 10 </code></pre> <p>and the pattern begins to repeat 0.01010101...</p> <p>So if a multiply by 5 means binary 101*n = (n&lt;&lt;2) + (n&lt;&lt;0) because the non-zero bits are at the 2^0 and 2^2 locations. Then if you do the multiplication as we did with 5 above it doesnt matter if there is a decimal place. 0.1 is 2 to the power -1, 0.01 is 2 to the power -2 and so on so binary 1.01 times N would be (n&lt;&lt;0) + (n>>2). </p> <p>And finally multiplying by 1/3rd which is approximated with 0.0101010101.... that means</p> <pre><code>result = (n&gt;&gt;2) + (n&gt;&gt;4) + (n&gt;&gt;6) + ... </code></pre> <p>Which as pointed out by someone else you can do that in a loop, something along the lines of.</p> <pre><code>result = 0; while(n) { n&gt;&gt;=2; result+=n; } </code></pre> <p>Just like in base 10, when you divide by something that has a factor of 3 in it you get an infinitely repeating number, you have the same problem in base 2, an infinite repeating number. Just like base 10 where sometimes you want 0.6666666 to be 0.666667 depending on how many digits, but not round 0.333333 you might want to round your divisor and have extra bit in there 0.0101011 or something like that.</p> <p>divthree.c</p> <pre><code>unsigned int divthree ( unsigned int x ) { unsigned int y; y=0; x&lt;&lt;=16; while(x) { x&gt;&gt;=2; y+=x; } </code></pre> <p>// y+=0x8000; //round up? y>>=16; return(y); }</p> <p>main.c </p> <pre><code>#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; extern unsigned int divthree ( unsigned int ); unsigned int next_prand ( unsigned int x ) { if(x&amp;1) { x=x&gt;&gt;1; x=x^0xBF9EC099; } else { x=x&gt;&gt;1; } return(x); } int main ( void ) { unsigned int ra,rb,rc,rd,re; unsigned int p; unsigned int prand; prand=0x12345; for(ra=0;ra&lt;20;ra++) { prand=next_prand(prand); p=prand&amp;0xFFFF; rb=p/3; rc=divthree(p); rd=divthree(p+1); re=divthree(p+2); printf("%u %u ",p,rb); printf("(%u %d) ",rc,rc-rb); printf("(%u %d) ",rd,rd-rb); printf("(%u %d) ",re,re-rb); printf("\n"); } return(0); } </code></pre> <p>so running the above, without doing the rounding...</p> <pre><code>6931 (6931 0) (6931 0) (6932 1) 19798 (19798 0) (19798 0) (19799 1) 20822 (20821 -1) (20822 0) (20822 0) 10411 (10410 -1) (10411 0) (10411 0) 21640 (21640 0) (21640 0) (21640 0) 16241 (16241 0) (16241 0) (16242 1) 13627 (13627 0) (13627 0) (13628 1) 12224 (12223 -1) (12224 0) (12224 0) 6112 (6111 -1) (6112 0) (6112 0) 3056 (3055 -1) (3056 0) (3056 0) 12450 (12450 0) (12450 0) (12451 1) 6225 (6225 0) (6225 0) (6225 0) 3112 (3112 0) (3112 0) (3113 1) 1556 (1556 0) (1556 0) (1556 0) 6274 (6274 0) (6274 0) (6274 0) 8563 (8563 0) (8563 0) (8563 0) 4281 (4281 0) (4281 0) (4282 1) 7642 (7642 0) (7642 0) (7642 0) 20170 (20169 -1) (20170 0) (20170 0) 10085 (10084 -1) (10085 0) (10085 0) </code></pre> <p>that second set, divthree(n+1) is right on so far...</p> <p>to improve on the multiply by this irrational number, notice how the division routine gave lots more precision (didnt need to be that extreme) assuming 16 bit numbers using 32 bit math operations. </p> <p>Not doing that</p> <pre><code>unsigned int divthree ( unsigned int x ) { unsigned int y; y=0; //x&lt;&lt;=16; while(x) { x&gt;&gt;=2; y+=x; } //y+=0x8000; //y&gt;&gt;=16; return(y); } </code></pre> <p>Not as accurate as one would hope.</p> <pre><code>20795 6931 (6928 -3) (6929 -2) (6929 -2) 59396 19798 (19796 -2) (19796 -2) (19796 -2) 62466 20822 (20819 -3) (20819 -3) (20820 -2) 31233 10411 (10408 -3) (10408 -3) (10408 -3) 64921 21640 (21635 -5) (21635 -5) (21635 -5) 48725 16241 (16237 -4) (16237 -4) (16237 -4) 40883 13627 (13622 -5) (13623 -4) (13623 -4) 36672 12224 (12221 -3) (12221 -3) (12221 -3) 18336 6112 (6109 -3) (6109 -3) (6109 -3) 9168 3056 (3053 -3) (3053 -3) (3053 -3) 37352 12450 (12447 -3) (12447 -3) (12447 -3) 18676 6225 (6222 -3) (6222 -3) (6222 -3) 9338 3112 (3109 -3) (3109 -3) (3110 -2) 4669 1556 (1553 -3) (1553 -3) (1553 -3) 18823 6274 (6271 -3) (6272 -2) (6272 -2) 25690 8563 (8560 -3) (8560 -3) (8561 -2) 12845 4281 (4278 -3) (4278 -3) (4278 -3) 22927 7642 (7638 -4) (7640 -2) (7640 -2) 60510 20170 (20165 -5) (20165 -5) (20167 -3) 30255 10085 (10080 -5) (10082 -3) (10082 -3) </code></pre> <p>(can start to appreciate what a floating point unit does or doesnt do for you).</p> <p>If you try shifting, one then two then three then four, this matches the shift 16 from above.</p> <pre><code>unsigned int divthree ( unsigned int x ) { unsigned int y; y=0; x&lt;&lt;=4; while(x) { x&gt;&gt;=2; y+=x; } y&gt;&gt;=4; return(y); } </code></pre> <p>you would need those extra 4 bits of headroom depending on your numbers or the instruction set/registers.</p> <p>So any time you want to multiply by (or divide by) a constant that is known at/before compile time you can use this simple method of shifting and adding. but you have to deal with accuracy if the division is by an irrational number.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload