我有問題,比較調試和發佈時,我的代碼返回不同的結果。我檢查了兩種模式都使用/ fp:精確,所以不應該是問題。我的主要問題是完整的圖像分析(它是一個圖像理解項目)是完全確定性的,它絕對沒有任何隨機性。調試和發佈之間的不同結果
另一個問題是,我的發佈版本實際上總是返回相同的結果(圖像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停用獲得與Release相同的結果。
如果我們看到一些代碼,我們可能會提供更多幫助。一般來說,我的猜測是,你在正常編譯器正確理解的地方使用了鬆散的語法,但是調試器卻沒有。 – rsegal 2012-08-14 14:16:42
使用valgrind檢查是否有可能導致非確定性行爲的內存損壞。 – 2012-08-14 14:17:06
有趣。通常的Heisenbug情況是調試獲得更可靠的結果。 – dmckee 2012-08-14 14:19:09