# Comparing 2 floats, off by 1

• 11-29-2012
javaeyes
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?
• 11-29-2012
Salem
You would need to post some code we can compile and try for ourselves.
• 11-29-2012
grumpy
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.
• 11-29-2012
sean
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.
• 11-29-2012
iMalc
This is quite simply a bug in your code. You'll need to show the code.
• 11-29-2012
javaeyes
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; }```
• 11-29-2012
dmh2000
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.
• 11-29-2012
javaeyes
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.