算術演算なしで「bytes [4] - > float number - > bytes [4]」変換を行います。 バイトでは、私はIEEE-754形式で1つの精度の数値を持っています(数値は4バイト、マシンのリトルエンディアンの順)。 bytesが逐語ではなくNaN値を表すときに問題が発生しました。 例えば:浮動小数点数のNaN値をバイナリ形式からその逆に変換すると、不一致が発生する
{として0x1B、0xC4、0xAB、0x7Fを} - >のNaN - 再生のため> {として0x1B、0xC4、0xEB、0x7Fを}
コード:
using System;
using System.Linq;
namespace StrangeFloat
{
class Program
{
private static void PrintBytes(byte[] array)
{
foreach (byte b in array)
{
Console.Write("{0:X2}", b);
}
Console.WriteLine();
}
static void Main(string[] args)
{
byte[] strangeFloat = { 0x1B, 0xC4, 0xAB, 0x7F };
float[] array = new float[1];
Buffer.BlockCopy(strangeFloat, 0, array, 0, 4);
byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
PrintBytes(strangeFloat);
PrintBytes(bitConverterResult);
bool isEqual = strangeFloat.SequenceEqual(bitConverterResult);
Console.WriteLine("IsEqual: {0}", isEqual);
}
}
}
結果(https://ideone.com/p5fsrE):
1BC4AB7F
1BC4EB7F
IsEqual: False
この動作はプラットフォームおよび構成から:このコードは、すべての構成またはx86/Debugで、x64でエラーのない数値を変換します。 x86/Releaseでは、エラーが存在します。私は
float f = array[0];
byte[] bitConverterResult = BitConverter.GetBytes(f);
に
byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
を変更した場合
また、それは、x86 /デバッグにもerroneus。
私は問題を調査し、コンパイラが浮動小数点値(FLD/FST命令)を保持するためにFPUレジスタ(!)を使用するx86コードを生成することを発見しました。しかし、FPUは、仮数の上位ビットを0ではなく1に設定しています。したがって、ロジックは変更なしで値を渡すだけですが、値を変更します。 x64プラットフォームの場合xmm0レジスタ(SSE)が使用され、正常に動作します。
[質問]
、これはどのようなものです:それはどこかがNaNのために未定義の動作を文書化されれる値またはJIT /最適化バグ?
算術演算が行われていないときにコンパイラがFPUとSSEを使用するのはなぜですか?
更新1
デバッグ構成 - 副作用なしスタックを介してパス値 - 正しい結果:
byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
02232E45 mov eax,dword ptr [ebp-44h]
02232E48 cmp dword ptr [eax+4],0
02232E4C ja 02232E53
02232E4E call 71EAC65A
02232E53 push dword ptr [eax+8] // eax+8 points to "1b c4 ab 7f" CORRECT!
02232E56 call 7136D8E4
02232E5B mov dword ptr [ebp-5Ch],eax // eax points to managed
// array data "fc 35 d7 70 04 00 00 00 __1b c4 ab 7f__" and this is correct
02232E5E mov eax,dword ptr [ebp-5Ch]
02232E61 mov dword ptr [ebp-48h],eax
盤構成 - オプティマイザまたはJITは奇妙なパスを行いますFPU経由でレジスタにデータをブレークする - が正しくない
byte[] bitConverterResult = BitConverter.GetBytes(array[0]);
00B12DE8 cmp dword ptr [edi+4],0
00B12DEC jbe 00B12E3B
00B12DEE fld dword ptr [edi+8] // edi+8 points to "1b c4 ab 7f"
00B12DF1 fstp dword ptr [ebp-10h] // ebp-10h points to "1b c4 eb 7f" (FAIL)
00B12DF4 mov ecx,dword ptr [ebp-10h]
00B12DF7 call 70C75810
00B12DFC mov edi,eax
00B12DFE mov ecx,esi
00B12E00 call dword ptr ds:[4A70860h]
IEEE仕様の 'NaN'には有効な値が複数あります。 – leppie
DebugとReleaseで同じ結果が得られますか?私は、デバッグではコンピュータでFPUを使用しながらFPUをシミュレートするソフトウェアを使用していると考えています。 PCは何歳ですか?私はtherreがいくつかのUP浮動小数点ユニットの既知の問題だと信じています。 – jdweng
Intelプロセッサのマニュアル:ソースオペランドのいずれかまたは両方がNaNで、浮動小数点の無効操作例外がマスクされている場合、 の結果は表4-7に示すとおりです.SNaNがQNaNに変換されると、 ** SNaNの の最上位小数点ビットを1 **に設定することによって処理されます。また、ソースオペランドの1つがSNaNである場合、浮動小数点 無効操作例外フラグが設定されます。ソースオペランドの場合、x87 FPUオペレーションとSSE/SSE2/SSE3/SSE4.1オペレーションで異なる結果が であるIntel AVXは、SSE/SSE2と同じ ビヘイビアを実行します... " –