Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Reinterpret the bits of a float as unsigned long

Reply
Thread Tools

Reinterpret the bits of a float as unsigned long

 
 
thomas.mertes@gmx.at
Guest
Posts: n/a
 
      02-03-2006
For a hash function I want to reinterpret the bits of a float
expression as unsigned long. The normal cast

(unsigned long) float_expression

truncates the float to an (unsigned long) integer.

But this is not the effect I want for a hash function.
With unions my hash function can be implemented:

union {
long unsigned hashvalue;
float floatvalue;
} value;

value.floatvalue = float_expression;

Now

value.hashvalue

contains the reinterpreted bits as intended. But I think a shorter
solution (without assignment or memcpy to a variable) should
be possible.

When I cast first to (void *) and after that to (unsigned long)
the gcc gives me the error:

cannot convert to a pointer type

It seems casting a float to a pointer is prohibited by gcc.

Has anybody an idea to reinterpret the bits of a float as
unsigned long without assignment or memcpy (some sort
of tricky cast).

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Wikipedia: http://en.wikipedia.org/wiki/Seed7
Project page: http://sourceforge.net/projects/seed7

 
Reply With Quote
 
 
 
 
P.J. Plauger
Guest
Posts: n/a
 
      02-03-2006
<(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...

> For a hash function I want to reinterpret the bits of a float
> expression as unsigned long. The normal cast
>
> (unsigned long) float_expression
>
> truncates the float to an (unsigned long) integer.
>
> But this is not the effect I want for a hash function.
> With unions my hash function can be implemented:
>
> union {
> long unsigned hashvalue;
> float floatvalue;
> } value;
>
> value.floatvalue = float_expression;
>
> Now
>
> value.hashvalue
>
> contains the reinterpreted bits as intended. But I think a shorter
> solution (without assignment or memcpy to a variable) should
> be possible.
>
> When I cast first to (void *) and after that to (unsigned long)
> the gcc gives me the error:
>
> cannot convert to a pointer type
>
> It seems casting a float to a pointer is prohibited by gcc.
>
> Has anybody an idea to reinterpret the bits of a float as
> unsigned long without assignment or memcpy (some sort
> of tricky cast).


If float_expression is a lvalue, you can write:

*(unsigned long *)&(float_expression)

but that is fraught with peril.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


 
Reply With Quote
 
 
 
 
thomas.mertes@gmx.at
Guest
Posts: n/a
 
      02-03-2006
"P.J. Plauger" <(E-Mail Removed)> wrote:

> If float_expression is a lvalue, you can write:
>
> *(unsigned long *)&(float_expression)
>
> but that is fraught with peril.


Thank you for your help. But the float_expression is not
granted to be an lvalue. Do you have an rvalue solution as well?

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Wikipedia: http://en.wikipedia.org/wiki/Seed7
Project page: http://sourceforge.net/projects/seed7

 
Reply With Quote
 
=?ISO-8859-1?Q?=22Nils_O=2E_Sel=E5sdal=22?=
Guest
Posts: n/a
 
      02-03-2006
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
> "P.J. Plauger" <(E-Mail Removed)> wrote:
>
>> If float_expression is a lvalue, you can write:
>>
>> *(unsigned long *)&(float_expression)
>>
>> but that is fraught with peril.

>
> Thank you for your help. But the float_expression is not
> granted to be an lvalue. Do you have an rvalue solution as well?

You can get at the underlying representation by casting to an
unsigned char* and work your way through that.
unsigned char *raw = (unsigned char *)&floatval;
Fiddle with raw[0] to raw[sizeof(float)-1] (e.g build an
unsigned long from the bits..)
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-03-2006


(E-Mail Removed) wrote On 02/03/06 13:20,:
> "P.J. Plauger" <(E-Mail Removed)> wrote:
>
>
>>If float_expression is a lvalue, you can write:
>>
>> *(unsigned long *)&(float_expression)
>>
>>but that is fraught with peril.

>
>
> Thank you for your help. But the float_expression is not
> granted to be an lvalue. Do you have an rvalue solution as well?


You'll have to store the value in an lvalue first.
Consider: "Reinterpreting the bits" is an operation on
the representation of a value, not on the value itself.
A value doesn't "get represented" (in any C-accessible
sense) until it's stored; a value "in flight" in an
expression is just a naked value, without a representation
that C has any way to talk about.

Don't overlook PJP's closing remark, by the way.
When he says "fraught with peril" he doesn't mean there's
only one peril; he means there are multiple perils. Just
off-hand and without working hard, I can think of three.

--
(E-Mail Removed)

 
Reply With Quote
 
P.J. Plauger
Guest
Posts: n/a
 
      02-03-2006
<(E-Mail Removed)> wrote in message
news:(E-Mail Removed) ups.com...

> "P.J. Plauger" <(E-Mail Removed)> wrote:
>
>> If float_expression is a lvalue, you can write:
>>
>> *(unsigned long *)&(float_expression)
>>
>> but that is fraught with peril.

>
> Thank you for your help. But the float_expression is not
> granted to be an lvalue. Do you have an rvalue solution as well?


No.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com


 
Reply With Quote
 
thomas.mertes@gmx.at
Guest
Posts: n/a
 
      02-03-2006
Eric Sosman <(E-Mail Removed)> wrote:

> You'll have to store the value in an lvalue first.
> Consider: "Reinterpreting the bits" is an operation on
> the representation of a value, not on the value itself.


Reinterpreting a float expression as unsigned long
does absolutely nothing with the value. In the machine
code you would see nothing at this place.

The C compiler (gcc) must be convinced to accept a
"do nothing" cast. Normal casts from float to (long) integers
are defined as trunc operations. But in my case nothing
should be done with the value. From the logical point of view
a "do nothing" operation does not need an lvalue.

The x86 gcc has the same size for float and unsigned long:

sizeof(float) = 4
sizeof(unsigned long) = 4

therefore all float values map to unsigned long values.
Just the compiler must be convinced.

Any ideas?

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Wikipedia: http://en.wikipedia.org/wiki/Seed7
Project page: http://sourceforge.net/projects/seed7

 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-03-2006


(E-Mail Removed) wrote On 02/03/06 14:55,:
> Eric Sosman <(E-Mail Removed)> wrote:
>
>
>>You'll have to store the value in an lvalue first.
>>Consider: "Reinterpreting the bits" is an operation on
>>the representation of a value, not on the value itself.

>
>
> Reinterpreting a float expression as unsigned long
> does absolutely nothing with the value. In the machine
> code you would see nothing at this place.


I think we've said the same thing in different words:
Reinterpretation is about representations, not about
values.

> The C compiler (gcc) must be convinced to accept a
> "do nothing" cast. Normal casts from float to (long) integers
> are defined as trunc operations.


That's why the compiler must *not* be convinced to
change its behavior. It is doing what the language
definition requires.

> But in my case nothing
> should be done with the value. From the logical point of view
> a "do nothing" operation does not need an lvalue.


It needs a representation to be able to reinterpret.
C is unable to "see" representations that do not reside
in lvalues, and this "blindness" is the source of some of
C's power to optimize. For example, `x++' is defined as
having the same effect as `x += 1', yet on many systems
there will not even *be* a `1' anywhere in the compiled
code of `x++'. That `1' has no representation, yet it
is a value nonetheless.

> The x86 gcc has the same size for float and unsigned long:
>
> sizeof(float) = 4
> sizeof(unsigned long) = 4
>
> therefore all float values map to unsigned long values.
> Just the compiler must be convinced.


That takes care of one of the three perils I thought
of. Another is alignment: the fact that two objects have
the same size does not imply that they have the same
alignment requirements -- and it's not hard to imagine a
machine whose integer and F-P units connect to memory in
different fashions (one word: "coprocessor").

The third peril is more subtle: Some F-P schemes can
use different bit combinations for the same value. In
IEEE F-P, for example, -0 and +0 are numerically equal but
have different representations. Since you want to use the
reinterpreted-as-long bits as a hash code, you could find
yourself with different hash codes for equal keys. Your
hash table would work fine *most* of the time ...

And, of course, once you've verified that all three
perils are either non-perilous or can be avoided on your
current machine, you or someone else will decide to use
the code on a different system -- where, all of a sudden,
`long' is eight bytes and requires eight-byte alignment.
The peril of avoiding peril rather than dealing with it
is that avoidance is local and avoidance is temporary ...

> Any ideas?


One thought is that using a floating-point value as a
hash key is a dodgy business at best. The problem isn't
so much with the value itself, but with the computation
that produces it: if you insert an item using `0.0f' as a
key and then try to retrieve it with `(float)cos(3.14159)'
you are quite likely to be disappointed. Discrepancies
as small as one part in four million are enough to bollix
your hash code and send the search to the wrong spot in
the table.

Are you sure you want to do this? What larger problem
are you trying to solve by building this hash table?

--
(E-Mail Removed)

 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      02-03-2006


Eric Sosman wrote On 02/03/06 16:04,:
>
> [...] if you insert an item using `0.0f' as a
> key and then try to retrieve it with `(float)cos(3.14159)'
> you are quite likely to be disappointed. [...]


Never do trig on an empty stomach. That should
have been `(float)sin(3.14159)', of course.

--
(E-Mail Removed)

 
Reply With Quote
 
thomas.mertes@gmx.at
Guest
Posts: n/a
 
      02-03-2006
Eric Sosman <(E-Mail Removed)> wrote

> Are you sure you want to do this? What larger problem
> are you trying to solve by building this hash table?


The Seed7 programming language supports hashtables for
all index types that provide a 'hashCode' and a 'compare'
function. If you use the type

hash [string] float

the 'hashCode(string)' and 'compare(string, sting)' functions
are used to implement this hashtable. When the baseType of
the hashtable (float in this examle) has also an 'hashCode'
and an 'compare' function the type 'hash [string] float' can
be flipped (the values are turned to keys and the keys into values).
the result type of the flipped hashtable is

hash [float] array string

When your 'hash [string] float' table maps mountain names to
their height. It is possible to write a list of mountains sorted by
height with:

mountainsWithHeight := flip(HeightOfMountain);
for height range sort(keys(mountainsWithHeight)) do
for mountainName range sort(mountainsWithHeight[height]) do
writeln(mountainName rpad 20 <& " " <& height);
end for;
end for;

This example is similar to the wordcnt.sd7 example in the
Seed7 package.

The Seed7 interpreter uses unions to store all object values.
The 'float to unsigned long' cast is done with unions there.
The Seed7 compiler produces a C program where the hashCode
function could just be a "do nothing" cast from float to
unsigned long.

Greetings Thomas Mertes

Seed7 Homepage: http://seed7.sourceforge.net
Wikipedia: http://en.wikipedia.org/wiki/Seed7
Project page: http://sourceforge.net/projects/seed7

 
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
float to string to float, with first float == second float Carsten Fuchs C++ 45 10-08-2009 09:47 AM
Shifting unsigned long long values by 64 bits krunalb C Programming 10 01-23-2007 02:47 PM
extracting front bits from an unsigned long long? Digital Puer C Programming 36 11-13-2005 12:05 PM
Assigning unsigned long to unsigned long long George Marsaglia C Programming 1 07-08-2003 05:16 PM
Re: float->byte->float is same with original float image. why float->ubyte->float is different??? bd C Programming 0 07-07-2003 12:09 AM



Advertisments