【问题标题】:Compiling in Release settings introduce infinite cycle在 Release 设置中编译引入无限循环
【发布时间】:2014-07-29 09:00:00
【问题描述】:

此循环是简单寻路算法的一部分。问题是在发布模式下构建时,程序永远不会离开这个循环。 我们移动一个二维数组的“表”,StepGrid 数组维护从起点(pZero)到达每个对应点(表)所需的步数。 当运行附加到具有发布和调试设置的 Visual Studio 2012 调试器时,此代码工作正常。使用调试设置编译时工作正常。 此代码在使用 Release 设置编译时不起作用。

  public List<IntPoint> PathFind(IntPoint pZero, IntPoint pEnd)
        {

            float BIGVALUE = 1000000000f;

            IntPoint p0 = pZero;
            List<IntPoint> res = new List<IntPoint>(); 
            //Initialize StepGrid
            StepGrid = new float[TableWidth][];
            for (int x = 0; x < StepGrid.Length; x++)
            {
                StepGrid[x] = new float[TableHeight];
                for (int y = 0; y < StepGrid[x].Length; y++)
                    StepGrid[x][y] = BIGVALUE;
            }

            List<IntPoint> visitandi = new List<IntPoint>() { p0 };
            List<IntPoint> addendi = new List<IntPoint>();

            if (p0.X > StepGrid.Length || p0.Y > StepGrid[0].Length ||
                pEnd.X > StepGrid.Length || pEnd.Y > StepGrid[0].Length)
                return res;

            StepGrid[p0.X][p0.Y] = 0;

            bool progressMade = true; 
            while (progressMade)
            {
                progressMade = false;
                addendi.Clear();
                for (int cp = 0; cp < visitandi.Count; cp++)
                {
                    float pdist = this.StepGrid[visitandi[cp].X][visitandi[cp].Y];
                      // PossibleMoves  is an array containing all the possible relative moves from a given point. MoveLen contains the steps traveled when performing each one of PossibleMoves
                    for (int pm = 0; pm < PossibleMoves.Length; pm++) 
                    {
                        IntPoint p3 = visitandi[cp] + PossibleMoves[pm];

                        if (CanMoveTo(p3)) //if the pixel is white i can move there
                        {
                            float arrivalDist = pdist + MoveLen[pm];
                            float oldDist = StepGrid[p3.X][p3.Y];
                            if ( StepGrid[p3.X][p3.Y]  > arrivalDist)
                            {
                                if (StepGrid[p3.X][p3.Y] >= BIGVALUE)  
                                    addendi.Add(p3);
                                StepGrid[p3.X][p3.Y] = arrivalDist;
                                progressMade = true;

                            }
                        }
                    }
                }
                if (addendi.Count > 0)
                    progressMade = true;
                visitandi.AddRange(addendi);

            }
         .....
       }

        protected bool CanMoveTo(IntPoint p)
        {
            //Table is byte[,] and is a bitmap gray scale image
            if (p.X < TableWidth && p.Y < TableHeight && p.X > -1 && p.Y > -1)
                if (Table[p.X, p.Y] > BrightnessThreshold)//BrightnessThreshold=70
                    return true;
                else
                    return false;
            return false;
        }

【问题讨论】:

  • 这是一大堆代码,我们需要仔细分析。您能否在同样是 shortcomplete 示例中重现该问题?您执行了哪些诊断来检查每种情况的不同之处?
  • 好的,然后试试/fp:strict。以双精度进行计算时问题是否重现?
  • CanMoveTo() 是什么样的?您是否曾经对浮点数进行精确的相等比较,而不是 comparing with some tolerance
  • 请注意,浮点精度在调试和发布之间略有偏差,可能是比较浮点数的 if 语句之一永远不会接近到足以触发匹配吗?
  • 好的,我找到了解决方案.... if ( StepGrid[pDest.X][pDest.Y] -arrivalDist > 0.1f) 感谢您指出浮动不一致。其实几分钟前有人发布的答案几乎是正确的,我不知道他为什么删除它。 Lasse V. Karlsen 和 dbc 指出了正确的方向。谢谢。

标签: c# .net compiler-optimization


【解决方案1】:

感谢那些评论我的问题的人,我可以找到解决方案。 由于处理器架构以及这些数字在寄存器中的处理方式,Debug 和 Release 之间的浮点数比较存在一些不一致。 解决方案是在比较中添加一个容差,所以这条线

if ( StepGrid[p3.X][p3.Y]  > arrivalDist)

应该改为

if ( StepGrid[p3.X][p3.Y]  - arrivalDist > epsilon)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    相关资源
    最近更新 更多