【发布时间】:2012-08-14 14:14:17
【问题描述】:
我的问题是在比较调试和发布时我的代码返回不同的结果。我检查了两种模式都使用 /fp:precise,所以这应该不是问题。我对此的主要问题是完整的图像分析(它是一个图像理解项目)是完全确定的,其中绝对没有随机性。
另一个问题是我的发布版本实际上总是返回相同的结果(图像为 23.014),而调试返回 22 到 23 之间的一些随机值,这不应该是.我已经检查过它是否可能与线程相关,但是算法中唯一的多线程部分在调试和发布时返回完全相同的结果。
这里还可能发生什么?
更新1:我现在发现的代码导致了这种行为:
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;
}
更新 2: 这不能用 32 位代码重现。虽然 debug 和 release 代码在 32bit 下总是会产生相同的值,但它仍然与 64bit release 版本不同,并且 64bit debug 仍然返回一些完全随机的值。
更新3: 好的,我发现它肯定是由 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 相同的结果。 Debug 模式和 OpenMP 激活得到不同的结果,OpenMP deactivated 得到与 Release 相同的结果。
【问题讨论】:
-
如果我们看到一些代码,我们可能会提供更多帮助。一般来说,我的猜测是您在普通编译器可以正确理解的地方使用了松散的语法,但调试器却没有。
-
使用 valgrind 检查您是否有可能导致不确定行为的内存损坏。
-
有趣。通常的 Heisenbug 情况是调试得到更可靠的结果。
-
闻起来像未定义的行为......
-
发布和调试只是不同的项目选项集——您可以一一更改选项,直到找到使发布输出与调试输出匹配的选项。但是我们没有足够的信息来告诉你发生了什么。打印出中间输出,分而治之... 8 - )
标签: c++ visual-studio-2010 openmp release-mode debug-mode