Macro that test BCDness evaluating its argument only once

F

Francois Grieu

This macro returns 1 if the low 8 bits of x form a valid BCD value,
and 0 otherwise.

#define VALIDBCD(x) (((x)&0x0F)<0x0A && ((x)&0xF0)<0xA0)

How do you rewrite it so that it evaluates its argument only once,
requires no temp variable or table, and is fully C99 compliant?

My shortest solution uses 3 constants, and beats the original
hands off in term of performance on my desktop CPU.
I wish my C compilers would know this kind of optimization.


François Grieu
 
T

Thad Smith

Francois said:
This macro returns 1 if the low 8 bits of x form a valid BCD value,
and 0 otherwise.

#define VALIDBCD(x) (((x)&0x0F)<0x0A && ((x)&0xF0)<0xA0)

How do you rewrite it so that it evaluates its argument only once,
requires no temp variable or table, and is fully C99 compliant?

Here's one way:

#define VALBCD(x) !((((((x)&0xff)*0x201)&0x1ef0)+0xc60)&0x2100)
My shortest solution uses 3 constants, and beats the original
hands off in term of performance on my desktop CPU.

You got me beat! I'd be interested in seeing your version.
 
T

Thad Smith

Francois said:
This macro returns 1 if the low 8 bits of x form a valid BCD value,
and 0 otherwise.

#define VALIDBCD(x) (((x)&0x0F)<0x0A && ((x)&0xF0)<0xA0)

How do you rewrite it so that it evaluates its argument only once,
requires no temp variable or table, and is fully C99 compliant?

Just after posting, I realized that the lsb of each digit isn't needed, so

#define VALIDBCD(x) !((((x)&0xee)+0x66)&0x110)
 
F

Francois Grieu

Thad Smith said:
#define VALIDBCD(x) !((((x)&0xee)+0x66)&0x110)

Yes, that's the best I could find in term of number of constants and
operators.
If the code is to run on an 8-bit machine, this likely is more efficient:
#define VALIDBCD(x) !((((x)>>1&0x77)+0x33)&0x88)

Rather amazingly, even when sizeof(x) is 2, my usual embedded C
compiler (Metrowerks) needs no explicit cast to unsigned char
to make this generate a perfect stream of single-byte arithmetic/logic
operations.

Francois Grieu
 
T

Thad Smith

Francois said:
>
If the code is to run on an 8-bit machine, this likely is more efficient:
#define VALIDBCD(x) !((((x)>>1&0x77)+0x33)&0x88)

Good point.
Rather amazingly, even when sizeof(x) is 2, my usual embedded C
compiler (Metrowerks) needs no explicit cast to unsigned char
to make this generate a perfect stream of single-byte arithmetic/logic
operations.

I'm not surprised. On an 8-bit machine it pays to know when the
calculations can be done properly with a single byte. The shift and
both AND operators ensure that. The biggest test is knowing that the
sum with 0x33 gets truncated to 8 bits in the following operation so
that the upper byte isn't needed.
 

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,995
Messages
2,570,230
Members
46,817
Latest member
DicWeils

Latest Threads

Top