通过调试语句放置修复了不一致的输出

inconsistent output fixed by debug statement placement

本文关键字:不一致 输出 调试 语句      更新时间:2023-10-16

EDIT:这是一个未初始化的变量…:(

说明:我使用的PointLLA构造函数只通过Latitude和Longitude,但我从未明确将内部Altitude成员变量设置为0。新手失误。。。

原始问题:我的代码中出现了一个错误,这让我很难过。我在计算一个点和一个矩形的角之间的距离。在这种情况下,点位于矩形的中心,所以我应该得到四个相等的距离。我得到三个相等的距离,还有一个几乎相等的不一致的距离值(每次运行都不同)。

如果我有几个关键的调试语句(几乎只是一个std::cout调用)明确地打印出每个矩形角的位置,我就会得到距离的预期值,不一致性就会消失。这是相关代码:

// calculate the minimum and maximum distance to
// camEye within the available lat/lon bounds
Vec3 viewBoundsNE;   convLLAToECEF(PointLLA(maxLat,maxLon),viewBoundsNE);
Vec3 viewBoundsNW;   convLLAToECEF(PointLLA(maxLat,minLon),viewBoundsNW);
Vec3 viewBoundsSW;   convLLAToECEF(PointLLA(minLat,minLon),viewBoundsSW);
Vec3 viewBoundsSE;   convLLAToECEF(PointLLA(minLat,maxLon),viewBoundsSE);
// begin comment this block out, and buggy output
OSRDEBUG << "INFO: NE (" << viewBoundsNE.x
         << "  " << viewBoundsNE.y
         << "  " << viewBoundsNE.z << ")";
OSRDEBUG << "INFO: NW (" << viewBoundsNW.x
         << "  " << viewBoundsNW.y
         << "  " << viewBoundsNW.z << ")";
OSRDEBUG << "INFO: SE (" << viewBoundsSW.x
         << "  " << viewBoundsSW.y
         << "  " << viewBoundsSW.z << ")";
OSRDEBUG << "INFO: SW (" << viewBoundsSE.x
         << "  " << viewBoundsSE.y
         << "  " << viewBoundsSE.z << ")";
// --------------- end
// to get the maximum distance, find the maxima
// of the distances to each corner of the bounding box
double distToNE = camEye.DistanceTo(viewBoundsNE);
double distToNW = camEye.DistanceTo(viewBoundsNW); // <-- inconsistent
double distToSE = camEye.DistanceTo(viewBoundsSE);
double distToSW = camEye.DistanceTo(viewBoundsSW);
std::cout << "INFO: distToNE: " << distToNE << std::endl;
std::cout << "INFO: distToNW: " << distToNW << std::endl; // <-- inconsistent
std::cout << "INFO: distToSE: " << distToSE << std::endl;
std::cout << "INFO: distToSW: " << distToSW << std::endl;
double maxDistToViewBounds = distToNE;
if(distToNW > maxDistToViewBounds)
{   maxDistToViewBounds = distToNW;   }
if(distToSE > maxDistToViewBounds)
{   maxDistToViewBounds = distToSE;   }
if(distToSW > maxDistToViewBounds)
{   maxDistToViewBounds = distToSW;   }
OSRDEBUG << "INFO: maxDistToViewBounds: " << maxDistToViewBounds;

因此,如果我运行上面显示的代码,我将得到如下输出:

INFO: NE (6378137  104.12492  78.289415)
INFO: NW (6378137  -104.12492  78.289415)
INFO: SE (6378137  -104.12492  -78.289415)
INFO: SW (6378137  104.12492  -78.289415)
INFO: distToNE: 462.71851
INFO: distToNW: 462.71851
INFO: distToSE: 462.71851
INFO: distToSW: 462.71851
INFO: maxDistToViewBounds: 462.71851

正如预期的那样。请注意,所有distTo*值都是相同的。我可以一遍又一遍地运行这个程序,我会得到完全相同的输出。但现在,如果我注释掉我在上面代码中注意到的块,我会得到这样的东西:

INFO: distToNE: 462.71851
INFO: distToNW: 463.85601
INFO: distToSE: 462.71851
INFO: distToSW: 462.71851
INFO: maxDistToViewBounds: 463.85601

每次跑步的distToNW略有不同。为什么distToNW而不是其他值?我不知道。再跑几次:

463.06218
462.79352
462.76194
462.74772
463.09787
464.04648

所以。。。这是怎么回事?我试着清理/重建我的项目,看看是否有什么奇怪的事情发生,但无济于事。我将GCC 4.6.3与x86目标一起使用。

编辑:添加相关功能的定义。

void MapRenderer::convLLAToECEF(const PointLLA &pointLLA, Vec3 &pointECEF)
{
    // conversion formula from...
    // hxxp://www.microem.ru/pages/u_blox/tech/dataconvert/GPS.G1-X-00006.pdf
    // remember to convert deg->rad
    double sinLat = sin(pointLLA.lat * K_PI/180.0f);
    double sinLon = sin(pointLLA.lon * K_PI/180.0f);
    double cosLat = cos(pointLLA.lat * K_PI/180.0f);
    double cosLon = cos(pointLLA.lon * K_PI/180.0f);
    // v = radius of curvature (meters)
    double v = ELL_SEMI_MAJOR / (sqrt(1-(ELL_ECC_EXP2*sinLat*sinLat)));
    pointECEF.x = (v + pointLLA.alt) * cosLat * cosLon;
    pointECEF.y = (v + pointLLA.alt) * cosLat * sinLon;
    pointECEF.z = ((1-ELL_ECC_EXP2)*v + pointLLA.alt)*sinLat;
}
    // and from the Vec3 class defn
    inline double DistanceTo(Vec3 const &otherVec) const
    {
        return sqrt((x-otherVec.x)*(x-otherVec.x) +
                    (y-otherVec.y)*(y-otherVec.y) +
                    (z-otherVec.z)*(z-otherVec.z));
    }

不一致的输出表明您正在使用代码中某个未初始化的变量,或者您有一些内存错误(访问已删除的内存、双重删除内存等)。我在您粘贴的代码中没有看到这两种情况,但还有很多其他代码被调用。

Vec3构造函数是否将所有成员变量初始化为零(或某些已知状态)?如果没有,那么就这样做,看看这是否有帮助。如果它们已经初始化,请仔细查看convlAToECEF和PointLLA,看看是否有任何变量没有初始化,或者是否有任何内存错误。

在我看来,DistanceTo函数在某种程度上被窃听了。如果你不能弄清楚发生了什么,那就试一下,然后汇报。

  • 尝试重新排序输出,看看是否仍然是NW错误
  • 试着把NW点重做2-3次,变成不同的变量,看看它们在一次跑步中是否一致
  • 尝试对每个点使用不同的camEye来排除该类中的状态性

尽管我很讨厌它,但你在调试器中经历过吗?我通常倾向于基于stdout的调试,但这似乎会有所帮助。除此之外,你也会因为一些讨厌的事情而产生副作用。

我的猜测是,事实上,你期望(当然是正确的)所有四个值都是相同的,这掩盖了某个地方的"NW/SW/NE/SE"拼写错误。我要做的第一件事是将你在这里得到的块隔离到它自己的函数中(获取框和点坐标),然后在几个不同的位置使用点运行它。我认为这个错误很可能会很快暴露出来。

如果您有调试语句,但在输出之后移动它们,则查看问题是否会再次出现。然后,调试语句可以帮助确定是Vec3对象损坏了,还是来自它的计算

其他想法:在valgrind下运行代码。

仔细检查拆卸输出。