0

This loop is part of a simple pathfinding algorithm. The problem is that when building in Release mode the program never leaves this loop. We move on a 'Table' that's a two dimension array , the StepGrid array maintains the number of steps that are required to reach each corresponding point ( of Table ) from the starting point ( pZero ). This code works fine when running attached to Visual Studio 2012 debugger with both Release and Debug settings. Works fine when compiled with Debug setting . This code does NOT work when compiled with Release settings.

  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;
        }
Frabu
  • 314
  • 2
  • 12
  • 3
    That's a lot of code for us to analyze carefully. Can you not reproduce the problem in a *complete* example which is also *short*? What diagnostics have you performed to check what's different in each case? – Jon Skeet Jul 29 '14 at 09:03
  • Try enabling arithmetic underflow and overflow exceptions and run again in the debugger: http://rionscode.wordpress.com/2013/04/27/enabling-underflow-and-overflow-checking-within-visual-studio/ More here: http://blogs.msdn.com/b/wifry/archive/2007/04/29/visual-studio-and-arithmetic-overflow.aspx – dbc Jul 29 '14 at 09:08
  • I just edited the question. However i verified that the table where the pathfinding is perfomed has the same values in all cases. I noticed that if i add some Console.Write(...) in the loop it terminates but still doesn't give correct result. – Frabu Jul 29 '14 at 09:09
  • I just tried to enable arithmetic underflow and overflow but it didn't generate any exception. – Frabu Jul 29 '14 at 09:15
  • 1
    OK, then try [**/fp:strict**](http://msdn.microsoft.com/en-us/library/e7s85ffb.aspx). Does the problem reproduce when doing the calculations in double precision? – dbc Jul 29 '14 at 09:18
  • 1
    What does CanMoveTo() look like? Are you ever doing exact equality comparison on floats, rather than [comparing with some tolerance](http://floating-point-gui.de/errors/comparison/)? – dbc Jul 29 '14 at 09:34
  • It seems that i can't set compile options in vs2012 for C# projects. – Frabu Jul 29 '14 at 09:35
  • I added CanMoveTo() to the question. – Frabu Jul 29 '14 at 09:39
  • My mistake: /fp:strict is only for c++. More here: http://stackoverflow.com/questions/14864238/coercing-floating-point-to-be-deterministic-in-net – dbc Jul 29 '14 at 09:47
  • 1
    Note that floating point accuracy is slightly off between debug and release, could it be that one of the if-statements that compare floats is never getting close enough to trigger a match? – Lasse V. Karlsen Jul 29 '14 at 09:47
  • `MoveLen` is also missing, and seems important. – BartoszKP Jul 29 '14 at 09:56
  • I tryed modifying the float comparison with this....still infinite cycle. if (Math.Abs(StepGrid[p3.X][p3.Y] - arrivalDist) > 0.05f) – Frabu Jul 29 '14 at 09:57
  • 1
    Ok i found the solution.... if ( StepGrid[pDest.X][pDest.Y] - arrivalDist > 0.1f) Thanks for pointing out the float inconsistency. Actually the answer that someone posted few minutes ago was almost right, i don't know why he deleted it. Lasse V. Karlsen and dbc pointed in the right direction. Thanks. – Frabu Jul 29 '14 at 10:16

1 Answers1

0

Thanks to the guys commenting my question i could find the solution. There is a little inconsistency in floating numbers comparison between Debug and Release due to processor architecture and how these numbers a treated in the registers. The solution is to add a tolerance to the compare so this line

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

should change to

if ( StepGrid[p3.X][p3.Y]  - arrivalDist > epsilon)
Frabu
  • 314
  • 2
  • 12