Jump to page: 1 2
Thread overview
D equivalent of C++ reinterpret cast?
Sep 19, 2010
Bradley Mitchell
Sep 19, 2010
orgoton baberek
Sep 20, 2010
bearophile
Sep 20, 2010
Jonathan M Davis
Sep 20, 2010
Ali Çehreli
Sep 20, 2010
bearophile
Sep 20, 2010
Juanjo Alvarez
Sep 20, 2010
Jonathan M Davis
Sep 20, 2010
Kagamin
Sep 19, 2010
Simen kjaeraas
Sep 19, 2010
Bradley Mitchell
September 19, 2010
Hello,

I'm trying to implement the Quake 3 fast inverse square root algorithm which requires casting from int to float without modifying the stored bits. A C++ reinterpret cast seems to accomplish this just fine but so far I have had no success in D after trying quite a few different things. Here is the C++ I've written that currently works:

#include <iostream>

float fastInvSqrt( float x )
{
    const int INV_SQRT_N = 1597292357;
    const float MULT = 1.000363245811462f;

    float const mx = 0.5f * MULT * x;
    int xi = *reinterpret_cast<int *>( &x );
    xi = INV_SQRT_N - (xi >> 1);
    x = *reinterpret_cast<float *>( &xi );
    return x * (1.5f * MULT - mx * x * x);
}

int main()
{
    float a = fastInvSqrt( 9.0f );
    std::cout << a << std::endl;
}

And here is my D code that doesn't work yet:

module test;

import std.stdio;

float fastInvSqrt( float x )
{
    const int INV_SQRT_N = 1597292357;
    const float MULT = 1.000363245811462f;

    float mx = 0.5f * MULT * x;
    int xi = cast(int)cast(void*)x;
    xi = INV_SQRT_N - (xi >> 1);
    x = xi;
    x = cast(float)cast(void*)xi;
    return x * (1.5f * MULT - mx * x * x);
}

void main(string[] args)
{
    float a = fastInvSqrt( 9.0f );
    writefln("%f", a);
}

For further reference, the wikipedia article on this algorithm can be found here: http://en.wikipedia.org/wiki/Fast_inverse_square_root

and my C++ code is based on a slightly modified version described here: http://www.ece.uwaterloo.ca/~dwharder/Algorithms_and_Data_Structures/Algorithms/Inverse_square_root/

As you can see, I'm not trying to convert an integer to an equivalent floating point value but rather trying to coerce the variable to a float without modifying the underlying bit sequence. Any help would be greatly appreciated!!

Thank you for your time,
Brad
September 19, 2010
On 19/09/2010 18:39, Bradley Mitchell wrote:
> Hello,
>
> I'm trying to implement the Quake 3 fast inverse square root algorithm which
> requires casting from int to float without modifying the stored bits. A C++
> reinterpret cast seems to accomplish this just fine but so far I have had no
> success in D after trying quite a few different things. Here is the C++ I've
> written that currently works:
>
> #include<iostream>
>
> float fastInvSqrt( float x )
> {
>      const int INV_SQRT_N = 1597292357;
>      const float MULT = 1.000363245811462f;
>
>      float const mx = 0.5f * MULT * x;
>      int xi = *reinterpret_cast<int *>(&x );
>      xi = INV_SQRT_N - (xi>>  1);
>      x = *reinterpret_cast<float *>(&xi );
>      return x * (1.5f * MULT - mx * x * x);
> }
>
> int main()
> {
>      float a = fastInvSqrt( 9.0f );
>      std::cout<<  a<<  std::endl;
> }
>
> And here is my D code that doesn't work yet:
>
> module test;
>
> import std.stdio;
>
> float fastInvSqrt( float x )
> {
>      const int INV_SQRT_N = 1597292357;
>      const float MULT = 1.000363245811462f;
>
>      float mx = 0.5f * MULT * x;
>      int xi = cast(int)cast(void*)x;
>      xi = INV_SQRT_N - (xi>>  1);
>      x = xi;
>      x = cast(float)cast(void*)xi;
>      return x * (1.5f * MULT - mx * x * x);
> }
>
> void main(string[] args)
> {
>      float a = fastInvSqrt( 9.0f );
>      writefln("%f", a);
> }
>
> For further reference, the wikipedia article on this algorithm can be found here:
> http://en.wikipedia.org/wiki/Fast_inverse_square_root
>
> and my C++ code is based on a slightly modified version described here:
> http://www.ece.uwaterloo.ca/~dwharder/Algorithms_and_Data_Structures/Algorithms/Inverse_square_root/
>
> As you can see, I'm not trying to convert an integer to an equivalent floating
> point value but rather trying to coerce the variable to a float without
> modifying the underlying bit sequence. Any help would be greatly appreciated!!
>
> Thank you for your time,
> Brad

Use a union, which is the correct and safe way.

union convert
{
	float f;
	uint i;
}


convert.f = 1.0f;
writeln(convert.i);

will print 1065353216 (0x3f800000)
September 19, 2010
Bradley Mitchell <abstractant1@gmail.com> wrote:

>     int xi = cast(int)cast(void*)x;
[...]
>     x = cast(float)cast(void*)xi;

The simple solution (seeing as how x is an lvalue) is


    int xi = *cast(int*)&x;
[...]
    x = *cast(float*)&xi;

Function version:

T reinterpret( T, U )( U value ) {
    return *cast( T* )&value;
}

There may be situations in which this will not work (though
I know of none, OTOH), and where using a union will:

T reinterpret( T, U )( U value ) {
    union Uni {
        U u;
        T t;
    }
    return Uni(value).t;
}

Of course, these are general solutions, and the easy solution
to your problem is to use a union directly:


float fastInvSqrt( float x ) {
    enum int INV_SQRT_N = 1597292357;
    enum float MULT = 1.000363245811462f;

    float mx = 0.5f * MULT * x;
    union Xu {
        float f;
        int i;
    }
    Xu xu = Xu(x);
    xu.i = INV_SQRT_N - (xu.i >> 1);
    return xu.f * (1.5f * MULT - mx * xu.f * xu.f);
}


-- 
Simen
September 19, 2010
Yes, that did it exactly!

Thank you, Simen, and Orgoton.

September 20, 2010
orgoton baberek:
> Use a union, which is the correct and safe way.

C standard say that's not safe. You can force that to be safe in C-GCC if you explicitly disable a compiler optimization. I think D docs don't say anything about this. And Walter has said that regarding such things D acts as C. So I am not sure that will be safe in future D.

Bye,
bearophile
September 20, 2010
On Sunday 19 September 2010 17:07:38 bearophile wrote:
> orgoton baberek:
> > Use a union, which is the correct and safe way.
> 
> C standard say that's not safe. You can force that to be safe in C-GCC if you explicitly disable a compiler optimization. I think D docs don't say anything about this. And Walter has said that regarding such things D acts as C. So I am not sure that will be safe in future D.
> 
> Bye,
> bearophile

I'd have to go digging in old posts, but I'm pretty sure that that's essentially how you're supposed to do it in D. I haven't ever done it because I think that that sort of casting is pretty evil and only should be used as a last resort, but I believe that unions are the correct way to handle it in D. It's been discussed before, I'm fairly certain, though I think that the last place that I saw it was buried in a topic on a specific problem rather than anything necessarily particularly searchable in the archives.

- Jonathan M Davis
September 20, 2010
Jonathan M Davis wrote:
> On Sunday 19 September 2010 17:07:38 bearophile wrote:
>> orgoton baberek:
>>> Use a union, which is the correct and safe way.
>> C standard say that's not safe. You can force that to be safe in C-GCC if
>> you explicitly disable a compiler optimization. I think D docs don't say
>> anything about this. And Walter has said that regarding such things D acts
>> as C. So I am not sure that will be safe in future D.
>>
>> Bye,
>> bearophile
>
> I'd have to go digging in old posts, but I'm pretty sure that that's essentially
> how you're supposed to do it in D. I haven't ever done it because I think that
> that sort of casting is pretty evil and only should be used as a last resort,
> but I believe that unions are the correct way to handle it in D.

I remember being a part of a discussion where D'is unions were told to be exactly the same as C's. That means, results of using a union is only specified when it's used through one its members. Writing to one member and reading from another is unspecified. It is clear that endianness and padding should complicate matters.

But it's still used in C in low level code. That must be because programs are not as portable as thought; and if they are, compile time checks and macro magic are possible to obtain expected behavior.

Ali
September 20, 2010
On Sun, 19 Sep 2010 20:07:38 -0400, bearophile <bearophileHUGS@lycos.com> wrote:
> C standard say that's not safe. You can force that to be safe in 
C-GCC if you explicitly disable a compiler optimization. I think D docs don't say anything about this. And Walter has said that regarding such things D acts as C. So I am not sure that will be safe in future D.

Unions are not allowed in SafeD, so I guess they are considered unsafe in D.
September 20, 2010
On Sunday 19 September 2010 18:19:25 Juanjo Alvarez wrote:
> On Sun, 19 Sep 2010 20:07:38 -0400, bearophile
> 
> <bearophileHUGS@lycos.com> wrote:
> > C standard say that's not safe. You can force that to be safe in
> 
> C-GCC if you explicitly disable a compiler optimization. I think D docs don't say anything about this. And Walter has said that regarding such things D acts as C. So I am not sure that will be safe in future D.
> 
> Unions are not allowed in SafeD, so I guess they are considered unsafe in D.

Well, it's not like reintepret_cast is the safest thing either.

- Jonathan M Davis
September 20, 2010
Juanjo Alvarez Wrote:

> Unions are not allowed in SafeD, so I guess they are considered unsafe in D.

They're safer in this particular case. Note how original poster forgot about taking and address.
« First   ‹ Prev
1 2