Reputation: 33
I need to take all the digits in a hex number and "invert" them: all zeroes become non-zeroes (F) and all non-zeroes become zeroes.
I tried:
void someFunction(DWORD hexVal)
{
//...
hexVal = ~hexVal;
//...
}
and this changed 0xE0000000 to 0x1FFFFFFF instead of 0x0FFFFFFF.
How can I produce the desired result?
Upvotes: 2
Views: 7921
Reputation: 375634
Assuming you really meant that you want zero->non-zero and vice-versa, on a digit-by-digit basis:
DWORD invertDigits(DWORD in) {
return (
((in & (0xF << 28)) ? 0x0 : (0xF << 28)) |
((in & (0xF << 24)) ? 0x0 : (0xF << 24)) |
((in & (0xF << 20)) ? 0x0 : (0xF << 20)) |
((in & (0xF << 16)) ? 0x0 : (0xF << 16)) |
((in & (0xF << 12)) ? 0x0 : (0xF << 12)) |
((in & (0xF << 8)) ? 0x0 : (0xF << 8)) |
((in & (0xF << 4)) ? 0x0 : (0xF << 4)) |
((in & (0xF << 0)) ? 0x0 : (0xF << 0))
);
}
Upvotes: 3
Reputation: 13196
That is the desired result for the bitwise NOT operation. 0xE0000000 + 0x1FFFFFFF = 0xFFFFFFFF
The absolute fastest way to do what you want would be to split it into bytes and use a lookup table.
This solution takes the processor equivalent of about: 24 adds, 4 multiplies, and 4 memory lookups. The multiplies are part of the array indexing. All simple mathematical operations run at about the same speed, except multiplies and memory lookups which are slightly longer. Your mileage may vary depending on your processor architecture and the compiler optimizations performed.
unsigned int transform1(unsigned int value)
{
// static const unsigned char ZZ = 0x0, ZF = 0xF, FZ = 0xF0, FF = 0xFF; // for C++
#define ZZ (unsigned char) 0x00
#define FZ (unsigned char) 0xF0
#define ZF (unsigned char) 0x0F
#define FF (unsigned char) 0xFF
static const unsigned char lookup[256] =
{
FF, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ, FZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
ZF, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ, ZZ,
}; // array takes up 1KB of RAM
unsigned int result = 0;
result |= lookup[(unsigned int)((value & (FF << 0 )) >> 0) ] << 0;
result |= lookup[(unsigned int)((value & (FF << 8 )) >> 8) ] << 8;
result |= lookup[(unsigned int)((value & (FF << 16)) >> 16)] << 16;
result |= lookup[(unsigned int)((value & (FF << 24)) >> 24)] << 24;
return result;
}
Upvotes: 2
Reputation: 4744
So inversion and negation are two different things.
Inversion takes each bit and produces its complement like so:
0xE0000000 = 1110 0000 0000 0000 0000 0000 0000 0000
~0xE0000000 = 0001 1111 1111 1111 1111 1111 1111 1111 = 0x1FFFFFFF
If you want "Anything other than zero needs to become zero" you want boolean negation i.e.
hexVal = !hexVal;
EDIT: Okay, so I finally got what the asker was asking after reading some of the other answers, here's my personal version using one giant bit math expression
n = ~(n | ((n & 0x77777777) << 1) | ((n & 0x88888888) >> 3)
| ((n & 0x33333333) << 2) | ((n & 0xCCCCCCCC) >> 2)
| ((n & 0x11111111) << 3) | ((n & 0xEEEEEEEE) >> 1));
Upvotes: 1
Reputation: 60007
This should give you the desired result for 2 bytes. You get the idea for 4 bytes.
hexval = ((hexval & 0xf000) ? 0 : 0xf000) |
((hexval & 0xf00) ? 0 : 0xf00) |
((hexval & 0xf0) ? 0 : 0xf0) |
((hexval & 0xf) ? 0 : 0xf);
Upvotes: 3
Reputation: 395
You may have to go byte by byte, starting with the MSB. Check if the value is between 16^6 and 16^7 (assuming this is unsigned). If it is, add to the new number 0. If it's not, add to the new number 2^31+2^30+2^29+2^28.
See what I'm getting at?
Upvotes: 0