C++ 调试和发布之间的不同结果
我的问题是,我的代码在比较调试和发布时返回不同的结果。我检查了这两种模式是否都使用/fp:precise,因此这应该不是问题所在。我的主要问题是,完整的图像分析(它是一个图像理解项目)是完全确定的,其中绝对没有随机性 另一个问题是,我的发布版本实际上总是返回相同的结果(镜像为23.014),而调试返回22到23之间的一些随机值,这是不应该的。我已经检查过它是否与线程相关,但算法中唯一的部分是多线程,它在调试和发布时都返回完全相同的结果 这里还会发生什么 更新1:我现在发现的导致这种行为的代码:C++ 调试和发布之间的不同结果,c++,visual-studio-2010,openmp,release-mode,debug-mode,C++,Visual Studio 2010,Openmp,Release Mode,Debug Mode,我的问题是,我的代码在比较调试和发布时返回不同的结果。我检查了这两种模式是否都使用/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;
}
浮点模式匹配器::GetSADFloatRel(浮点*样本,浮点*比较,int-sampleX,int-compX,int-offX)
{
if(sampleX!=compX)
{
返回50000.0f;
}
浮动结果=0;
float*pTemp1=样本;
浮点*pTemp2=比较+offX;
浮球w1=0.0f;
浮球w2=0.0f;
浮点数w3=0.0f;
对于(int j=0;j#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;
}
}
}
}
}
#用于共享的pragma omp并行(最后、最佳命中、cVal、rad、veneOffset)
对于(int r=0;r<53;++r)
{
对于(int k=0;k<3;++k)
{
对于(int c=0;c<30;++c)
{
for(int o=-1;o last)
{
最佳点击=最后一次;
拉德=(r+8)*0.25f;
cVal=c*2;
veneOffset=(-0.5f+(1.0f/3.0f)*k+(1.0f/3.0f)/2.0f);
if(晶圆厂(偏移量)<0.001)
veneOffset=0.0f;
}
last=GetSADFloatRel(输入和f采样(偏移),w*4+1,w*4+1,0);
如果(最佳点击>最后一次)
{
最佳点击=最后一次;
拉德=(r+8)*0.25f;
cVal=c*2;
veneOffset=(-0.5f+(1.0f/3.0f)*k+(1.0f/3.0f)/2.0f);
if(晶圆厂(偏移量)<0.001)
veneOffset=0.0f;
}
}
}
}
}
注意:在释放模式和OpenMP激活的情况下,我得到的结果与禁用OpenMP相同。调试模式和OpenMP激活会得到不同的结果,OpenMP停用会得到与发布相同的结果。至少有两种可能性:
如果您在Windows上,则不可用(遗憾的是),但您可以查找替代列表。需要仔细检查的一件事是所有变量都已初始化。很多时候,未优化的代码(调试模式)将初始化内存。我会说变量初始化在调试中,而不是在发布中。但您的结果不会支持这一点(发布时的可靠结果) 您的代码是否依赖于任何特定的偏移量或大小?调试生成将在某些分配周围放置保护字节 它可能与浮点相关吗 调试浮点堆栈不同于为提高效率而构建的版本
看看这里:几乎任何未定义的行为都可以解释这一点:未初始化 变量、恶意指针、同一对象的多个修改 在没有中间序列点的情况下 结果有时是不可产生的,这在某种程度上有助于 未初始化的变量,但也可能因指针问题或 限制错误 请注意,优化可能会改变结果,尤其是在Intel上。 优化可以更改哪些中间值溢出到内存,以及 如果您没有仔细使用括号,甚至计算顺序 用一种表情。(我们都知道,在机器浮点中,
(a+
b) +c)!=a+(b+c)
)结果仍然应该是确定的:
您将根据优化程度得到不同的结果,
但是对于任何一组优化标志,您都应该得到相同的结果。要详细说明我的评论,以下代码很可能是问题的根源:
#pragma omp parallel for shared(last, bestHit, cVal, rad, veneOffset)
{
...
last = GetSADFloatRel(adapted, &fSamples.at(offset), 4*w+1, 4*w+1, 0);
if(bestHit > last)
{
last
仅在再次读取之前分配给,因此如果您确实需要并行区域外最后一次迭代的值,则它很适合作为lastprivate
变量。否则,只需将其设置为私有
获取
#pragma omp critical
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;
}
#pragma omp parallel private(last)
{
int rBest = 0, kBest = 0, cBest = 0;
float myBestHit = bestHit;
#pragma omp for
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(myBestHit > last)
{
myBestHit = last;
rBest = r;
cBest = c;
kBest = k;
}
last = GetSADFloatRel(input, &fSamples.at(offset), w * 4 + 1, w * 4 + 1, 0);
if(myBestHit > last)
{
myBestHit = last;
rBest = r;
cBest = c;
kBest = k;
}
}
}
}
}
#pragma omp critical
if (bestHit > myBestHit)
{
bestHit = myBestHit;
rad = (rBest+8)*0.25f;
cVal = cBest * 2;
veneOffset =(-0.5f + (1.0f / 3.0f) * kBest + (1.0f / 3.0f) / 2.0f);
if(fabs(veneOffset) < 0.001)
veneOffset = 0.0f;
}
}