Macro that test BCDness evaluating its argument only once

Discussion in 'C Programming' started by Francois Grieu, Jan 18, 2007.

  1. 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
    Francois Grieu, Jan 18, 2007
    #1
    1. Advertising

  2. Francois Grieu

    Thad Smith Guest

    Francois Grieu wrote:
    > 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.

    --
    Thad
    Thad Smith, Jan 20, 2007
    #2
    1. Advertising

  3. Francois Grieu

    Thad Smith Guest

    Francois Grieu wrote:
    > 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)

    --
    Thad
    Thad Smith, Jan 20, 2007
    #3
  4. In article <45b1ab9a$0$58034$>,
    Thad Smith <> wrote:

    > Francois Grieu wrote:
    > > 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?

    >
    > #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
    Francois Grieu, Jan 20, 2007
    #4
  5. Francois Grieu

    Thad Smith Guest

    Francois Grieu wrote:
    > In article <45b1ab9a$0$58034$>,
    > Thad Smith <> wrote:
    >
    >
    >>Francois Grieu wrote:
    >>
    >>>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?

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

    >
    > 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.

    --
    Thad
    Thad Smith, Jan 20, 2007
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Francois Grieu

    Reformulating a macro to use argument just once

    Francois Grieu, Jan 16, 2007, in forum: C Programming
    Replies:
    17
    Views:
    471
    ais523
    Jan 19, 2007
  2. Francois Grieu

    Reformulating a macro to use argument just once

    Francois Grieu, Jan 16, 2007, in forum: C Programming
    Replies:
    9
    Views:
    307
    Eric Sosman
    Jan 17, 2007
  3. Chris Angelico
    Replies:
    0
    Views:
    290
    Chris Angelico
    May 6, 2011
  4. thunk
    Replies:
    1
    Views:
    292
    thunk
    Mar 30, 2010
  5. thunk
    Replies:
    0
    Views:
    454
    thunk
    Apr 1, 2010
Loading...

Share This Page