Basically, the behavior you get when overflowing integers with subtraction, but for a given number of bits. The obvious way, assuming a signed integer:
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.
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);
}
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
.
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