デバッグとリリースを比較すると、コードが異なる結果を返すという問題があります。両方のモードが /fp:precise を使用していることを確認したので、問題にはなりません。これに関する主な問題は、完全な画像分析 (画像理解プロジェクト) が完全に決定論的であり、ランダムなものがまったくないことです。
これに関するもう 1 つの問題は、私のリリース ビルドが実際には常に同じ結果 (イメージの場合は 23.014) を返すという事実ですが、デバッグは 22 から 23 の間のランダムな値を返しますが、これは本来あるべきではありません。スレッドに関連する可能性があるかどうかは既に確認しましたが、マルチスレッドのアルゴリズムの唯一の部分は、デバッグとリリースの両方でまったく同じ結果を返します。
ここで他に何が起こっているのでしょうか?
Update1:この動作の原因であることがわかったコード:
float PatternMatcher::GetSADFloatRel(float* sample, float* compared, int sampleX, int compX, int offX)
{
if (sampleX != compX)
{
return 50000.0f;
}
float result = 0;
float* pTemp1 = sample;
float* pTemp2 = compared + offX;
float w1 = 0.0f;
float w2 = 0.0f;
float w3 = 0.0f;
for(int j = 0; j < sampleX; j ++)
{
w1 += pTemp1[j] * pTemp1[j];
w2 += pTemp1[j] * pTemp2[j];
w3 += pTemp2[j] * pTemp2[j];
}
float a = w2 / w3;
result = w3 * a * a - 2 * w2 * a + w1;
return result / sampleX;
}
Update2: これは 32 ビット コードでは再現できません。デバッグ コードとリリース コードは常に 32 ビットで同じ値になりますが、それでも 64 ビット リリース バージョンとは異なり、64 ビット デバッグは完全にランダムな値を返します。
Update3: わかりました。確かに OpenMP が原因であることがわかりました。無効にすると、正常に動作します。(Debug と Release の両方で同じコードを使用し、両方とも OpenMP がアクティブになっています)。
以下は私に問題を引き起こしているコードです:
#pragma omp parallel for shared(last, bestHit, cVal, rad, veneOffset)
for(int r = 0; r < 53; ++r)
{
for(int k = 0; k < 3; ++k)
{
for(int c = 0; c < 30; ++c)
{
for(int o = -1; o <= 1; ++o)
{
/*
r: 2.0f - 15.0f, in 53 steps, representing the radius of blood vessel
c: 0-29, in steps of 1, representing the absorption value (collagene)
iO: 0-2, depending on current radius. Signifies a subpixel offset (-1/3, 0, 1/3)
o: since we are not sure we hit the middle, move -1 to 1 pixels along the samples
*/
int offset = r * 3 * 61 * 30 + k * 30 * 61 + c * 61 + o + (61 - (4*w+1))/2;
if(offset < 0 || offset == fSamples.size())
{
continue;
}
last = GetSADFloatRel(adapted, &fSamples.at(offset), 4*w+1, 4*w+1, 0);
if(bestHit > last)
{
bestHit = last;
rad = (r+8)*0.25f;
cVal = c * 2;
veneOffset =(-0.5f + (1.0f / 3.0f) * k + (1.0f / 3.0f) / 2.0f);
if(fabs(veneOffset) < 0.001)
veneOffset = 0.0f;
}
last = GetSADFloatRel(input, &fSamples.at(offset), w * 4 + 1, w * 4 + 1, 0);
if(bestHit > last)
{
bestHit = last;
rad = (r+8)*0.25f;
cVal = c * 2;
veneOffset = (-0.5f + (1.0f / 3.0f) * k + (1.0f / 3.0f) / 2.0f);
if(fabs(veneOffset) < 0.001)
veneOffset = 0.0f;
}
}
}
}
}
注: リリース モードで OpenMP を有効にすると、OpenMP を無効にした場合と同じ結果になります。デバッグ モードで OpenMP をアクティブにすると異なる結果が得られ、OpenMP を非アクティブにするとリリースと同じ結果が得られます。