だから私の質問は、Vector2.Normalize(v)を呼び出した結果が、34回呼び出した後、<0.9750545、-0.22196561>から<0.97505456、-0.22196563>に変化するのはなぜですか?
それではまず、変更が発生する理由を説明します。これらの値を計算するコードも変更されるため、変更が観察されます。
コードの最初の実行の早い段階でWinDbgに侵入し、Normalize
edベクトルを計算するコードに少し入ると、次のアセンブリが表示されます(多かれ少なかれ、一部を切り詰めました)。
movss xmm0,dword ptr [rax]
movss xmm1,dword ptr [rax+4]
lea rax,[rsp+40h]
movss xmm2,dword ptr [rax]
movss xmm3,dword ptr [rax+4]
mulss xmm0,xmm2
mulss xmm1,xmm3
addss xmm0,xmm1
sqrtss xmm0,xmm0
lea rax,[rsp+40h]
movss xmm1,dword ptr [rax]
movss xmm2,dword ptr [rax+4]
xorps xmm3,xmm3
movss dword ptr [rsp+28h],xmm3
movss dword ptr [rsp+2Ch],xmm3
divss xmm1,xmm0
movss dword ptr [rsp+28h],xmm1
divss xmm2,xmm0
movss dword ptr [rsp+2Ch],xmm2
mov rax,qword ptr [rsp+28h]
約30回実行すると(この数値については後で詳しく説明します)、次のコードになります。
vmovsd xmm0,qword ptr [rsp+70h]
vmovsd qword ptr [rsp+48h],xmm0
vmovsd xmm0,qword ptr [rsp+48h]
vmovsd xmm1,qword ptr [rsp+48h]
vdpps xmm0,xmm0,xmm1,0F1h
vsqrtss xmm0,xmm0,xmm0
vinsertps xmm0,xmm0,xmm0,0Eh
vshufps xmm0,xmm0,xmm0,50h
vmovsd qword ptr [rsp+40h],xmm0
vmovsd xmm0,qword ptr [rsp+48h]
vmovsd xmm1,qword ptr [rsp+40h]
vdivps xmm0,xmm0,xmm1
vpslldq xmm0,xmm0,8
vpsrldq xmm0,xmm0,8
vmovq rcx,xmm0
さまざまなオペコード、さまざまな拡張子-SSEとAVX、そしておそらく、さまざまなオペコードを使用すると、計算の精度が異なります。
それでは、その理由について詳しく説明しましょう。.NET Core(バージョンについては不明-3.0を想定-2.1でテスト済み)には、「Tiered JITコンパイル」と呼ばれるものがあります。それが最初に行うのは、高速で生成されるコードを生成することですが、非常に最適ではない可能性があります。後でランタイムがコードの使用率が高いことを検出したときにのみ、新しい、より最適化されたコードを生成するために追加の時間を費やします。これは.NET Coreの新しい機能であるため、そのような動作は以前には観察されない可能性があります。
また、なぜ34呼び出しですか?これは階層化されたコンパイルが開始されるしきい値であるため、30回程度実行されると予想されるため、これは少し奇妙です。定数はcoreclrのソースコードで確認できます。多分それが起動するときにいくつかの追加の変動性があります。
これが事実であることset COMPlus_TieredCompilation=0
を確認するために、実行を再度発行して確認することにより環境変数を設定することにより、階層型コンパイルを無効にすることができます。奇妙な効果はなくなりました。
C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ FloatMultiple.exe
0000: <0,9750545 -0,22196561>
0001: <0,9750545 -0,22196561>
0002: <0,9750545 -0,22196561>
...
0032: <0,9750545 -0,22196561>
0033: <0,9750545 -0,22196561>
0034: <0,9750545 -0,22196561>
0035: <0,97505456 -0,22196563>
0036: <0,97505456 -0,22196563>
^C
C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ set COMPlus_TieredCompilation=0
C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ FloatMultiple.exe
0000: <0,97505456 -0,22196563>
0001: <0,97505456 -0,22196563>
0002: <0,97505456 -0,22196563>
...
0032: <0,97505456 -0,22196563>
0033: <0,97505456 -0,22196563>
0034: <0,97505456 -0,22196563>
0035: <0,97505456 -0,22196563>
0036: <0,97505456 -0,22196563>
これは予期されたものですか、それとも言語/ランタイムのバグですか?
これに関してすでにバグが報告されています- 問題1119