Extreme Efficiency for Odd/Even

F

Frederick Gotham

Skarmander posted:
You don't know and probably shouldn't care. Aside from that, you're on
the wrong level.


We have already achieved our objective -- we have a fool-proof method of
determing whether an integer is odd or even.

The objective here is different. The objective here is to perform the task
efficiently. If processing need be done to convert -5 to an unsigned
integer expression, then I _do_ care.

It's certainly better than the code you posted upthread for one's
complement machines, which can fail on -0 (and is less likely to be
optimized well). The moral of that story is to not construct clever
solutions for simple problems; you just end up with more problems.


Here's a verbatim quote from my original post:

| Yes, I realise that the smart thing would probably just
| be to write "x % 2" and forget about it, but this is
| more for kicks than anything else.
 
S

Skarmander

Frederick said:
Skarmander posted:



We have already achieved our objective -- we have a fool-proof method of
determing whether an integer is odd or even.
Multiple, in fact.
The objective here is different. The objective here is to perform the task
efficiently. If processing need be done to convert -5 to an unsigned
integer expression, then I _do_ care.
So your question is: "could people with experience on one's complement
machines tell me how the compilers they've used compile the expression
'(unsigned) x & 1', and in particular whether it involves generating
instructions for converting x to unsigned, and in particular how efficient
those instructions are"?

Fair enough.
Here's a verbatim quote from my original post:

| Yes, I realise that the smart thing would probably just
| be to write "x % 2" and forget about it, but this is
| more for kicks than anything else.
I get my kicks from spoiling your fun. I hate fun, you see. If programmers
had less fun hacking, I would have more fun maintaining programs.

So, don't mind if I *do* tell you every two paragraphs that you should be
spending your time on something else, even if this is terribly presuming.
Since you already know that the obvious solution is probably the most
appropriate one, you can just ignore me. (Except where I said that your
original elaborate solution is wrong, since that's actually true.)

S.
 
C

Clark S. Cox III

Frederick said:
posted:



That's C++ speak.

Actually no. Now that C has inline functions many of the arguments that
C++-ers have used against function macros for years now apply to C. I
would write those as inline functions and only switch to macros after
profiling shows that they are indeed slower.

This would take care of your double-evaluation problem in your
ones-compliment version.

#include <stdbool.h>

#define SIGNMAG 0
#define ONES 1
#define TWOS 2

#if -1 & 3 == 1
#define NUMSYS SIGNMAG
#elif -1 & 3 == 2
#define NUMSYS ONES
#else
#define NUMSYS TWOS
#endif

#if NUMSYS != ONES
/* Or maybe use uintmax_t instead of unsigned */
inline bool IsOdd(unsigned x) { return x & 1; }
inline bool IsEven(unsigned x) { return !(x & 1); }
#else
inline bool IsOdd(unsigned x) { return (x >= 0) == (x & 1); }
inline bool IsEven(unsigned x) { return (x >= 0) != (x & 1); }
#endif
 
M

Michal Nazarewicz

Clark S. Cox III said:
Actually no. Now that C has inline functions many of the arguments that
C++-ers have used against function macros for years now apply to C. I
would write those as inline functions and only switch to macros after
profiling shows that they are indeed slower.

Oh pleas... Even *if* macros are evil it doesn't mean *never* use
them. They are good for small subroutines such as IS_ODD/IS_EVEN.
 
C

Clark S. Cox III

Michal said:
Oh pleas... Even *if* macros are evil it doesn't mean *never* use
them. They are good for small subroutines such as IS_ODD/IS_EVEN.

Did I say to never use them? No. I did not. Please do not put words into
my mouth.
 
M

Michal Nazarewicz

Clark S. Cox III said:
Did I say to never use them? No. I did not. Please do not put words into
my mouth.

Not directly but saying IS_ODD/IS_EVEN should be made into inline
function sounds like "do note ever use macros 'cuz they're evil."
 
C

Clark S. Cox III

Michal said:
Not directly but saying IS_ODD/IS_EVEN should be made into inline
function sounds like "do note ever use macros 'cuz they're evil."

Whatever it sounds like to you, that is not what I said. Here is what I
said:

"Now that C has inline functions many of the arguments that
C++-ers have used against function macros for years now apply to C. I
would write those as inline functions and only switch to macros after
profiling shows that they are indeed slower."

Pay close attention to "I would..."; it has a very different meaning
than "You should always...". Also, pay close attention to "switch to
macros after profiling shows that they are indeed slower."
 
K

Keith Thompson

Clark S. Cox III said:
Actually no. Now that C has inline functions many of the arguments that
C++-ers have used against function macros for years now apply to C. I
would write those as inline functions and only switch to macros after
profiling shows that they are indeed slower.

Many, but not all. For one thing, few C compilers fully support the
C99 standard; C90 doesn't have inline functions.
 
C

Clark S. Cox III

Keith said:
Many, but not all. For one thing, few C compilers fully support the
C99 standard; C90 doesn't have inline functions.

True, but of the parts of C99 that *are* implemented, I'd imagine that
"inline" is one of the most common.

Of course, YMMV.
 
D

dcorbit

Michal said:
Not directly but saying IS_ODD/IS_EVEN should be made into inline
function sounds like "do note ever use macros 'cuz they're evil."

Using macros as functions is a very bad idea. There is no type
checking performed at all. Sometimes you will get an error message as
a side effect (e.g. in the IS_ODD() macro a double or pointer would
object to the & operator ... but you might also have a macro that
increments which would work willy-nilly on pointers, doubles, ints,
etc.). Macros can be redefined to something else.

They have all sorts of evil side effects. Using macros as functions is
the product of a lazy mind -- {ironically} hard at work doing as little
thinking as possible.

See (for instance):
http://www.thescripts.com/forum/thread62551.html

That having been said, I do it myself -- once in a while.

Macros are useful -- for instance -- for conditional compiling or
creating idempotent headers. But function macros are bug engines of
the worst kind.
 
M

Michal Nazarewicz

Clark S. Cox III said:
"Now that C has inline functions many of the arguments that
C++-ers have used against function macros for years now apply to C. I
would write those as inline functions and only switch to macros after
profiling shows that they are indeed slower."

Do you really think a sequence which involves two instructions (namely
'%'/'&' and '=='/'!=') is worth that effort? The fact that macros are
evil doesn't mean one should do ridiculous things.
 
M

Michal Nazarewicz

Using macros as functions is a very bad idea. There is no type
checking performed at all. Sometimes you will get an error message as
a side effect (e.g. in the IS_ODD() macro a double or pointer would
object to the & operator ... but you might also have a macro that
increments which would work willy-nilly on pointers, doubles, ints,
etc.). Macros can be redefined to something else.

I'm not saying macros ain't evil but C gives you a lot of
opportunities to shoot yourself in your leg and still macros make live
easier in some situations and if someone really wants IS_ODD/IS_EVEN
then defining those as macros is probably one of such situations.
 
C

Chris Dollin

Michal said:
Do you really think a sequence which involves two instructions (namely
'%'/'&' and '=='/'!=') is worth that effort?

It's not significantly more effort to write an inline function than
it is to write the corresponding function macro.

(It's even less effort to write a non-inline function for the same
thing.)
 
D

dcorbit

Chris said:
It's not significantly more effort to write an inline function than
it is to write the corresponding function macro.

And that function will have type checking and also be immune to evil
macro side effects.
Using macros for functions is both lazy and stupid. Of course, I have
admitted that I do it from time to time {what does that say about
me...}
(It's even less effort to write a non-inline function for the same
thing.)

Which most compilers will inline if you ask them to (and in a way that
is smarter than you, for the most part).

/* Some people might even be surprised by the output of this: */
#define square(x) ((x)*(x))
#define even(x) ((((x)>>1)<<1) == (x))

#include <stdio.h>
int main(void)
{
long long ll = 217;
long l = 19;
int i = 2;
char c = 8;

if (even(square(++c)))
puts("square of 8+1 is even");
else
puts("square of 8+1 is odd");

if (even(square(++i)))
puts("square of 2+1 is even");
else
puts("square of 2+1 is odd");

if (even(square(++l)))
puts("square of 19+1 is even");
else
puts("square of 19+1 is odd");

if (even(square(++ll)))
puts("square of 217+1 is even");
else
puts("square of 217+1 is odd");

ll = 217;
l = 19;
i = 2;
c = 8;

printf("218 squared = %.0f\n", (double) square(++ll));
printf("20 squared = %.0f\n", (double) square(++l));
printf("3 squared = %.0f\n", (double) square(++i));
printf("9 squared = %.0f\n", (double) square(++c));

ll = 217;
l = 19;
i = 2;
c = 8;

if (even(++ll))
puts("218 is even");
else
puts("218 is odd");

if (even(++ll))
puts("20 is even");
else
puts("20 is odd");

if (even(++ll))
puts("3 is even");
else
puts("3 is odd");

if (even(++ll))
puts("9 is even");
else
puts("9 is odd");

return 0;
}
/*
dcorbit@DCORBIT64 /c/tmp
$ gcc -Wall -ansi -pedantic t.c
t.c: In function 'main':
t.c:7: warning: ISO C90 does not support 'long long'
t.c:37: warning: operation on 'll' may be undefined
t.c:38: warning: operation on 'l' may be undefined
t.c:39: warning: operation on 'i' may be undefined
t.c:40: warning: operation on 'c' may be undefined

dcorbit@DCORBIT64 /c/tmp
$ ./a
square of 8+1 is odd
square of 2+1 is odd
square of 19+1 is odd
square of 217+1 is odd
218 squared = 47961
20 squared = 441
3 squared = 16
9 squared = 90
218 is odd
20 is odd
3 is odd
9 is odd

dcorbit@DCORBIT64 /c/tmp
$
*/

Of course, nasal demons are another possible output.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,144
Latest member
KetoBaseReviews
Top