符号付き浮動小数点変数をDWORDに変換しようとしています...DWORDは別のプログラムで使用されるため、DWORD変数の型が重要です...
まず...署名されたDWORDを署名されていないDWORDとして解釈できますか?
また...署名されたフロートをDWORD(署名済み)に変換するにはどうすればよいですか?
符号付き浮動小数点変数をDWORDに変換しようとしています...DWORDは別のプログラムで使用されるため、DWORD変数の型が重要です...
まず...署名されたDWORDを署名されていないDWORDとして解釈できますか?
また...署名されたフロートをDWORD(署名済み)に変換するにはどうすればよいですか?
DWORD
WindowsAPIで定義された32ビットの符号なし整数型です。「署名されたDWORD」のようなものはありません。おそらくあなたは対応する署名されたタイプを意味します。
C ++では、すべての浮動小数点型(float
、、double
およびlong double
)は符号付き型であるため、「符号付き浮動小数点」について話すのは珍しいことです。おそらく、それは負の値になる可能性があることを意味します。また、負の浮動小数点値を符号なし整数に変換するには、主に2つの可能性があります。
たとえば、浮動小数点値が符号付き整数に変換され、2 n-1.23
の適切な倍数で調整されて、符号なし整数の範囲に入る場合、または
浮動小数点値は、 2 n-1.23
の適切な倍数で調整されて符号なし整数の範囲になり、符号なし整数型に変換されるかのようになります。
これらの手順では、通常、1ずつ異なる結果が得られます。ただし、これをテストすると、Visual C++11.0およびMinGWg++4.7.1で使用される最初の手順になります。そして、どういうわけかこれは標準によって義務付けられていると思います(たとえば、C ++ 11は、負の数の整数除算の結果について最終的に明確なルールを取得しました):
#include <math.h>
#include <windows.h>
using namespace std;
#include <iostream>
DWORD test1()
{
double floatValue = -1.23456;
DWORD const dwValue = floatValue;
cout << dwValue << endl;
return dwValue;
}
DWORD test2()
{
double floatValue = -1.23456;
double reduced = floatValue + (1uLL << 32);
DWORD const dwValue = reduced;
cout << dwValue << endl;
return dwValue;
}
int main()
{
cout << DWORD(-1) << endl;
DWORD const t1 = test1(); cout << 1uLL + DWORD(-1) - t1 << endl;
DWORD const t2 = test2(); cout << 1uLL + DWORD(-1) - t2 << endl;
}
Visual C++11.0およびMinGWg++ 4.7.1を使用した出力:
4294967295 4294967295 1 4294967294 2
一般に、変換(単純な割り当てまたは初期化によって実行される)はデータを失います。
コンパイラはそれについて警告するかもしれません。シャットダウンする方法の1つは、機能する場合と機能しない場合がありますが、を使用しstatic_cast
て変換を明示的にすることです。とにかく、一般的に浮動小数点値はより多くのビットを持っているので、変換は一般的な場合にデータを失う必要DWORD
があることに注意してください。
ただし、aDWORD
に十分なビットがある場合がありfloat
ます。これは、Windowsでは32ビットIEEEであるタイプの値の場合です。
したがって、任意の値を同じビットのfloat
値として表すことができますが、数値間の接続はかなり任意に見えます。そして、それが実際に役立つかどうかは、他のアプリケーションによって異なります。それは何を期待しますか、またはそれは何を処理できますか?DWORD
#include <windows.h>
#include <iostream>
using namespace std;
DWORD dwordBitsFrom( float const number )
{
return *reinterpret_cast< DWORD const* >( &number );
}
float floatFromBits( DWORD const bits )
{
return *reinterpret_cast< float const* >( &bits );
}
int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom( original );
float const reconstituted = floatFromBits( bits );
cout << original << endl;
cout << bits << endl;
cout << reconstituted << endl;
}
Visual C++11およびg++4.7.1(および実際に実用的なWindows C ++コンパイラー)を使用した出力:
-1.23 3214766244 -1.23
ただし、この後者の変換はWindowsで明確に定義されていますが、WindowsルールはC++標準ではサポートされていないことに注意してください。厳密に形式的な観点から、上記のコードをプラットフォームに依存しないものと不適切に見なすと、上記はC++の厳密なエイリアシングルールに違反します。どのg++があなたに知らせてくれてとてもうれしいです:
[D:\ dev \ test] > gnuc --strict-aliasing foo.cpp foo.cpp:関数内'DWORD dwordBitsFrom(float)': foo.cpp:7:55:警告:型のパンニングされたポインターを逆参照すると、厳密なエイリアスのルールが破られます[-Wstrict-aliasing] foo.cpp:関数内'float floatFromBits(DWORD)': foo.cpp:12:53:警告:型のパンニングされたポインターを逆参照すると、厳密なエイリアスのルールが破られます[-Wstrict-aliasing] [D:\ dev \ test] > _
g ++などのばかげたコンパイラを満足させるには、バイトのバッファを介して変換を行う必要があります。警告は、コンパイラが、あなたが表現したものが、適用される可能性のある非常に望ましくない限界最適化と互換性がないことを検出することに関するものであるため、かなり厄介です。そして、それがすべきではないことを検出できるとき、それができないことを警告する代わりに、なぜそれはその望ましくないことをしないのではないのですか?または、なぜそれはまったくそれをしないことができないのですか?誰もそれを望んでいないので。
しかしとにかく、g++をシャットダウンさせるコードは次のとおりです。
#include <windows.h>
#include <iostream>
#include <string.h> // memcpy
using namespace std;
static_assert( sizeof( DWORD ) == sizeof( float ), "y DWORD no same size float?" );
int const nBytes = sizeof( DWORD );
DWORD dwordBitsFrom( float const number )
{
char buffer[nBytes];
DWORD result;
memcpy( buffer, &number, nBytes );
memcpy( &result, buffer, nBytes );
return result;
}
float floatFromBits( DWORD const bits )
{
char buffer[nBytes];
float result;
memcpy( buffer, &bits, nBytes );
memcpy( &result, buffer, nBytes );
return result;
}
int main()
{
float const original = -1.23;
DWORD const bits = dwordBitsFrom( original );
float const reconstituted = floatFromBits( bits );
cout << original << endl;
cout << bits << endl;
cout << reconstituted << endl;
}
もちろん、それははるかに冗長で効率の悪いコードなので、ばかげたコンパイラー(つまりg ++)をシャットダウンする価値はないと判断するかもしれません。個人的には、それだけの価値はないと思います。-fno-strict-aliasing
代わりに、 g ++に言って、を使用してください。reinterpret_cast
それが目的であるため、言語でそれを使用する理由です。
要約すると、他のプログラムが、可能であれば元の浮動小数点値に近い数値DWORD
を期待している場合は、割り当てまたは初期化によって、場合によってはstatic_cast
コンパイラの警告を抑制するために、に変換します。
また、他のプログラムが値のビットを期待している場合は、変換を使用してください。上記のコードは、g ++コンパイラを満足させるために、代わりに、より非効率的で冗長でバグを引き付ける方法を示しています。しかし、私のアドバイスは、それが適切な場合は、g ++警告を抑制することです(g ++コンパイラを実用性に合わせるためのもう1つの便利なオプションは、IMHOが常に使用する必要があります)。float
reinterpret_cast
memcpy
-fno-strict-aliasing
-fwrapv