views:

628

answers:

6

I'm talking about this:

If we have the letter 'A' which is 77 in decimal and 4D in Hex. I am looking for the fastest way to get D.

I thought about two ways:

Given x is a byte.

  1. x << 4; x >> 4

  2. x %= 16

Any other ways? Which one is faster?

Thanks.

+4  A: 

Single AND operation can do it.

x = (x & 0x0F);
arul
+21  A: 

I always use x &= 0x0f

Terje Mikal
You beat me to it. I upvoted you over arul for brevity.
mdec
A: 

x = x & 15

Glenner003
mdec
I would advise to use hex notation when working with bit operations. Adds a lot of readability.
xtofl
May I should have, but Terje's answer beats mine in brevity as in clarity.
Glenner003
@mdec where n is a power of 2
Sekhat
down-voting this is a little harsh, I think...
Alnitak
I agree with Alnitak. We should upvote exceptionally good answers and downvote _wrong_ ones. Glenner's answer (although terse) wasn't wrong.
efotinis
+2  A: 

It will depend on on the architecture to some extent - shifting up and back down on an ARM is probably the fastest way - however the compiler should do that for you. In fact, all of the suggested methods will probably be optimized to the same code by the compiler.

MrZebra
Certain older CPUs can only shift a bit at a time and do not have variable or multiple shift. AFAIK, two shift operations is slower than a single AND operation on every CPU I have ever encountered.
Adisak
+32  A: 

Brevity is nice - explanations are better :)

  • x &= 0x0f

is, of course, the right answer. It exactly expresses the intent of what you're trying to achieve, and on any sane architecture will always compile down to the minimum number of instructions (i.e. 1). Do use hex rather than decimal whenever you put constants in a bit-wise operator.

  • x <<= 4; x >>= 4

will only work if your 'byte' is a proper unsigned type. If it was actually a signed char then the second operation might cause sign extension (i.e. your original bit 3 would then appear in bits 4-7 too).

without optimization this will of course take 2 instructions, but with GCC on OSX, even -O1 will reduce this to the first answer.

  • x %= 16

even without the optimizer enabled your compiler will almost certainly do the right thing here and turn that expensive div/mod operation into the first answer. However it can only do that for powers of two, and this paradigm doesn't make it quite so obvious what you're trying to achieve.

Alnitak
Very nice explanation of the inner workings and pitfalls of even such simple expressions.
Terje Mikal
You are right: explanations are better.
xtofl
"If it was actually a signed char then the second operation would cause sign extension" - not necessarily. Implementations are permitted to sign-fill, or to 0-fill when >> is used on a negative signed value.
Steve Jessop
ok - changed "would cause" to "might cause". BTW, I don't recall - would an unsigned char operand be promoted to an int for the right shift operator? If it were, that would also cause sign extension.
Alnitak
+9  A: 

There are many good answers and some of them are technically the right ones.

In a broader scale, one should understand that C/C++ is not an assembler. Programmer's job is to try to tell to the compiler the intention what you want to achieve. The compiler will pick the best way to do it depending on the architecture and various optimization flags.

x &= 0x0F; is the most clear way to tell the compiler what you want to achieve. If shifting up and down is faster on some architecture, it is the compiler's job to know it and do the right thing.

kauppi
Indeed! Let us care about the most readable code, let the compiler care about the fastest code.
xtofl
"to tell to the compiler the intention what you want to achieve" - hey - that's my line! :)
Alnitak