未定義のビヘイビアを呼び出さずにfloatからビットを抽出しようとしています。ここに私の最初の試みている:私はそれを理解したよう浮動小数点ビットと厳密なエイリアシング
unsigned foo(float x)
{
unsigned* u = (unsigned*)&x;
return *u;
}
、これは右、厳格なエイリアシング規則に動作することが保証されていませんか?文字ポインタを使って中間ステップを取るとうまくいくのでしょうか?
unsigned bar(float x)
{
char* c = (char*)&x;
unsigned* u = (unsigned*)c;
return *u;
}
自分で個々のバイトを抽出する必要がありますか?
unsigned baz(float x)
{
unsigned char* c = (unsigned char*)&x;
return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
}
もちろん、これはエンディアンに依存するという欠点がありますが、私はそれで生きることができます。
ユニオンハックは間違いなく未定義の動作です。
unsigned uni(float x)
{
union { float f; unsigned u; };
f = x;
return u;
}
完全版のため、ここには参照バージョンfoo
があります。また、未定義の動作、右ですか?
unsigned ref(float x)
{
return (unsigned&)x;
}
だから、それは(もちろん、両方が 32ビット幅であると仮定)フロートからビットを抽出することができますか?
編集:そしてここには、Gozによって提案されたmemcpy
バージョンがあります。多くのコンパイラは、まだstatic_assert
をサポートしていないので、私はいくつかのテンプレートメタプログラミングでstatic_assert
を交換した:本当にすべての問題を回避するための唯一の方法について
template <bool, typename T>
struct requirement;
template <typename T>
struct requirement<true, T>
{
typedef T type;
};
unsigned bits(float x)
{
requirement<sizeof(unsigned)==sizeof(float), unsigned>::type u;
memcpy(&u, &x, sizeof u);
return u;
}
私は本当に非常に最初のアプローチの問題が表示されていないさまざまな種類のアクセス左辺値のない使用がないので、次は、エイリアシング規則に違反しない - あなたも持っていませんが2つのポインターが同じオブジェクトを指しています。コンパイル時にsizeof(float)== sizeof(unsigned)をアサートすることが望ましいかもしれませんが、うまくいくはずです。私はまた、(私は再びサイズを確認するだろうが)組合のハックに問題が表示されません。しかし、私は気づいていないいくつかのあいまいなルールがあると確信しています。座って、人々が私を間違っていると証明するのを待ちましょう! – EboMike
@Ebomike:最初の方法は、厳密なエイリアシング規則に反します。これを読んでください:http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html – Goz
ありがとう、私は誰かが私が間違っていることを証明するだろうと知っていた:) – EboMike