Re: Fast binary IEEE to float
Thomas Richter wrote:
Actually, I think I'd write it using references :
float QuickBinaryToFloat( uint32_t in )
{
return reinterpret_cast< float& >( in ) ;
}
Ah, so here's the trick. I've to use a reference. Thanks.
Maybe. In the end, what you need is for it to be fast, AND to
work. Technically, this is exactly the same as if you had
written it as "*reinterpret_cast< float* >( &in )". I find it
feels more natural with the references, but I cannot imagine it
being treated in any way differently in the compiler internals.
Formally, that's undefined behavior. (The reinterpret_cast
is only implementation defined.) In practice, it should
work if the function is compiled without optimization.
(With optimization, of course, the compiler will recognize
that u.i is never used, and suppress the assignment.)
So, in that sense, "avoid" since we're compiling with
optimization turned on.
Well, it depends on the compiler. G++ actually guarantees it,
as an extension. In addition, g++ doesn't work in all cases
with the pointer aliasing, at least from what I understand.
(From the bug report cited in another answer, I gather that this
is not intentional, and that it has been, or will be, fixed.)
Neither are formally guaranteed by the standard. The wording of
the standard (and of the C standard before it) strongly suggests
that the targetted way of supporting this kind of aliasing is
using pointer casts, or reference casts in C++ (and of course,
these are reinterpret_cast's in C++) -- the results of such
conversions are "unspecified" and not "undefined behavior", and
a note also indicates that "it [the mapping function] is
intended to be unsurprising to those who know the addressing
structure of the underlying machine". Still, as you very well
realize, you're playing with fire, and the essential is to not
get burned. You're doing something very implementation
specific, so what counts most is what the implementation
actually does, and not what the standard says.
3) Modified version 1):
float QuickBinaryToFloat(LONG in)
{
return *(float *)(char *)∈
}
What does this buy you compared to 1?
Well, "no warning from g++-4.1" due to changed aliasing rules,
but probably a pessimisation as well. Though it looks quite
obscure, too. (Note to myself: Add comments here, definitely!)
Note that there are two issues to be concerned with: the
warning, and what the optimizer does. There are definitely
cases where the code will work, despite the warning. Given the
bug report, I think it possible that there are cases where the
code might not work, even in the absense of a warning.
Whatever solution you choose, test it very, very thoroughly.
(If you do run into problems, you might want to consider some
judicious use of volatile, to inhibit the optimization at
specific points of access -- and only at those points.)
[...]
Method 3 avoids the aliasing as a "char *" must, AFAIK, be
assumed to be possibly aliased. It might possibly (?)
prevent the optimizer from making some optimizations - the
code above is truncated down, it is part of a larger
method which does this step.
Since you don't actually access as a char*, method 3 buys
you nothing (IMHO). Strictly speaking, the surest is
copying the bytes: memcpy, or copy through an unsigned
char*. That is the only way in which the standard
guarantees that the bits in the original uint32_t are the
same as those in the float.
Method 4) then. I would need to try how that performs, but I
would suspect it's not quite as fast as 1) or 3).
Probably not.
Note that if you are doing something like a*x + b*y + c, where x
and y are your floats mascarading as int's, the reference and
pointer conversions can, in theory at least, be made to use them
directly, without any copying.
(I'm sure you've considered the issue, and determined that it's
not a problem in your case, but for others, it's worth pointing
out that when reading streamed bytes, there is no guarantee per
se with regards to alignment -- a float might occur three bytes
into a buffer. In such cases, the only thing which will work
other than a portable conversion is memcpy, or some equivalent,
which accesses the data byte by byte to copy it into the
target.)
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]