2016-04-26 15 views
3

算術演算なしで「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] 
+0

IEEE仕様の 'NaN'には有効な値が複数あります。 – leppie

+0

DebugとReleaseで同じ結果が得られますか?私は、デバッグではコンピュータでFPUを使用しながらFPUをシミュレートするソフトウェアを使用していると考えています。 PCは何歳ですか?私はtherreがいくつかのUP浮動小数点ユニットの既知の問題だと信じています。 – jdweng

+2

Intelプロセッサのマニュアル:ソースオペランドのいずれかまたは両方がNaNで、浮動小数点の無効操作例外がマスクされている場合、 の結果は表4-7に示すとおりです.SNaNがQNaNに変換されると、 ** SNaNの の最上位小数点ビットを1 **に設定することによって処理されます。また、ソースオペランドの1つがSNaNである場合、浮動小数点 無効操作例外フラグが設定されます。ソースオペランドの場合、x87 FPUオペレーションとSSE/SSE2/SSE3/SSE4.1オペレーションで異なる結果が であるIntel AVXは、SSE/SSE2と同じ ビヘイビアを実行します... " –

答えて

1

私はちょうど答えとして@HansPassantのコメントを翻訳します。

「のx86ジッタが浮動小数点値を処理するためにFPUを使用しています。これは バグではありません。これらのバイト値がfloat型の引数は、単に間違っている受け取るメソッドへの適切な 引数であることをあなたの仮定。」すなわち

、これは(ガベージアウトにおいてごみ)だけGIGOケースです。

関連する問題