[Open-graphics] peer review of a fast boolean addition algorithm, please...

Mark mark at jarvin.net
Thu Aug 30 08:26:36 EDT 2007


Dennis Heuer wrote:
> many thanks for your replies. naturally, i'm a bit disappointed with
> the reviews :) can you point me at good internet literature about the
> alternatives? however, for completeness, i also put the following
> subtraction under the original BSD license:
>
Many thanks to you for the proposal -- I certainly enjoyed thinking it 
through.

I found this page linked to by the Wikipedia article on adders, and it 
seems to be pretty good:
http://www.aoki.ecei.tohoku.ac.jp/arith/mg/algorithm.html

> the problem with the subtraction is that detecting the carry isn't that
> easy. boolean XOR catches both 1->0 and 0->1, though only the first case
> is to be considered. for a luck, filtering the first case out can be
> done with a combination of XOR and AND. this is just how the other
> algorithm worked except that using the XOR for both the basic addition
> and the first step of the calculation of the carry needs some change in
> the order of re-using the values. also, the bitshift must be done before
> the carry is used in the next XOR because the shifted value is also the
> correct input for the next AND. confused? just look at the following
> code in c:
> 
> int main ()
> {
>     // boolean subtraction with bit shifting
>     unsigned int x = 23;  // the first value
>     unsigned int y = 15;  // the second value, which is also the
>                           // carry bitfield
> 
>     while (y != 0)
>     {
>         x = x ^ y;     // first calculating the addition or, from then,
>                        // the merging with the current carry bitfield
>         y = y & x;     // before the result becomes the second input of
>                        // the calculation of the next carry
>         y = y << 1;    // shifting the carry to merge it with x
>     }                  // already beginning from above again
> 
>     if (x == 8)
>         printf("test passed!\n");
> 
>     return 0;
> }
> 
> in the end, this algorithm is even easier than the other. one can skip
> the third variable for the carry (at least in code this makes a
> difference.)
> 
The downside from a logic implementation perspective is that you now 
have a data dependency between two operations where you didn't before, 
meaning that each stage is two gate-delays instead of one.  If you want 
to keep the basic adder block the same for the adder & subtractor, you 
can add a layer of XORs at the minuend input and the output to invert 
both in the case of subtraction.  Of course, if it's a pure subtractor, 
use inverters instead of XORs.  This is what I meant by "negate one 
input", which was really a sloppy way of phrasing it on my part -- 
sorry.  What do you think?

#include <iostream>

unsigned int doit(unsigned int a, unsigned int b, unsigned int sub) {
     unsigned int x=a^sub;
     unsigned int y=b;
     for(int j=0; j<sizeof(a)<<3; j++) {
       int z=x;
       x=y^z;
       y=(y&z)<<1;
     }
     return x^sub;
}
int main(void) {
   unsigned int numadd = 0;
   unsigned int numsub = 0;
   for (int i=0; i<10000; i++) {
     unsigned int sub = (rand()&1?~0:0);
     unsigned int a = rand();
     unsigned int b = rand();
     unsigned int x = doit(a,b,sub);
     unsigned int y = (sub?a-b:a+b);
     if (x!=y) {
       std::cout << "Error: tried " << a << (sub?" - ":" + ") << b;
       std::cout << ", expected " << y << " but got " << x << ".";
       std::cout << std::endl;
       return -1;
     } else if (sub)
       numsub++;
     else
       numadd++;
   }
   std::cout << "Success: " << numadd << " additions, ";
   std::cout << numsub << " subtractions." << std::endl;
   return 0;
}


More information about the Open-graphics mailing list