[comp.lang.c] Binary Constants: FOLLOWUP

jfriedl@frf.omron.co.jp (Jfriedl) (11/25/89)

Two weeks ago I posted a question about how to effect binary
constants, as in the fictitious:
	case 0b110011:	/* "bsr.n" opcode */

I had a macro that allowed
	case B(110011):	/* "bsr.n" opcode */
The macro,
    #define B(N)                             (	\
        ((1==(((2 ## N)         )%10))   ) |	\
        ((1==(((2 ## N)/10      )%10))<<1) |	\
        ((1==(((2 ## N)/100     )%10))<<2) |	\
        ((1==(((2 ## N)/1000    )%10))<<3) |	\
        ((1==(((2 ## N)/10000   )%10))<<4) |	\
        ((1==(((2 ## N)/100000  )%10))<<5) |	\
        ((1==(((2 ## N)/1000000 )%10))<<6) |	\
        ((1==(((2 ## N)/10000000)%10))<<7)   )

allows binary constants up to 8 digits long, but looks horrible.

From the non-net responses:
	A number of people suggested that a preprocessor
could be easily written.  [easy enough, but I'd rather not
have to do this].

	However, one response, reprinted here (without permission --
hope it's ok), from uunet!peregrine.COM!dmi (Dean Inada) :
> Hah!
> Inspired, I find:
> 
> #define D(N)	(2 ## N)
> #define DTOB(N)	((N)%8 + (N)/125%64 + ((N)/15625%512&0700))
> #define B(N)	DTOB(D(N))
> 
> Encouraged, I go on;
> 
> #define H(N)	(0x ## N)
> #define HTOB(N)	(\
> 	((\
> 		((\
> 			((\
> 				(N)\
> 			*0x15)&0x21221881)%0xffff%0x1ff\
> 		*0x1001)&0x9216d)%0x1ff\
> 	*0x201)&c200ff)%0x7ff\
> )/*note: evaluates arg only once*/
> 
> #define B(N)	HTOB(H(N))
> 
> Whew, I think I'll let someone else simplify this, and/or work on OtoB.

Inspired, I'd say.  Having absolutely NO clue to the above, I asked for
the derivation (which, as it turns out, I didn't understand either).
It's somewhat long, but if you want it, let me know and I'll pass it
along.

Anyway, it did give me the idea to come up with:
    #ifdef __STDC__
    #    define _FORCE_OCTAL(num)   0##num##U
    #else
    #    define _FORCE_OCTAL(num)   (0/**/num) /* well, it's worth a try */
    #endif

    #define _CONV_O2B_(N)              \
	    ((N & 000000000001U)       \
	    |(N & 000000000010U)>>002  \
	    |(N & 000000000100U)>>004  \
	    |(N & 000000001000U)>>006  \
	    |(N & 000000010000U)>>010  \
	    |(N & 000000100000U)>>012  \
	    |(N & 000001000000U)>>014  \
	    |(N & 000010000000U)>>016  \
	    |(N & 000100000000U)>>020  \
	    |(N & 001000000000U)>>022  \
	    |(N & 010000000000U)>>024)
    #define B(Num)  _CONV_O2B_(_FORCE_OCTAL(Num))

which has the benefit of allowing up to 11 bits.
It's really much more natural than converting from decimal --
thanks Dean, for forging the path.  I still wish, though,
that I could understand your derivation!

This new macro, above, would be much more compact if C had an operator
which meant "fold bits, keeping every third bit".  Mmmm, maybe
if we sue..... (-:

On the net, there were a lot of people wishing that XJ311
had allowed stuff like 0b[01]+, but, apparently (from an
apparent XJ311 member), it would have been just "nice" to have.
Like it's also "nice" to have "for", "while", etc, rather than
having to use "goto", eh? Maybe not so dramatic but
    0b[01]+	{yylval.i = atob(yytext+2); return INTEGER;}
is pretty not-so-dramatic too.  Sheesh.

Oh, and one more response.
It was pointed out that I misspelled "wretched".
	*jeff*

NB:
  I'm going to be in The States for the next month on business.
  [It'll be *GREAT* to have a cup of coffee for less than $3!]
  Mail will follow me, but news won't, so please mail comments and flames.
  Heck, I get so little mail, "yes | mail jeff" would even be appreciated.
  Well, maybe not, but you get the idea..... (-:

-----------------------------------------------------------------------------
Jeffrey Eric Francis Friedl                             jfriedl@nff.ncl.omron
Omron Tateisi Electronics, Dept. OE                         Nagaokakyo, Japan
Fax: 011-81-75-955-2442                        Phone: 011-81-75-951-5111 x154
direct path from UUNET:                             ...!uunet!othello!jfriedl

dmi@peregrine.peregrine.com (Dean Inada) (11/26/89)

In article <308@frf.omron.co.jp> jfriedl@frf.omron.co.jp (Jfriedl) writes:
>Two weeks ago I posted a question about how to effect binary
>constants, as in the fictitious:
>	case 0b110011:	/* "bsr.n" opcode */
...
>	However, one response, reprinted here (without permission --
>hope it's ok), from uunet!peregrine.COM!dmi (Dean Inada) :
>> #define DTOB(N)	((N)%8 + (N)/125%64 + ((N)/15625%512&0700))
                                                        ^^^^
Note that the %512 is superfluous here. 

Or,
#define DTOB(N)	((N)*9/5%16 + ((N)*9/3125&0xf0))

Can anyone reduce this to one eval of (N)?

>> #define H(N)	(0x ## N)
>> #define HTOB(N)	(\
>> 	((\
>> 		((\
>> 			((\
>> 				(N)\
>> 			*0x15)&0x21221881)%0xffff%0x1ff\
>> 		*0x1001)&0x9216d)%0x1ff\
>> 	*0x201)&c200ff)%0x7ff\
>> )/*note: evaluates arg only once*/
>
>Inspired, I'd say.  Having absolutely NO clue to the above, I asked for
>the derivation (which, as it turns out, I didn't understand either).
You might try tracing the intermediate values for
0x1, 0x10, 0x100, ... ,0x10000000

>It's somewhat long, but if you want it, let me know and I'll pass it
>along.
If you do pass it along, let me know where.

>This new macro, above, would be much more compact if C had an operator
>which meant "fold bits, keeping every third bit".  Mmmm, maybe
>if we sue..... (-:

Picking up the gauntlet:  -)
#define _CONV_O2B(N)	(\
	(((((\
 	(N)%01777	/* 100001 */\
 	*04000001&050001545)%03777	/* 100011 */\
	*04000001&010420001443)%07777	/* 100111 */\
	*010001&030000547)%0777	/*   111111 */\
	*02001&0200477)%0777	/* 10111111 */\
	*0401&0200277)%01777	/* 11111111 */\
)

Only 8 bits worth, and no effort to optimize like the hex version,
but that didn't get very far anyway.  Anyone else care to try?