473,396 Members | 1,894 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Conversion between float and long

I was very puzzled about the conversion between float and long, I
cann't understand why a long val can convert to a float, as the below
codes show:

typedef unsigned long u_long;
float val = 3.14159;
u_long nw_val = *((u_long *) &val);

than the nw_val equal to 1078530000, I made such conversion:
float d_val = *((float*)&nw_val);

than I got d_val = 3.14159

Can anybody help me explains this sentence *((u_long*) &val) ?

best regards!

Jun 27 '08 #1
8 14055
d major <ji*****@gmail.comwrites:
>I was very puzzled about the conversion between float and long,
http://www-h.eng.cam.ac.uk/help/tpl/...ongtyping.html
might help.

>Can anybody help me explains this sentence *((u_long*) &val) ?
You're creating a pointer of type u_long* and pointing it at a place
where a float has been stored. When you dereference this pointer (using
the first of the "*" symbols) the bit-pattern representation of the
float's value is being treated as if it were the representation of a u_long.
floats and ints are stored in different formats, so you get a strange value.

Jun 27 '08 #2
On 2008-05-21 06:37:04 -0400, d major <ji*****@gmail.comsaid:
I was very puzzled about the conversion between float and long, I
cann't understand why a long val can convert to a float, as the below
codes show:

typedef unsigned long u_long;
float val = 3.14159;
u_long nw_val = *((u_long *) &val);

than the nw_val equal to 1078530000, I made such conversion:
float d_val = *((float*)&nw_val);

than I got d_val = 3.14159

Can anybody help me explains this sentence *((u_long*) &val) ?
Please don't call this a conversion between float and long. It's not.
It's a conversion between pointers, and the cast should be a hint that
someting isn't kosher. In particular, if an unsigned long and a float
are different sizes, at worst you'll get a nonsensical result, and at
best you'll get a hardware trap. If they're the same size (which is
unusual these days), the conversion will probably work, and then the
unsigned long that you get from dereferencing the converted pointer
will have the same bit pattern as the float. But of course the meaning
of those bits is completely different. This is low-level hacker stuff;
don't do it.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Jun 27 '08 #3
On May 21, 1:00*pm, t...@eng.cam.ac.uk (Tim Love) wrote:
d major <jing...@gmail.comwrites:
I was very puzzled about the conversion between float and long,

*http://www-h.eng.cam.ac.uk/help/tpl/...ongtyping.html
might help.
Can anybody help me explains this sentence *((u_long*) &val) ?

You're creating a pointer of type u_long* and pointing it at a place
where a float has been stored. When you dereference this pointer (using
the first of the "*" symbols) the bit-pattern representation of the
float's value is being treated as if it were the representation of a u_long.
floats and ints are stored in different formats, so you get a strange value.
And, BTW, reading from a memory location using a type different than
its dynamic
type is undefined behavior as it breaks strict aliasing, and will
actually
break on real modern compilers.

Note that the union trick, explained else post, is also undefined but
it is a common
extension to the language.

The correct way to implement this type of type punning is using
std::memcpy.

HTH,

--
Giovanni P. Deretta
Jun 27 '08 #4
Hi!

d major schrieb:
I was very puzzled about the conversion between float and long, I
cann't understand why a long val can convert to a float,
It can. And apart from the discussion about the *pointer* cast I want to
show the simple numeric cast:

#include <iostream>
#include <ostream>
int main()
{
const float f = 3.1415962f;
const long l = f;
const float f2 = l;
std::cout << f2 << std::endl;
}

Which simply prints "3". "l" is created from "f" which is a float. "l =
f" is a numeric conversion and will likely produce a compiler warning.
"f2 = l" is another conversion in the reverse direction: from long to
float. It does not produce a warning as it is a standard "promotion" (I
think): the range of a float is assumed to be larger than the range of a
long, so there shouldn't be a problem (hehe, loss of precision probably,
but anyway).

Frank
Jun 27 '08 #5
On 21 mai, 17:26, gpderetta <gpdere...@gmail.comwrote:
On May 21, 1:00 pm, t...@eng.cam.ac.uk (Tim Love) wrote:
d major <jing...@gmail.comwrites:
>I was very puzzled about the conversion between float and long,
http://www-h.eng.cam.ac.uk/help/tpl/...ongtyping.html
might help.
>Can anybody help me explains this sentence *((u_long*) &val) ?
You're creating a pointer of type u_long* and pointing it at
a place where a float has been stored. When you dereference
this pointer (using the first of the "*" symbols) the
bit-pattern representation of the float's value is being
treated as if it were the representation of a u_long.
floats and ints are stored in different formats, so you get
a strange value.
And, BTW, reading from a memory location using a type
different than its dynamic type is undefined behavior as it
breaks strict aliasing, and will actually break on real modern
compilers.
It's well defined if the target type is a character pointer;
you're allowed to read the raw bytes of an "object". It's also
fairly clearly the intent of the standard that it should work
more or less as expected for other basic types.

It also happens that making it work wrecks havoc with the
optimizer, and can slow code down considerably, so compilers
don't normally do it unless the casts are very local and very
visible. (A good compiler will turn off optimizing if it sees a
reinterpret_cast in a block. That still won't help if you pass
the converted pointer to another function, however.)
Note that the union trick, explained else post, is also
undefined but it is a common extension to the language.
The advantage of the union trick (from a compiler author's point
of view) is that the aliasing is immediately visible. But it
doesn't necessarily work either if you take the address of each
of the members, and pass those addresses to another function.
The correct way to implement this type of type punning is
using std::memcpy.
The more correct thing to do is not to implement it at all:-).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #6
On May 21, 10:20*pm, James Kanze <james.ka...@gmail.comwrote:
On 21 mai, 17:26, gpderetta <gpdere...@gmail.comwrote:
On May 21, 1:00 pm, t...@eng.cam.ac.uk (Tim Love) wrote:
d major <jing...@gmail.comwrites:
I was very puzzled about the conversion between float and long,
*http://www-h.eng.cam.ac.uk/help/tpl/...ongtyping.html
might help.
Can anybody help me explains this sentence *((u_long*) &val) ?
You're creating a pointer of type u_long* and pointing it at
a place where a float has been stored. When you dereference
this pointer (using the first of the "*" symbols) the
bit-pattern representation of the float's value is being
treated as if it were the representation of a u_long.
floats and ints are stored in different formats, so you get
a strange value.
And, BTW, reading from a memory location using a type
different than its dynamic type is undefined behavior as it
breaks strict aliasing, and will actually break on real modern
compilers.

It's well defined if the target type is a character pointer;
you're allowed to read the raw bytes of an "object". *
Yes, forgot to mention that.
It's also
fairly clearly the intent of the standard that it should work
more or less as expected for other basic types.
I'm not convinced about that. In fact I have read experts discussing
this that made it clear that strict aliasing also applies to all
types
(modulo exceptions like chars). In particular the guaranteed freedom
of
aliasing between integral and floating point types could very well
speed
up real numeric code (which uses integers for indexes and floats for
computation). Or at least, this is what I've read.

Type aliasing is still a very controversial topic, as you can see
by browsing gcc bugzilla :)

There are also a couple of open issues on the C standard regarding
this
topic.
[...]
The correct way to implement this type of type punning is
using std::memcpy.

The more correct thing to do is not to implement it at all:-).
;)

Of course, but in real life it is sometime necessary for some system
specific operations...

... or optimizations *ducks*.

--
Giovanni P. Deretta
Jun 27 '08 #7
On May 21, 11:12*pm, Michael DOUBEZ <michael.dou...@free.frwrote:
gpderetta a écrit :
And, BTW, reading from a memory location using a type different than
its dynamic
type is undefined behavior as it breaks strict aliasing,

As soon as you have a reinterpret_cast<>(), you have however UB.
I think that it is actually implementation defined.

For example the POSIX standard practically requires is it do deal
with
sockaddr_t and friends.
and will actually break on real modern compilers.

IIRC on gcc, strict aliasing is only activated from -02 optimisation
In current releases, in future it could been enabled even at lower
optimization levels...
and
you can always pass a -fno-strict-aliasing to avoid the optimisation.
... and, as the man page says, -fno-strict-aliasing is not guaranteed
to be supported in the future. I would be surprised if it were to be
dropped though, way too much software would break.
>
Does it really break when only reading values or passing a pointer
around (float*->long*->float*) ? I though aliasing was a problem only
upon writing (i.e. the value is not propagated to heterogeneous readers).
I do not know, it might or might not. I think the gcc developers have
explicitly refused to guarantee it.

--
Giovanni P. Deretta
Jun 27 '08 #8
On May 22, 12:30 am, gpderetta <gpdere...@gmail.comwrote:
On May 21, 10:20 pm, James Kanze <james.ka...@gmail.comwrote:
On 21 mai, 17:26, gpderetta <gpdere...@gmail.comwrote:
On May 21, 1:00 pm, t...@eng.cam.ac.uk (Tim Love) wrote:
d major <jing...@gmail.comwrites:
>I was very puzzled about the conversion between float and long,
http://www-h.eng.cam.ac.uk/help/tpl/...ongtyping.html
might help.
>Can anybody help me explains this sentence *((u_long*) &val) ?
You're creating a pointer of type u_long* and pointing it at
a place where a float has been stored. When you dereference
this pointer (using the first of the "*" symbols) the
bit-pattern representation of the float's value is being
treated as if it were the representation of a u_long.
floats and ints are stored in different formats, so you get
a strange value.
And, BTW, reading from a memory location using a type
different than its dynamic type is undefined behavior as it
breaks strict aliasing, and will actually break on real modern
compilers.
It's well defined if the target type is a character pointer;
you're allowed to read the raw bytes of an "object".
Yes, forgot to mention that.
Note that we're talking about the standard here. Any
relationship between what the standard requires and what any
particular implementation does is purely coincidental.
It's also fairly clearly the intent of the standard that it
should work more or less as expected for other basic types.
I'm not convinced about that.
The note in §5.2.10/4, concerning the mapping done by
reinterpret_cast: "it is intended to be unsurprising to those
who know the addressing structure of the underlying machine."
Strictly speaking, this note concerns the mapping between
integers and pointer types, but it seems reasonable to expect it
to further apply between two pointer types.
In fact I have read experts discussing this that made it clear
that strict aliasing also applies to all types (modulo
exceptions like chars). In particular the guaranteed freedom
of aliasing between integral and floating point types could
very well speed up real numeric code (which uses integers for
indexes and floats for computation). Or at least, this is what
I've read.
It's a case of the left hand not knowing what the right hand is
doing:-). The rules concerning aliasing are very important for
optimizing, and C++ very clearly does say in its object model
that accessing an object via an lvalue of a different type
(other than a character type) is undefined behavior. Regardless
of how you do it. On the other hand, reinterpret_cast is
useless unless you can do it. Clearly, reinterpret_cast is not
meant for portable code, but arguably, it should be usable in an
implementation defined manner. And the "undefined behavior" in
the object model is not because of optimizing, but because
accessing an int as a double (for example) might result in a
trapping representation. (But we don't have a rationale for the
C++ standard, so we don't know the real motivations.)

Practically, from a quality of implementation point of view, I'd
expect such accesses to behave in a manner "unsurprising to
those who know the addressing structure of the underlying
machine", and the exact representations of the types involved,
if, but only if, the reinterpret_cast is clearly visible to the
compiler, i.e. if I write something like:

void
f( double* d )
{
unsigned long long* p
= reinterpret_cast< unsigned long long* >( d ) ;
*p = 0x4000000000000000ULL ;
}

I expect the double pointed to by d to be modified to contain
the specified bit pattern, and that code calling this function,
say:

void
g()
{
double d = 0.0 ;
f( &d ) ;
std::cout << d << std::endl ;
}

will output the expected value (1.0, if I'm not mistaken with my
integral literal). Either the compiler knows what is in f()
(e.g. because it is inline), can see the reinterpret_cast, and
so knows that strict aliasing no longer applies, or it doesn't
know, in which case, it has to assume that f modifies d, and
thus reread the value before calling operator<<.

I don't expect it to work in a function which gets the two
pointers (one double*, one unsigned long long*) from some
external, unknown source.
Type aliasing is still a very controversial topic, as you can
see by browsing gcc bugzilla :)
It's essential for good optimization. All that one can
reasonably ask is that the compiler drop it when it sees a
reinterpret_cast.
There are also a couple of open issues on the C standard
regarding this topic.
I can believe it.

My understanding of the intent in C90 was that casting, and not
unions should be used for type punning. Admittedly, however,
this is based on somewhat uncertain memories of vague
discussions many years ago, so I'm not sure how reliable it is.
Still, it seems clear to me that a union introduces still an
additional constraint:

union U
{
double d1 ;
double d2 ;
} u ;

Formally, if you write to u.d1, and read from u.d2, you have
undefined behavior. Supposedly, in theory at least, an
implementation could keep a tag cached somewhere hidden, and
check it when you accessed. (How such an implementation would
deal with something like *(double*)(&u), I don't know, since
I think there is a guarantee that casting the address of a union
to the type of an address to one its members results in a
pointer to the member.)

Practically (again from a quality of implemenation point of
view), I'd expect type punning with a union to work as long as
the accesses are all directly to the union---again, if you take
the address of two members of different types, and pass them to
another function, I think that that function has the right to
suppose that different types means non-overlapping objects. But
I've used at least one C compiler where this was NOT the case.
[...]
The correct way to implement this type of type punning is
using std::memcpy.
The more correct thing to do is not to implement it at all:-).
;)
Of course, but in real life it is sometime necessary for some
system specific operations...
If you're writing very low level software, you almost have to.
How would you write a garbage collector without breaking typing,
for example?
... or optimizations *ducks*.
No need to duck. As I've said more than once, if the profiler
says you have to, you have to.

Practically: see the thread about reading floating point values.
You generally have an engineering decision: you don't need the
type punning, but if it can be done reasonably safely, and saves
a couple of days of development time...

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jun 27 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Stub | last post by:
Docs says that "The compiler does not use an explicit constructor to implement an implied conversion of types. It's purpose is reserved explicitly for construction." I put up code of three cases...
15
by: dkultasev | last post by:
I mean, when I am trying to get result of 1/3 (or smf) it returns 0.33333333334 or something. I understand that result can not be 100% right, but it is it possibly to get more accuracy ?...
22
by: bq | last post by:
Hello, Two questions related to floating point support: What C compilers for the wintel (MS Windows + x86) platform are C99 compliant as far as <math.h> and <tgmath.h> are concerned? What...
2
by: sriamar | last post by:
Hello, How does the type conversion work if the expression involves a float and long int? By K&R 2nd Ed i assume float & long -> float & float . But does the 'long' qualifier affect this...
16
by: TTroy | last post by:
Hello, I'm relatively new to C and have gone through more than 4 books on it. None mentioned anything about integral promotion, arithmetic conversion, value preserving and unsigned preserving. ...
13
by: maadhuu | last post by:
hello , i would like to know as to why double is more efficient than float . thanking you, ranjan.
3
by: Ken Dopierala Jr. | last post by:
Hi, Here is C# code: Random rdm1 = new Random(unchecked((int)DateTime.Now.Ticks)); Can I do this in VB? I've tried CType(DateTime.Now.Ticks, Integer) and CInt(DateTime.Now.Ticks) but...
3
by: pranab.salian | last post by:
I need to compile some newer code in Borland TC 3.0. Here's the snippet.. /* CODE */ /* // --------------------------------------------------------------- // Shift register implementation:...
2
by: mystiq | last post by:
How can I convert numbers input as long/long double data type to binary in C/C++??? The program is in 2 parts. First teh program has to change inputs from long(32 bits) to binary and then show...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.