Like Tree1Likes
  • 1 Post By dmh2000

Comparing 2 floats, off by 1

This is a discussion on Comparing 2 floats, off by 1 within the C Programming forums, part of the General Programming Boards category; I understand that 1.2 cannot be represented perfectly with a float. But I am getting an off by 1 (or ...

  1. #1
    Registered User javaeyes's Avatar
    Join Date
    Feb 2012
    Posts
    153

    Comparing 2 floats, off by 1

    I understand that 1.2 cannot be represented perfectly with a float. But I am getting an off by 1 (or really off by .99998) error and I am convinced it not due to array indexes but by floating point weirdness. Is there some reason that the mantissa would be disregarded in a greater than comparison. e.g.
    if (2.999 < 2.0) would evaluate to true?
    Last edited by javaeyes; 11-29-2012 at 10:33 AM. Reason: mistake

  2. #2
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,484
    You would need to post some code we can compile and try for ourselves.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,245
    You'll never get that sort of thing with floating point comparisons (assuming the hardware or software implementation of floating point and floating point operations is not buggy).

    The more likely explanation is a mismatch between programmer expectations and algorithm stability. Do a numerical calculation repeatedly, then errors accumulate. But, if doing the same calculation by hand, the result has no error. The real cause is a programmer error, but programmers have a tendency to blame the technology rather than themselves.
    Right 98% of the time, and don't care about the other 3%.

  4. #4
    Super Moderator
    Join Date
    Sep 2001
    Posts
    4,913
    Being off by exactly 1 sounds to me like somewhere in your computation a float is getting converted to an int (going from *.999999 to *) and then being converted back to a float.

  5. #5
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,299
    This is quite simply a bug in your code. You'll need to show the code.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  6. #6
    Registered User javaeyes's Avatar
    Join Date
    Feb 2012
    Posts
    153
    Well if anyone is willing to look through it, it compiles with no warnings with -Wall, and is very close in its prediction. First the program reads in the actual NFL scores from week 1, it then calculates offense and defense vectors for each team by adding or subtracting delta from the vector based on the prediction. I've only included the data for week 1, so in theory the prediction should be perfect. But the actual score is Titans: 13 Patriots: 34, predicted score 13.979 to 34.999.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #define TOTALGAMES 16 
    #define TOTALTEAMS 32 
    #define VECTORLENGTH 4 
    
    typedef struct
    {
      int week;
      int hometeam;
      int awayteam;
      float homescore;
      float awayscore;
    } game_t;
     
     
     
    game_t * init_games(game_t *gamePtr)
    {
      static game_t game[TOTALGAMES] = {
        {1,15,11,17.0,24.0} ,
        {1,29,12,30.0,10.0} ,
        {1,28,30,13.0,34.0} ,
        {1,18,22,27.0,23.0} ,
        {1,25,24,32.0,40.0} ,
        {1,5,13,16.0,17.0} ,
        {1,9,14,24.0,40.0} ,
        {1,17,3,48.0,28.0} ,
        {1,31,16,26.0,23.0} ,
        {1,7,26,20.0,16.0} ,
        {1,6,20,16.0,10.0} ,
        {1,19,0,22.0,30.0} ,
        {1,4,27,31.0,19.0} ,
        {1,23,2,44.0,13.0} ,
        {1,21,8,14.0,22.0} ,
        {1,1,10,41.0,21.0}
        
      };
     
      gamePtr = game;
      return gamePtr;
    }
    
    float getAverageHome(game_t *gamePointer)
    {
      int i;
      float hometotal = 0;
        for (i = 0 ; i < TOTALGAMES ; i++)
        {
          hometotal += gamePointer[i].homescore;
        }
        float homeaverage = hometotal / (TOTALGAMES * 1.0);
        //printf("%f",awayaverage);
        return homeaverage;
    }
    
    float getAverageAway(game_t *gamePointer)
    {
      int i;
      float awaytotal = 0;
        for (i = 0 ; i < TOTALGAMES ; i++)
        {
          awaytotal += gamePointer[i].awayscore;
        }
        float awayaverage = awaytotal / (TOTALGAMES * 1.0);
        //printf("%f",awayaverage);
        return awayaverage;
    }
    
    float getAverage(game_t *gamePointer)
    {
      int i;
      float total = 0;
      int count=0;
        for (i = 0 ; i < TOTALGAMES ; i++)
        {
          total += gamePointer[i].homescore;
          total += gamePointer[i].awayscore;
          count += 2;
        }
        float homeaverage = total / (count * 1.0);
        //printf("%f",homeaverage);
        return homeaverage;
    }
    
    void runVectors(game_t *gamePointer , float teamoffense[VECTORLENGTH][TOTALTEAMS],float teamdefense[VECTORLENGTH][TOTALTEAMS], float homeaverage , float awayaverage)
    {
      float initdelta = .1;
      float  delta = initdelta;
      int i,j,k,loop;
      float tohtxtdat,toatxtdht;
      float epsilon = .000001;
      for (j = 0 ; j < VECTORLENGTH ; j++)
        {
          //      delta = initdelta / ( pow(10, (j)));
          
          for (loop = 0 ; loop < 100000 ; loop++)
        {
          for (i = 0 ; i < TOTALGAMES ; i++)
            {
              tohtxtdat = 0;
              toatxtdht = 0;
              for (k = 0 ; k <= j ; k++)  // FIND THE SUM OF OFFENSE VECTOR TIMES DEFENSE VECTOR
            {
              tohtxtdat += teamoffense[k][gamePointer[i].hometeam]*teamdefense[k][gamePointer[i].awayteam];
              toatxtdht += teamoffense[k][gamePointer[i].awayteam]*teamdefense[k][gamePointer[i].hometeam];
            }    
              // IF THE PREDICTED SCORE, BASED ON THE VECTORS IS HIGHER THAN THE ACTUAL SCORE, THEN DECREASE THE OFFENSE AND DEFENSE VECTORS
              if ( ((tohtxtdat * homeaverage) >  gamePointer[i].homescore) && (abs((tohtxtdat*homeaverage)-gamePointer[i].homescore) > epsilon)   )
            {
              teamoffense[j][gamePointer[i].hometeam] -= delta;
              teamdefense[j][gamePointer[i].awayteam] -= delta;
            }
    
          if ( ((tohtxtdat * homeaverage) <  gamePointer[i].homescore) && (abs((tohtxtdat*homeaverage)-gamePointer[i].homescore)>epsilon)   )
            {
              teamoffense[j][gamePointer[i].hometeam] += delta;
              teamdefense[j][gamePointer[i].awayteam] += delta;
            }
          
          if ( ((toatxtdht * awayaverage) >  gamePointer[i].awayscore) && (abs((toatxtdht*awayaverage)-gamePointer[i].awayscore)>epsilon)  )
            {
              teamoffense[j][gamePointer[i].awayteam] -= delta;
              teamdefense[j][gamePointer[i].hometeam] -= delta;
            }
          
          if ( ((toatxtdht * awayaverage) <  gamePointer[i].awayscore) && (abs((toatxtdht*awayaverage)-gamePointer[i].awayscore)>epsilon)  )
            {
              teamoffense[j][gamePointer[i].awayteam] += delta;
              teamdefense[j][gamePointer[i].hometeam] += delta;
            }
            }
        }
        }
    }
    
    int main(void)
    {
      float teamoffense[VECTORLENGTH][TOTALTEAMS];
      float teamdefense[VECTORLENGTH][TOTALTEAMS];
      int i,j;
      for (i = 0 ; i < VECTORLENGTH ; i++)
        {
          for (j = 0 ; j < TOTALTEAMS ; j++)
        {
          teamoffense[i][j] = 1.0;     
          teamdefense[i][j] = 1.0; // INITIALIZE VECTORES TO 1.0
        }
        }
      
      printf("FOOTBALL: \n");
      game_t * gamePointer = NULL;
      gamePointer = init_games(gamePointer); //LOAD THE ACTUAL NFL WEEK 1 SCORES
      //float homeaverage = getAverageHome(gamePointer);
      //float awayaverage = getAverageAway(gamePointer);
      float homeaverage = 1.0; // SET THIS TO 1.0 FOR TESTING
      float awayaverage = 1.0;
      runVectors(gamePointer , teamoffense ,teamdefense, homeaverage , awayaverage);
      int home,away,v;
      away = 28; // TITANS   -- ACTUAL SCORE OF GAME: AWAY TITANS: 13 --  HOME PATRIOTS: 34
      home = 30; // N.E. PATRIOTS
      float homescore=0,awayscore=0;
      for (v = 0 ; v < VECTORLENGTH ; v++)
        {
          homescore += (teamoffense[v][home]*teamdefense[v][away]);
          awayscore += (teamoffense[v][away]*teamdefense[v][home]);
        }
        homescore = (homescore * homeaverage);
        awayscore = (awayscore * awayaverage);
    
        printf("------------\n");
        printf("Away %i : %f \n",away,awayscore);
        printf("Home %i : %f \n",home,homescore); // PREDICTION IS 13.97, TO 34.998
        printf("------------ \n");
    
    
        printf("%f\n",teamoffense[0][home]);
        printf("%f\n",teamdefense[0][away]);
        printf("-----\n");
        printf("%f\n",teamoffense[1][home]);
        printf("%f\n",teamdefense[1][away]);
        printf("-----\n");
        printf("%f\n",teamoffense[2][home]);
        printf("%f\n",teamdefense[2][away]);
        printf("-----\n");
        printf("%f\n",teamoffense[3][home]);
        printf("%f\n",teamdefense[3][away]);
    
        
        printf("homeavg %f\n",homeaverage);
        printf("awayavg2 %f\n",awayaverage);
    
        return 0;
    }

  7. #7
    Registered User
    Join Date
    Mar 2011
    Posts
    546
    don't know if this is your problem but it looks suspicious since epsilon is a floating point value.

    abs((toatxtdht*awayaverage)-gamePointer[i].awayscore) > epsilon

    'abs' in the standard library returns an int, not a float, so if that matters here you will get truncation of the fractional part. I would have thought the compiler would throw a warning for this
    'fabs' is the floating point absolute value function

    edit: it would help if you told us exactly which comparison was giving you the problem.
    Salem likes this.

  8. #8
    Registered User javaeyes's Avatar
    Join Date
    Feb 2012
    Posts
    153
    Oh that is gold, never would have figured it out. Never heard of fabs, but it works perfectly now. Thanks for wading through this disaster of code.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Floats
    By okel91 in forum C Programming
    Replies: 7
    Last Post: 03-17-2010, 04:00 PM
  2. efficiency comparing ints and floats
    By MK27 in forum C Programming
    Replies: 14
    Last Post: 02-28-2009, 02:56 PM
  3. comparing two arrays of floats
    By COBOL2C++ in forum C++ Programming
    Replies: 7
    Last Post: 07-16-2003, 03:22 AM
  4. comparing numbers(floats)
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 03-30-2002, 08:12 AM
  5. Floats
    By JFK in forum C Programming
    Replies: 2
    Last Post: 11-27-2001, 06:53 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21