Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Binary set - how to calculate offset?

Reply
Thread Tools

Binary set - how to calculate offset?

 
 
A. Farber
Guest
Posts: n/a
 
      05-04-2007
Hello C programmers,

I have a small web game with the server part written in C
which runs on OpenBSD (Linux and Cygwin work too).

I've found out, that for me it's most comfortable to
make the different player states to be of power of 2:

typedef enum user_phase {
CONNECTING = 0,
CHAT_LOBBY = 1,
CHAT_TABLE = 2,
KIBITZING = 4,
BIDDING_1 = 8,
TAKING_TALON_1 = 16,
TAKING_TALON_2 = 32,
DISCARDING_1 = 64,
DISCARDING_2 = 128,
DECLARING = 256,
BIDDING_2 = 512,
ALL_PASSED = 1024,
PLAYING = 2048,
PHASE_MAX = 4096
} user_phase;

/* all phases from above except CONNECTING */
#define ALL_PHASES ((uint32_t) 0xFFFFFFFF)

That way I can check quickly for several phases
at once, for example here in event handling table:

static const EVENT_ENTRY EVENT_TABLE[] = {
/* valid phases args table turn */
{ ALL_PHASES, NO, ANY, ANY, handle_alive },
{ ALL_PHASES, YES, ANY, ANY, handle_chat },
{ ALL_PHASES ^ KIBITZING, NO, ANY, NO, handle_kuku },
{ CHAT_LOBBY, YES, NO, ANY, handle_join },
{ ALL_PHASES ^ CHAT_LOBBY, NO, YES, ANY, handle_lobby },
{ BIDDING_1 | BIDDING_2, YES, YES, YES, handle_bid },
{ ALL_PASSED | PLAYING, YES, YES, YES, handle_card }
};

However my problem is to perform the backward
mapping: given a user_phase, how do I found out,
which power of 2 is it (sorry for my awkward language)?

For example here how I find phase names currently:

static const char* PHASE_NAMES[] = {
"CONNECTING",
"CHAT_LOBBY",
"CHAT_TABLE",
"KIBITZING",
"BIDDING_1",
"TAKING_TALON_1",
"TAKING_TALON_2",
"DISCARDING_1",
"DISCARDING_2",
"DECLARING",
"BIDDING_2",
"ALL_PASSED",
"PLAYING"
};

const char*
phase_name(user_phase phase)
{
unsigned i;

for (i = 0; i < sizeof(PHASE_NAMES) / sizeof(char*); i++)
if ((uint32_t)(1 << i) == phase)
return PHASE_NAMES[i];

return "UNKNOWN";
}

Is there a better way maybe?

Thank you
Alex

 
Reply With Quote
 
 
 
 
Eric Sosman
Guest
Posts: n/a
 
      05-04-2007
A. Farber wrote On 05/04/07 10:26,:
> [...]
>
> However my problem is to perform the backward
> mapping: given a user_phase, how do I found out,
> which power of 2 is it (sorry for my awkward language)?


(The snipped material makes clear that user_phase
is an enum value equal to a positive integral power of 2.)

Stripped to its essentials, you are looking for the
binary logarithm of a value. There are many ways to do
this, some of which are described at

http://graphics.stanford.edu/~seander/bithacks.html

WARNING: Some of the hacks on this page rely on non-portable
assumptions, not always mentioned explicitly. Be alert!
Also, the claims about operation count, branch counts, and
so on are strongly platform-dependent.

--
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
 
Old Wolf
Guest
Posts: n/a
 
      05-06-2007
On May 5, 2:26 am, "A. Farber" <(E-Mail Removed)> wrote:
> I've found out, that for me it's most comfortable to
> make the different player states to be of power of 2:
>
> typedef enum user_phase {
> CONNECTING = 0,
> CHAT_LOBBY = 1,
> CHAT_TABLE = 2,

[...]
> PLAYING = 2048,
> PHASE_MAX = 4096


I find it is clearer to use hexadecimal constants in this
situation; it also helps to reduce typoes, sign, and
out-of-range constant problems.

> /* all phases from above except CONNECTING */
> #define ALL_PHASES ((uint32_t) 0xFFFFFFFF)


What is the purpose of that cast?

NB. 0xFFFFFFFF is already an unsigned int (unless you
are on a system where int is less than 32 bits, in which
the code is still correct but it will be a long or an unsigned
long).

> That way I can check quickly for several phases
> at once, for example here in event handling table:
>
> static const EVENT_ENTRY EVENT_TABLE[] = {


A minor point; uppercase identifiers starting with E are
reserved for implementation use whenever <errno.h> is
included. Suppose you were coding on an embedded
air conditioning system, the system vendor might have
defined an error condition where the entry to an air vent
was malfunctioning: E VENT_ENTRY !

> /* valid phases args table turn */


> { CHAT_LOBBY, YES, NO, ANY, handle_join },
> { ALL_PHASES ^ CHAT_LOBBY, NO, YES, ANY, handle_lobby },
> { BIDDING_1 | BIDDING_2, YES, YES, YES, handle_bid },
> { ALL_PASSED | PLAYING, YES, YES, YES, handle_card }
>
> However my problem is to perform the backward
> mapping: given a user_phase, how do I found out,
> which power of 2 is it (sorry for my awkward language)?


They way I do such things is (note, I like to always
prefix my enums to avoid unexpected clashes and
avoid causing undefind behaviour if one starts with E):

enum
{ PHASE_NONE
, PHASE_FOO
, PHASE_BAR
, PHASE_QUX
, NUM_PHASES
};

char const *phase_names[] =
{ "(none)"
, "foo"
, "bar"
, "qux"
};

STATIC_ASSERT( NUM_PHASES == dimof(phase_names) );

Note, this can be hard to keep in sync if the tables are
large. So it is possible to combine those two into one file, eg.
MAGIC( PHASE_FOO, "foo" )
MAGIC( PHASE_BAR, "bar" )
and then include this file in both your .h and .c files but
with MAGIC defined to produce the enum if it is a .h, and
produce the string table if it is a .c .

For the flags table, assuming your goal is compactness:
#define FT(X) P_##X = 1UL << PHASE_##X
enum
{ FT(FOO)
, FT(BAR)
, FT(QUX)
};
#undef FT

then the table will look like:
{ P_ALL_PASSED | P_PLAYING, YES, YES, YES, handle_card }
etc.


 
Reply With Quote
 
David Thompson
Guest
Posts: n/a
 
      05-21-2007
On 6 May 2007 16:03:28 -0700, Old Wolf <(E-Mail Removed)> wrote:
<snip>
> > #define ALL_PHASES ((uint32_t) 0xFFFFFFFF)


> NB. 0xFFFFFFFF is already an unsigned int (unless you
> are on a system where int is less than 32 bits, in which
> the code is still correct but it will be a long or an unsigned
> long).
>

Or int is more than 32 (nonpadding) bits in which case that fits in,
and is, signed int. (Although it would then safely promote to unsigned
int where needed in an expression, which is probably enough.)

> enum
> { PHASE_NONE
> , PHASE_FOO
> , PHASE_BAR
> , PHASE_QUX


BTW the canonical metaname is quux with two u's. Not to be confused
with two yous, two ewes, you toos, U-2s, yoohoos, tutus, or youse. <G>

- formerly david.thompson1 || achar(64) || worldnet.att.net
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
(8-bit binary to two digit bcd) or (8-bit binary to two digit seven segment) Fangs VHDL 3 10-26-2008 06:41 AM
Calculate sha1 hash of a binary file LaundroMat Python 7 08-07-2008 03:24 PM
A 64-bit binary returning a value to a 32-bit binary? spammenotplui31@yahoo.ca C Programming 12 04-08-2007 07:02 AM
Re: ostreams, ios::binary, endian, mixed binary-ascii Marc Schellens C++ 8 07-15-2003 12:27 PM



Advertisments