Integer subtraction with wrap around for N bits

后端 未结 4 1365
逝去的感伤
逝去的感伤 2021-01-05 20:56

Basically, the behavior you get when overflowing integers with subtraction, but for a given number of bits. The obvious way, assuming a signed integer:

相关标签:
4条回答
  • 2021-01-05 21:19

    This simulates an n bit integer operation:

    #include <iostream>
    #include <cstdlib>
    
    template< typename T >
    T sub_wrap(T a, T b, int nBits)
    {
            T topBit, mask, tmp;
    
            topBit=T(1) << (nBits-1);
            mask=(topBit << 1)-1;
            tmp=((a&mask)+((~b+1)&mask))&mask;
            if (tmp & topBit) tmp=-((~tmp&mask)+1);
    
            return tmp;
    }
    
    int main(int argc, char* argv[])
    {
            std::cout << sub_wrap< int >(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]))
                    << std::endl;
            return 0;
    }
    

    Results:

    $ ./sim 5 6 4
    -1
    $ ./sim 7 3 4
    4
    $ ./sim 7 -1 4
    -8
    $ ./sim -16 28 4
    4
    $ ./sim -16 28 5
    -12
    $ ./sim -16 28 6
    20
    

    Seems you miscalculated your type size by 1 bit.

    0 讨论(0)
  • 2021-01-05 21:21

    I suppose this should work:

     struct bits
     {
         signed int field : 5;
     };
    
     bits a = { -16 };     
     bits b = {  28 };
    
     bits c = { a.field - b.field };
     std::cout << c.field << std::endl;
    

    I'm pretty sure the field width won't work with a const template argument... and hence this is less generic. It should, however, avoid manual tinkering. Will post test soon

    Update It turns out my answer wasn't incorrect after all. It is just that the sample input (28) cannot be represented in 5 bits (signed). The outcome of the above is -12 (see http://ideone.com/AUrXy).

    Here is, for completeness, a templated version after all:

    template<int bits>
    int sub_wrap(int v, int s)
    {
        struct helper { signed int f: bits; } tmp = { v };
        return (tmp.f -= s);
    }
    
    0 讨论(0)
  • 2021-01-05 21:28

    For unsigned arithmetic, and mask the results, e.g.:

    template<int bits>
    unsigned
    sub_wrap( unsigned v, unsigned s )
    {
        return (v - s) & ((1 << bits) - 1);
    }
    

    More generally, you can use the modulo operator:

    template<int modulo>
    unsigned
    sub_wrap( unsigned v, unsigned s )
    {
        return (v - s) % modulo;
    }
    

    (Wrapping on n bits is the equivalent of modulo 2^n.)

    For signed arithmetic, it's a bit more complex; using the mask, you'll have to sign extend the results (supposing 2's complement).

    EDIT: Using sehe's suggestion for signed arithmetic:

    template<int bits>
    int
    sub_wrap( int v, int s )
    {
        struct Bits { signed int r: bits; } tmp;
        tmp.r = v - s;
        return tmp.r;
    }
    

    Given this, sub_wrap<5>( -16, 28 ) gives -12 (which is correct—note that 28 cannot be represented as signed int in 5 bits); sub_wrap<6>( -16, 28 ) gives 20.

    0 讨论(0)
  • 2021-01-05 21:39

    Here's how I'd do it w/o conditional branches and multiplication:

    #include <stdio.h>
    
    // Assumptions:
    // - ints are 32-bit
    // - signed ints are 2's complement
    // - right shifts of signed ints are sign-preserving arithmetic shifts
    // - signed overflows are harmless even though strictly speaking they
    //   result in undefined behavior
    //
    // Requirements:
    // - 0 < bits <= 32
    int sub_wrap(int v, int s, unsigned bits)
    {
      int d = v - s;
      unsigned m = ~0u >> (32 - bits);
      int r = d & m | -((d >> (bits - 1)) & 1) & ~m;
      return r;
    }
    
    #define BITS 2
    
    int main(void)
    {
      int i, j;
      for (i = -(1 << (BITS - 1)); i <= (1 << (BITS - 1)) - 1; i++)
        for (j = -(1 << (BITS - 1)); j <= (1 << (BITS - 1)) - 1; j++)
          printf("%d - %d = %d\n", i, j, sub_wrap(i, j, BITS));
      return 0;
    }
    

    Output:

    -2 - -2 = 0
    -2 - -1 = -1
    -2 - 0 = -2
    -2 - 1 = 1
    -1 - -2 = 1
    -1 - -1 = 0
    -1 - 0 = -1
    -1 - 1 = -2
    0 - -2 = -2
    0 - -1 = 1
    0 - 0 = 0
    0 - 1 = -1
    1 - -2 = -1
    1 - -1 = -2
    1 - 0 = 1
    1 - 1 = 0
    
    0 讨论(0)
提交回复
热议问题