Two weeks ago, I set a quiz. I listed four ways to write some code, which was supposed to divide an unsigned integer by 8. I commented that the priority was for the code to be as fast as possible and asked which of my lines of C was most efficient.
I was pleased with the response and acknowledge contributions from Peter Bushell, Dan S, Ken Simone, Krzysztof Wesołowski, Lee Riemenschneider, and Shaun Shippey. Between them, they picked up all the points that I had in mind and raised at least one more …
The key point was that I wanted efficient code and I wanted fast code. These are not the same thing.
Fast code is clear enough – we need to carry out the operation in as few machine instructions as possible. The fastest way to divide by 8 is to shift right by three bits. However, any reasonable compiler would optimize the code to do that, even if you expressed your wishes using a divide operator. If you find your compiler does not perform that optimization, it is time for a new compiler!
But what is efficient code? This can be answered by considering the priorities. Software engineering time is expensive. Very little of it is spent coding. Most is expended debugging and maintaining code. This implies [to me anyway] that the most “efficient” code is that which can be read and understood most easily. Most of the time a compiler will also render the fastest [or smallest, depending upon optimization settings] result from the code that is written most clearly. As one contributor put it: “write your code for human beings, and let the compiler do its job”.
So this points to the best options being one of:
x /= 8;
x = x / 8;
as these both unambiguously specify that a division is required.
Although I am personally very comfortable with the /= operator, as I have been writing C half my life, I have a feeling that the other form is actually clearer. It says “Take the value of x, divide it by 8 and put the result back into x” which precisely specifies what is required.
One concern, raised by a contributor, was my use of explicit constants. Should I have used #define constants or enums instead? Of course, it is only the 8 that is really of concern, as we have dismissed the use of explicit shift. The decision as to whether this should be a symbol depends on the details of the application. If it is something truly fixed – like the number of sides of an octagon, for example – then I think that an explicit value is OK and defining NUMBER_OF_SIDES_OF_AN_OCTAGON would be overkill. However, if it is a value that might potentially be subject to change, like BITS_IN_A_BYTE, maybe a symbol would be prudent. I guess a rule could be: only parameterize things that could conceivably need to change. However, I would agree that sometimes there is a readability issue. Maybe explicit constants should only be used where the significance of their value is obvious. Of course, “obvious” to one person might be “obscure” to another …
Who would have thought that such a small snippet of code could provoke so much discussion? Thanks everyone for your input. I am very open to suggestions for other language constructs that may be worthy of discussion – comments or email please.