[comp.lang.c] Playing with the bits of floats

max@george.lbl.gov (Max Rible) (01/14/89)

I'm trying to do deal with floating point numbers as if they're ints.
Things like "if(((3.1 - 3.14) & 0x7FFFFFF) <= 0.1)"--- lousy
programming style, I know, but I'm interested in speed, not
portability for this application.  (On a Sun, if C blithely masked out
the low bits, that would strip the sign bit.)  Also tests like
if((3.1 - 3.14) & 0x80000000) might be faster than 
if((3.1 - 3.14) < 0.0) ; I'd like to know if there's any dirty
trick that would permit this sort of action.  (I agree that it
shouldn't be an easy dirty trick, but I'd certainly like for it 
to be possible without adding any extra instructions for conversion!)
Reply to max@csam.lbl.gov and I'll summarise.  Thank you.
							Max

--
/----------------------------------v------------------------------------------\
| Max Rible, Computer Graphics Lab | "I have a very firm grasp on reality!  I |
| Lawrence Berkeley Laboratories   | can reach out and strangle it any time!" |
| ARPA:  max@csam.lbl.gov          |UUCP: {ames!ucbcad,ucbvax}!cartan!csam!max|
\----------------------------------^------------------------------------------/

bright@Data-IO.COM (Walter Bright) (01/17/89)

In article <MAX.89Jan13163256@george.lbl.gov> max@george.lbl.gov (Max Rible) writes:
>I'm trying to do deal with floating point numbers as if they're ints.
>Things like "if(((3.1 - 3.14) & 0x7FFFFFF) <= 0.1)"--- lousy
>programming style, I know, but I'm interested in speed, not
>portability for this application.

Two ways to do it:
	1. Define a union such as:
		typedef union
		{	double d;
			unsigned short u[4];
		} dblunion;
	   Assign values into d, and do the bit testing with u.
	2. Try this:
		double d;
		d = expression;
		if (*(unsigned short *)&d & 0x1234)
			...
I've generally used method 2. I know it violates all notions of
portability, but it was for very specific hardware! Using method
1 sometimes implies passing/returning unions to functions, which
is inefficiently implemented in a lot of compilers.

Unless your compiler supports something like (dblunion)(1.2) as
a 'type paint', I see no way to do this without going through a
memory location.

cik@l.cc.purdue.edu (Herman Rubin) (01/17/89)

In article <1825@dataio.Data-IO.COM>, bright@Data-IO.COM (Walter Bright) writes:
> In article <MAX.89Jan13163256@george.lbl.gov> max@george.lbl.gov (Max Rible) writes:
> >I'm trying to do deal with floating point numbers as if they're ints.
< <Things like "if(((3.1 - 3.14) & 0x7FFFFFF) <= 0.1)"--- lousy
< <programming style, I know, but I'm interested in speed, not
< <portability for this application.
> 
> Two ways to do it:
> 	1. Define a union such as:
> 		typedef union
> 		{	double d;
> 			unsigned short u[4];
> 		} dblunion;
> 	   Assign values into d, and do the bit testing with u.
> 	2. Try this:
> 		double d;
> 		d = expression;
> 		if (*(unsigned short *)&d & 0x1234)
> 			...
> I've generally used method 2. I know it violates all notions of
> portability, but it was for very specific hardware! Using method
> 1 sometimes implies passing/returning unions to functions, which
> is inefficiently implemented in a lot of compilers.
> 
> Unless your compiler supports something like (dblunion)(1.2) as
> a 'type paint', I see no way to do this without going through a
> memory location.

This is the sort of lack on the part of languages and compilers which
should not exist.  If the combination (language + compiler) allows
register unions (there are some) and register arrays (I do not know
of any), the following

 	1. Define a union such as:
 		typedef union
 		{	double d;
 			unsigned long u[2];
 		} dblunion;

would work.  The alternative is to use the clumsy assembly language
and even clumsier asm pseudo-function in C.  Even this can give
problems if the register variables in asm lines must be explicitly given,
rather than assigned by the compiler; in that case (which is what I have
to contend with), produce the assembler code with -S and edit it.

I agree that every language should make it easy for the knowledgeable
programmer to do these things, but I am afraid the movement is in the
opposite direction.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/18/89)

In article <1096@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>> In article <MAX.89Jan13163256@george.lbl.gov> max@george.lbl.gov (Max Rible) writes:
>> >I'm trying to do deal with floating point numbers as if they're ints.
>< <Things like "if(((3.1 - 3.14) & 0x7FFFFFF) <= 0.1)"--- lousy
>< <programming style, I know, but I'm interested in speed, not
>< <portability for this application.
>I agree that every language should make it easy for the knowledgeable
>programmer to do these things, but I am afraid the movement is in the
>opposite direction.

I utterly disagree.  Generating efficient code for routine floating-point
operations is the job of the compiler, not the high-level programmer.
There is no reason why, if the suggested replacement test represents the
most efficient code for the test, that the compiler should not generate
it in the first place.

There are a few cases, such as dealing with IEEE-754 NaNs, where bit
patterns are necessary.  C vendors on such systems have, quite properly,
provided the necessary support as macros or functions, so the programmer
still need not concern himself with bit-twiddling.

mrm%puffin@Sun.COM (Marianne Mueller) (01/18/89)

Various people have been recommending things like

> 	  Define a union such as:
> 		typedef union
> 		{	double d;
> 			unsigned long u[2];
> 		} dblunion;
>

to let a programmer access/manipulate bits directly.

You might want to make sure that your machine doesn't penalize you on
caching.  Some machines cache only floating point values, and opt not
to cache things that have a union type.  (I think it was the compiler
that forced main memory loads/stores, not the hardware.) 

I once thought I was speeding up my program by using union types, but
it turned out I slowed it down significantly!

cik@l.cc.purdue.edu (Herman Rubin) (01/18/89)

In article <9404@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
> In article <1096@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> >> In article <MAX.89Jan13163256@george.lbl.gov> max@george.lbl.gov (Max Rible) writes:
> >> >I'm trying to do deal with floating point numbers as if they're ints.
> >< <Things like "if(((3.1 - 3.14) & 0x7FFFFFF) <= 0.1)"--- lousy
> >< <programming style, I know, but I'm interested in speed, not
> >< <portability for this application.
> >I agree that every language should make it easy for the knowledgeable
> >programmer to do these things, but I am afraid the movement is in the
> >opposite direction.
> 
> I utterly disagree.  Generating efficient code for routine floating-point
> operations is the job of the compiler, not the high-level programmer.
> There is no reason why, if the suggested replacement test represents the
> most efficient code for the test, that the compiler should not generate
> it in the first place.

Clearly the compiler writers and language designers did not think that the
operations Max wants to use are routine.  I am not even sure that Max thinks
they are routine, but he wants to use them.  I find myself in this position
often, and I have so stated.  There are routine operations on both bit patterns
and floating-point numbers which are not in many languages; remember the
discussion in this group about the power OPERATOR.

Also, the particular situation may be highly non-portable.  Note that Max 
has stated that he wants speed, and not necessarily portability.

> There are a few cases, such as dealing with IEEE-754 NaNs, where bit
> patterns are necessary.  C vendors on such systems have, quite properly,
> provided the necessary support as macros or functions, so the programmer
> still need not concern himself with bit-twiddling.

Macros can be so clumsy as to be almost useless.  I do not see how to treat
a double float in registers as a pair of integers by anything provided in 
the C language.  Function calls can be quite slow, and usually are, and can
even take more space than inlining.  As I see the application cited, the
cost of the procedure inlined is less than the cost of moving the arguments
for processing by the function and moving the result back.

Max wants to do in one or two instructions what the has not been provided
for in the language.  As I read Doug's remarks, he feels that this is
inappropriate.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/19/89)

In article <1100@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>Max wants to do in one or two instructions what the has not been provided
>for in the language.  As I read Doug's remarks, he feels that this is
>inappropriate.

I sure do.  The actual test desired is merely some sort of tolerance
test.  When written in the usual way, a compiler should produce very
good code for the test.  Resorting to bit-twiddling not only should
not produce a noticeable increase in overall program speed, but it
will certainly degrade the reliability, portability, and
maintainability of the program.

As usual, Mr. Rubin maintains that high-level languages like C should
allow him to do everything he can do in assembler, and as usual most
software engineers I know of would disagree.  I don't know how long
it would take to port his, or other detailed bit-twiddling code, to
a new environment, but I do know how long it takes to port mine
(close to zero time).  This frees up my time for other things such as
working on new applications.  I have trouble imagining why that is
not an equally important criterion for others.  Do they really LIKE
to bit twiddle instead of work on new projects?

rjchen@phoenix.Princeton.EDU (Raymond Juimong Chen) (01/19/89)

[as is my wont, I put quoted material at the END.]

Harumph.  To emphasize that the code is inherently non-portable, why
not just code the test in question in assembly language?  This would
certainly point out to anyone trying to (heaven forbid!) port the code
that something amiss is up.  (I mean, the code is so blatantly non-portable,
one wonders how one could possibly code it in a language which was designed
with portability in mind.)

There seems to be this great movement to make C the One True Programming
Language That Lets You Do Anything You Want.  I don't think it is.
If you want to get ``under the hood'' and play dirty tricks, then
use assembly language.

And for those of you who missed last week's episode...

Max Rible wants to treat a float as an int-like bit pattern.  ``I'm 
interested in speed, not portability.''

Herman Rubin agrees that ``every language should make it easy for the 
knowledgeable programmer to do these things.''

Doug Gwyn disagress, maintaining that ``Generating efficient code for 
routine floating-point operations of the job of the compiler, not 
the high-level programmer.''

Herman Rubin concedes that ``the particular situation may be highly non-
portable.  Note that Max has stated that he wants speed, and not necessarily 
portability.''
-- 
Raymond Chen	UUCP: ...allegra!princeton!{phoenix|pucc}!rjchen
		BITNET: rjchen@phoenix.UUCP, rjchen@pucc
		ARPA: rjchen@phoenix.PRINCETON.EDU, rjchen@pucc.PRINCETON.EDU
"Say something, please!  ('Yes' would be best.)" - The Doctor

bga@bgalli.UUCP (Billy G. Allie) (01/21/89)

In article <5586@phoenix.Princeton.EDU>, rjchen@phoenix.Princeton.EDU (Raymond Juimong Chen) writes:
> Harumph.  To emphasize that the code is inherently non-portable, why
> not just code the test in question in assembly language?  This would
> certainly point out to anyone trying to (heaven forbid!) port the code
> that something amiss is up.

I DO NOT LIKE coding in assembly language and will only do so if there is
no other way to code it.  As for pointing out to anyone that the code is
non-portable, what's wrong with:

	<non-portable construct>	/* NON-PORTABLE */

Useful comments are meant to be included in your programs, and a comment
stating that a particular construct is non-portable is definately useful.

>                              (I mean, the code is so blatantly non-portable,
> one wonders how one could possibly code it in a language which was designed
> with portability in mind.)

I don't think C was designed for portablility.  It was designed to allow a
reasonably high level language provide adequate access to the underlining
hardware so that WRITING CODE IN ASSEMBLER WOULD NOT BE NECESSARY.  The
fact that UNIX is written mostly in C says to me that it acheived that
goal.

I also get the impression that you perceive `portability' as the One True
Goal.  Portability is a useful goal for programs such as emacs and pcomm,
but not for an imbedded real-time control system that needs to have good
response times to external events.  For such a project, portability can
take a flying leap off a high cliff.

> There seems to be this great movement to make C the One True Programming
> Language That Lets You Do Anything You Want.  I don't think it is.
> If you want to get ``under the hood'' and play dirty tricks, then
> use assembly language.

You are right, C is not the 'One True Programming ...'.  BUT - it does let
me get ``under the hood'' and play `dirty' (I question the use of the word
"dirty") tricks.  This is the reason I started using C and it is the reason
I will continue to use C.
___________________________________________________________________________
____		Billy G. Allie		Internet..: bga@bgalli.eds.com
|  /|		7436 Hartwell		UUCP......: {mcf|edsews}!bgalli!bga
|-/-|-----	Dearborn, MI 48126	Compuserve: 76337,2061
|/  |LLIE	(313) 582-1540		Genie.....: BGALLIE

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/22/89)

In article <284@bgalli.UUCP> bga@bgalli.UUCP (Billy G. Allie) writes:
>You are right, C is not the 'One True Programming ...'.  BUT - it does let
>me get ``under the hood'' and play `dirty' (I question the use of the word
>"dirty") tricks.  This is the reason I started using C and it is the reason
>I will continue to use C.

C is good for that, but experience has shown that the vast majority
of the time, portable C coding practice suffices, and it has the
benefit of reducing the amount of work over the long run.  Necessary
non-portabilities can virtually always be isolated in a small section
of code, with the rest system-independent.  Unnecessary non-portabilities
are best avoided altogether.