什么是一种正确的方式类型 - 将一个float到一个int,反之亦然? [英] What's a proper way of type-punning a float to an int and vice-versa?

查看:170
本文介绍了什么是一种正确的方式类型 - 将一个float到一个int,反之亦然?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码通过一些bit hack执行快速的平方根运算。
该算法可能是由Silicon Graphics在20世纪90年代初开发的,它也出现在Quake 3中。
更多信息



但是,我从GCC C ++编译器获得以下警告:取消引用类型冲突指针将破坏严格别名规则



应该使用<$ c在这种情况下,是否需要改变$ c> static_cast , reinterpret_cast dynamic_cast

  float InverseSquareRoot(float x)
{
float xhalf = 0.5f * x;
int32_t i = *(int32_t *)& x;
i = 0x5f3759df - (i> 1);
x = *(float *)& i;
x = x *(1.5f - xhalf * x * x);
return x;
}






UPDATE



根据答案,我制作了一些C ++ 11ish伪函数,以方便应用。 b
$ b

C99版本
(但编译器支持的最多,理论上可能是某些未定义的行为)

  template< typename T,typename U> 
inline T pseudo_cast(const U& x)
{
union {U from; T to; } __x = {x};
return __x.to;
}

通用版本
接受的答案)



投放大小相同的类型:

  #include< cstring> 

template< typename T,typename U>
inline T pseudo_cast(const U& x)
{
static_assert(sizeof(T)== sizeof(U),pseudo_cast不能处理不同大小的类型);

T to;
std :: memcpy(& to,& x,sizeof(T));
return to;
}

投放任何尺寸的类型:

  #include< cstring> 

template< typename T,typename U>
inline T pseudo_cast(const U& x)
{
T to = T(0);
std :: memcpy(& to,& x,(sizeof(T)< sizeof(U))?sizeof(T):sizeof(U)
return to;
}

使用方式: b
$ b

  float f = 3.14f; 
uint32_t u = pseudo_cast< uint32_t>(f);


解决方案

使用 memcpy

  float xhalf = 0.5f * x; 
uint32_t i;
assert(sizeof(x)== sizeof(i));
std :: memcpy(& i,& x,sizeof(i));
i = 0x5f375a86 - (i> 1);
std :: memcpy(& x,& i,sizeof(i));
x = x *(1.5f - xhalf * x * x);
return x;

原始代码尝试初始化 int32_t 通过首先通过 int32_t 指针访问 float 对象,这是规则被破坏的地方。 C风格的转换相当于 reinterpret_cast ,所以改为 reinterpret_cast 不会有太大的区别。 p>

使用memcpy的重要区别是,字节从 float 复制到 int32_t ,但是从不通过 int32_t lvalue访问 float 对象,因为 memcpy 接受指向void的指针,它的内部是神奇的,不破坏别名规则。


The code below performs a fast inverse square root operation by some bit hacks. The algorithm was probably developed by Silicon Graphics in early 1990's and it's appeared in Quake 3 too. more info

However I get the following warning from GCC C++ compiler: dereferencing type-punned pointer will break strict-aliasing rules

Should I use static_cast, reinterpret_cast or dynamic_cast instead in such situations?

float InverseSquareRoot(float x)
{
    float xhalf = 0.5f*x;
    int32_t i = *(int32_t*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    return x;
}


UPDATE

Based on the answers I made some C++11ish pseudo-cast function for ease of application.

C99 version (however the most compiler support it, theoretically could be undefined behaviour in some)

template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
    union { U from; T to; } __x = {x};
    return __x.to;
}

Universal versions (based on the accepted answer)

Cast types with the same size:

#include <cstring>

template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
    static_assert(sizeof(T) == sizeof(U), "pseudo_cast can't handle types with different size");

    T to;
    std::memcpy(&to, &x, sizeof(T));
    return to;
}

Cast types with any sizes:

#include <cstring>

template <typename T, typename U>
inline T pseudo_cast(const U &x)
{
    T to = T(0);
    std::memcpy(&to, &x, (sizeof(T) < sizeof(U)) ? sizeof(T) : sizeof(U));
    return to;
}

Use it like:

float f = 3.14f;
uint32_t u = pseudo_cast<uint32_t>(f);

解决方案

Forget casts. Use memcpy.

float xhalf = 0.5f*x;
uint32_t i;
assert(sizeof(x) == sizeof(i));
std::memcpy(&i, &x, sizeof(i));
i = 0x5f375a86 - (i>>1);
std::memcpy(&x, &i, sizeof(i));
x = x*(1.5f - xhalf*x*x);
return x;

The original code tries to initialize the int32_t by first accessing the float object through an int32_t pointer, which is where the rules are broken. The C-style cast is equivalent to a reinterpret_cast, so changing it to reinterpret_cast would not make much difference.

The important difference when using memcpy is that the bytes are copied from the float into the int32_t, but the float object is never accessed through an int32_t lvalue, because memcpy takes pointers to void and its insides are "magical" and don't break the aliasing rules.

这篇关于什么是一种正确的方式类型 - 将一个float到一个int,反之亦然?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆