[comp.sys.super] Type punning in C

desj@idacrd.UUCP (David desJardins) (10/02/89)

   Does anyone have any ideas on how one should go about converting an
integer to the floating-point number with the same bit pattern?  One
frequently (well, occasionally) needs to do this to implement certain
bit manipulations efficiently on Cray computers and other vector
machines, and possibly on other architectures with fast floating-point
but no fast shift (?).  The best way I have found to do this in
FORTRAN is to write

      INTEGER I
      REAL X
      X = OR (I, 0).

(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)

   It doesn't seem that there is any equally straightforward way to
accomplish this in C.  I don't want to involve pointers because the
whole point is efficiency, and I expect that it will be very difficult
for any compiler to optimize out the dereferences in something like

      int i;
      float x;
      * (int *) & x = i;

to produce a single register-to-register transfer (or not even that).

   What I think is probably necessary is to define a real function of
one integer argument, returning the same bit pattern as its input.
Ultimately I would need to get Cray to incorporate it into their C
compiler as an intrinsic function.  Does anyone have any experience
with such a thing, or a good idea of how these functions should be
named?

   -- David desJardins

henry@utzoo.uucp (Henry Spencer) (10/08/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?  ...
>   It doesn't seem that there is any equally straightforward way to
>accomplish this in C.  I don't want to involve pointers ...

You might try unions.  This is one of the things they're good for,
albeit in a very implementation-specific way.  (Not a problem here,
since the operation is inherently implementation-specific.)

If your compiler won't put unions into registers, complain to your supplier.  
-- 
A bit of tolerance is worth a  |     Henry Spencer at U of Toronto Zoology
megabyte of flaming.           | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

ok@cs.mu.oz.au (Richard O'Keefe) (10/08/89)

In article <475@idacrd.UUCP>, desj@idacrd.UUCP (David desJardins) writes:
>    Does anyone have any ideas on how one should go about converting an
> integer to the floating-point number with the same bit pattern?

	union { long i; float x; } pun;
	pun.i = the_integer_to_be_converted;
	the_single_precision_result = pun.f;

> One frequently (well, occasionally) needs to do this to implement certain
> bit manipulations efficiently on Cray computers and other vector machines ...

Just which operations are these?  If the operations are meaningful functions
of floating-point numbers (e.g. things like ilogb() copysign() nextafter())
it might make more sense to ask Cray to put _those_ in their library.

I really would like to know what the operations are.

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

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
<   Does anyone have any ideas on how one should go about converting an
<integer to the floating-point number with the same bit pattern?

Try a union:
	union blah { int i; float f; } x;
	x.f = f;
	/* now manipulate x.i */

<   It doesn't seem that there is any equally straightforward way to
<accomplish this in C.  I don't want to involve pointers because the
<whole point is efficiency, and I expect that it will be very difficult
<for any compiler to optimize out the dereferences in something like
<      int i;
<      float x;
<      * (int *) & x = i;
<to produce a single register-to-register transfer (or not even that).

Not at all. It's a pretty much standard and trivial optimization to
convert *(int*)&x=i into MOV X,I. Feel free to use it, with the caveat
that float format is not the same from machine to machine. I've done
it many times to do special manipulations on doubles.

jerry@violet.berkeley.edu ( Jerry Berkman ) (10/11/89)

In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
>   Does anyone have any ideas on how one should go about converting an
>integer to the floating-point number with the same bit pattern?
>The best way I have found to do this in FORTRAN is to write

>      INTEGER I
>      REAL X
>      X = OR (I, 0).

>(The Cray FORTRAN compiler optimizes out the trivial OR instruction.)
>   -- David desJardins

Why not use equivalence?
	INTEGER I
	REAL X, IX
	EQUIVALENCE (X,IX)

	IX = I
The Fortran standard specifies that a REAL and INTEGER occupy the same space.
The only problem is this might fool some optimizers.

	- Jerry Berkman
	  jerry@violet.berkeley.edu

ok@cs.mu.oz.au (Richard O'Keefe) (10/11/89)

In article <1989Oct10.185851.6490@agate.berkeley.edu>, jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
: In article <475@idacrd.UUCP> desj@idacrd.UUCP (David desJardins) writes:
: >   Does anyone have any ideas on how one should go about converting an
: >integer to the floating-point number with the same bit pattern?

: Why not use equivalence?
: 	INTEGER I
: 	REAL X, IX
: 	EQUIVALENCE (X,IX)

Because he was asking how to do it in C.

I understand that the original problem was something that could be expressed	
quite clearly and simply as an ordinary C arithmetic expression operating
exclusively on integers, and that straightforward C code would _work_ on the
Cray, but because some operation (bitwise shifts?) didn't have a vector
equivalent it wouldn't vectorise.  But a hairy hack involving floats _would_
vectorise because the Cray system is good at vectorising float operations.

The interesting point here is that there are a lot of things you can do IF
you have the functions required and recommended in the IEEE 754 standard.
For example, if there is some reason why you want to avoid
	p << i		use	(int) scalb((float)p, i)
	p >> j		use	(int) scalb((float)p, -j)

This is why I think that it would be interesting for people with such
problems (and this includes Herman Rubin) to give us more detail about
the problem they are really trying to solve (e.g. the original poster's
problem was "how do I get results equal to these in a way that will
vectorise on a Cray?").  It may be that some of these problems have
solutions which are less machine-specific than hand-crafted bit-twiddling,
or would be if functional equivalents of the IEEE functions were provided.

exspes@gdr.bath.ac.uk (P E Smee) (10/11/89)

In article <1989Oct10.185851.6490@agate.berkeley.edu> jerry@violet.berkeley.edu ( Jerry Berkman ) writes:
>
>Why not use equivalence?
>	INTEGER I
>	REAL X, IX
>	EQUIVALENCE (X,IX)
>
>	IX = I
>The Fortran standard specifies that a REAL and INTEGER occupy the same space.
>The only problem is this might fool some optimizers.
>
Problem is, the Fortran standard *also* says that if your program tries
to take the value of the variable using a different type than the type you
used when you last stored into it, your program is invalid.  This is a
polite way of saying (to the user) 'this trick may not work', and (to the
compiler writer) 'your optimizer does not have to worry about aliasing
between variables of different types'.  If the compiler can tell that
you are going to (e.g.) store an integer into that storage, and then
read a real, it is under no obligation to make sure that the integer
value gets stored.

Fortran equivalence was designed toallow reuse of storage on the early
small memory machines -- not to allow type punning.  Usually you can
get away with punning, but it doesn't always work and so is a bad habit.

-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

khb%chiba@Sun.COM (Keith Bierman - SPD Advanced Languages) (10/13/89)

In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:


>Problem is, the Fortran standard *also* says that if your program tries
>to take the value of the variable using a different type than the type you
>used when you last stored into it, your program is invalid.  This is a
>polite way of saying (to the user) 'this trick may not work', and (to
>the

My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
make this obvious to me. Could you please quote chapter and verse ?

>
>Fortran equivalence was designed toallow reuse of storage on the early
>small memory machines -- not to allow type punning.  Usually you can
>get away with punning, but it doesn't always work and so is a bad habit.
>

On which systems (if any) have you seen this not work ?


Keith H. Bierman    |*My thoughts are my own. !! kbierman@sun.com
It's Not My Fault   |	MTS --Only my work belongs to Sun* 
I Voted for Bill &  | Advanced Languages/Floating Point Group            
Opus                | "When the going gets Weird .. the Weird turn PRO"

exspes@gdr.bath.ac.uk (P E Smee) (10/16/89)

In article <126279@sun.Eng.Sun.COM> khb@sun.UUCP (Keith Bierman - SPD Advanced Languages) writes:
>In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>
>
>>Problem is, the Fortran standard *also* says that if your program tries
>>to take the value of the variable using a different type than the type you
>>used when you last stored into it, your program is invalid.  
>
>My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
>make this obvious to me. Could you please quote chapter and verse ?
>
Section 17.3(2) -- (or, page 17.4, lines 15-18) 'When an entity of a
given type becomes defined, all totally associated entities of
different type become undefined.'  With 17.2(1) 'Execution of an
arithmetic, logical, or character assignment statement causes the
entity that precedes the equals to become defined.  These must, of
course, be taken in conjunction with the definition of what it means
for something to be defined, and with the fact that if your program
uses variables while they are undefined, your program is invalid.

From 17.1 it is clear that EQUIVALENCE may cause total association.
May also cause only partial association depending on what the
equivalanced entities are.  In particular, from 17.1.1 single
(non-array) integer, real, and logical values equivalenced in any mix
are totally associated.

>>
>>Fortran equivalence was designed toallow reuse of storage on the early
>>small memory machines -- not to allow type punning.  Usually you can
>>get away with punning, but it doesn't always work and so is a bad habit.
>>
>
>On which systems (if any) have you seen this not work ?
>
Honeywell Multics at certain optimisation levels.  Of course, since HIS
don't make them any more, that's a moot point.  I believe I recall
similar occasional problems under various flavours of IBM OSes, again
at particular optimisation levels.  Doesn't alter the fact that since
the standard makes it clear that it can be invalid, it's a bad habit.

-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes

exspes@gdr.bath.ac.uk (P E Smee) (10/16/89)

In article <1989Oct16.092936.142@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>In article <126279@sun.Eng.Sun.COM> khb@sun.UUCP (Keith Bierman - SPD Advanced Languages) writes:
>>In article <1989Oct11.091619.18336@gdt.bath.ac.uk> exspes@gdr.bath.ac.uk (P E Smee) writes:
>>
>>
>>>Problem is, the Fortran standard *also* says that if your program tries
>>>to take the value of the variable using a different type than the type you
>>>used when you last stored into it, your program is invalid.  
>>
>>My quick peek into the document (pages 8-3 and 17-1..4ish) doesn't
>>make this obvious to me. Could you please quote chapter and verse ?
>>
In the previous posting, I quoted chapter and verse from the 77 FORTRAN
standard.  The 66 standard is even stricter.  EQUIVALENCE causes things
to become associated (full stop -- no fudging about partial or total
association) and says in 10.2.3.1 (5) [Variables and array
elements become undefined as follows:] When an associated entry
of different type becomes defined.

So, I'd say the 66 standard prohibits it completely, while the 77 standard
allows it in some cases (but only when the variables are not (loosely
speaking) of the same size).  The one interesting case which is explicitly
valid in 77 appears to be EQUIVALENCE of a REAL array of dimension 2 with
an COMPLEX variable, in which case REAL(1) would be the real part of
the COMPLEX and REAL(2) the imaginary part.
-- 
 Paul Smee               |    JANET: Smee@uk.ac.bristol
 Computer Centre         |   BITNET: Smee%uk.ac.bristol@ukacrl.bitnet
 University of Bristol   | Internet: Smee%uk.ac.bristol@nsfnet-relay.ac.uk
 (Phone: +44 272 303132) |     UUCP: ...!mcvax!ukc!gdr.bath.ac.uk!exspes