2

I posted about this earlier today and resolved that issue. I am having a different issue regarding my use of the haversine formula. I am trying to compute the distance between two lat and long points. I have the formula in, and my calculations are really close to the output I need, but it's slightly off. I just have to get the number right, not the decimal places. But some of the calculations are too far off that they aren't the same foot.

I've gone through and tried changing from floats to doubles, used the debugger to compare my lat and long to make sure that I did those calculations from DMS to Decimal correctly.

I can't figure out what is off. All the CONST's that I have got to stay, they can't change.

FYI I haven't done anything with the last two columns.

Any help to be led in the right direction would be much appreciated! Thanks!

Code:

//---------------------------------------------------------------------
//
// Input:   $GPRMC sentence for add (A). Distance traveled (D).
//          Average speed (S). Table of records (T).
//
// Output:  Record added. Table of records. Distance traveled.
//          Average speed.
//          
//---------------------------------------------------------------------

#include<iostream>
#include<string>
#include<iomanip>

using namespace std;

const int MAX_RECS = 5;
const float EARTH_RADIUIS_MILES = 3959;
const int FEET_IN_MILE = 5280;
const float HALF_CIRCLE = 180;
const float PI = 3.14159f;
const int SECS_IN_HR = 3600;
const int SECS_IN_MIN = 60;
const float FPS_PER_KNOT = 1.68781f;
const int ID1 = 2234;
const int ID2 = 5327;
const int ID3 = 7741;

const int TABLEFIRSTSPACE = 51;
const int TABLESECONDSPACE = 6;
const int TABLE8 = 8;
const int TABLE10 = 10;
const int TABLE11 = 11;
const int TABLE13 = 13;

enum FitBitID_Type 
{ 
   ID_FITBIT1 = ID1, ID_FITBIT2 = ID2, ID_FITBIT3 = ID3
};

enum CommandType 
{
   ADD_CMD = 'A', DISTANCE_TRAVELED_CMD = 'D',
   AVG_SPEED_CMD = 'S', TABLE_PRINT_CMD = 'T'
};

void ReadIn(string &time, string &latNum, string &longNum, 
   float &speedFloat);
//void timeBreakdown(int time, int &hours, int &minutes, int &seconds);
//void latLongCalc(float latNum, float longNum, float &latD, float &longD);
//float DegreesToRadians(float degrees);

class FitBit
{
private:
   string strTime[MAX_RECS];
   int totalSecs[MAX_RECS];
   float latitude[MAX_RECS];
   float longitude[MAX_RECS];
   float speed[MAX_RECS];
   int numRecs;//num of records currently stored in the parallel arrays

   void timeBreakdown(string time, int &hours, int &minutes, int &seconds)
   {
      hours = stoi(time.substr(0, 2));
      minutes = stoi(time.substr(2, 2));
      seconds = stoi(time.substr(4, 2));
   }

   void latLongCalc(string latNum, string longNum, float &latD, float &longD)
   {
      float degreeLa = stof(latNum.substr(0, 2));
      float minuteLa = stof(latNum.substr(2, 2));
      float secondLa = stof(latNum.substr(5, 3));
      latD = degreeLa + (minuteLa / SECS_IN_MIN) +
         (((secondLa / 1000) * SECS_IN_MIN) / SECS_IN_HR);
      float degreeLo = stof(longNum.substr(0, 3));
      float minuteLo = stof(longNum.substr(3, 2));
      float secondLo = stof(longNum.substr(6, 3));
      longD = degreeLo + (minuteLo / SECS_IN_MIN) +
         (((secondLo / 1000) * SECS_IN_MIN) / SECS_IN_HR); longD = -longD;
   }

   float DegreesToRadians(float degrees) const
   {
      return degrees * PI / HALF_CIRCLE;
   }

public:
   FitBit()
   {
      numRecs = 0;
   }
   void addRecord(string time, string latNum, string longNum, 
      float speedFloat)
   {
      int hours, minutes, seconds;
      timeBreakdown(time, hours, minutes, seconds);
      float latD, longD;
      latLongCalc(latNum, longNum, latD, longD);
      hours *= SECS_IN_MIN; minutes += hours; minutes *= SECS_IN_MIN;
      seconds += minutes; speedFloat *= FPS_PER_KNOT;
      if (numRecs < MAX_RECS)
      {
         strTime[numRecs] = time; totalSecs[numRecs] = seconds;
         latitude[numRecs] = latD; longitude[numRecs] = longD;
         speed[numRecs] = speedFloat;
         numRecs++;
      }
      else
      {
         for (int i = 1; i < numRecs; i++)
         {
            strTime[i - 1] = strTime[i]; totalSecs[i - 1] = totalSecs[i];
            latitude[i - 1] = latitude[i];
            longitude[i - 1] = longitude[i]; speed[i - 1] = speed[i];
         }
         strTime[numRecs] = time; totalSecs[numRecs] = seconds;
         latitude[numRecs] = latD; longitude[numRecs] = longD;
         speed[numRecs] = speedFloat;
      }
   }
   float distanceBetweenEarthCoordinates(float lat1, float lon1, 
                                       float lat2, float lon2) const
   {
      float dLat, dLon, a, c;
      lat1 = DegreesToRadians(lat1);
      lon1 = DegreesToRadians(lon1);
      lat2 = DegreesToRadians(lat2);
      lon2 = DegreesToRadians(lon2);
      lon1 = -lon1;
      lon2 = -lon2;
      dLat = (lat2 - lat1);
      dLon = (lon2 - lon1);

      a = (sin(dLat / 2) * sin(dLat / 2)) + cos(lat1) * cos(lat2) 
         * (sin(dLon / 2) * sin(dLon / 2));
      c = 2 * atan2(sqrt(a), sqrt(1 - a));

      //return ((EARTH_RADIUIS_MILES * c) * FEET_IN_MILE);
      return EARTH_RADIUIS_MILES * c * FEET_IN_MILE;
   }
   float Distance()
   {
      if (!(numRecs <= 1))
      {
         float total = 0;
         for (int i = 1; i < numRecs; i++)
         {
            float x = distanceBetweenEarthCoordinates(latitude[i-1],
               longitude[i-1], latitude[i], longitude[i]);
            total += x;
         }
         return total;
      }
      return 0;
   }
   float DistanceForTable(int i) const
   {
      if (!(i < 1))
      {
         return distanceBetweenEarthCoordinates(latitude[i - 1],
            longitude[i - 1], latitude[i], longitude[i]);
      }
      return 0;
   }
   void PrintTable()
   {
      cout << left << setw(TABLE8) << "Time" << setw(TABLE10)
         << "Latitude" << setw(TABLE10) << "Longitude" << setw(TABLE11)
         << "Speed" << setw(TABLE13) << "Distance" << setw(TABLE10)
         << "Average" << setw(TABLE13) << "Acceleration" << endl << right
         << setw(TABLEFIRSTSPACE) << "Traveled(ft)" 
         << setw(TABLESECONDSPACE) << "Speed" << endl;
      if (numRecs > 0)
      {
         for (int i = 0; i < numRecs; i++)
         {
            cout << left << setw(TABLE8) << strTime[i];
            cout << left << setw(TABLE10) << latitude[i];
            cout << left << setw(TABLE10) << longitude[i];
            cout << left << setw(TABLE11) << speed[i];
            if (i < 1)
               cout << left << setw(TABLE13) << " ";
            else
               cout << left << setw(TABLE13) << DistanceForTable(i);
            cout << left << setw(TABLE10) << 200.0;
            cout << left << setw(TABLE13) << 1.0101 << endl;
         }
      }
   }
};

void ProcessCommandForFitBit(FitBit & bit, CommandType command,
   FitBitID_Type FitBitID);

int main()
{
   cout << fixed << showpoint << setprecision(4);
   char cmd; int id;

   FitBit bit1, bit2, bit3;

   while (cin)
   {
      cin >> cmd >> id;
      FitBitID_Type FitBitID = FitBitID_Type(id);
      CommandType command = CommandType(cmd); 
      if (FitBitID == ID_FITBIT1)
         ProcessCommandForFitBit(bit1, command, FitBitID);
      else if (FitBitID == ID_FITBIT2)
         ProcessCommandForFitBit(bit2, command, FitBitID);
      else if (FitBitID == ID_FITBIT3)
         ProcessCommandForFitBit(bit3, command, FitBitID);
   }

   cout << "Normal Termination of Program 5.";
   return 0;
}

void ProcessCommandForFitBit(FitBit & bit, CommandType command,
                             FitBitID_Type FitBitID)
{
   int returnedDistance = 0;  float returnedAvgSpeed = 0;
   string time, latNum, longNum; float speedFloat = 0;

   switch (command)
   {
   case ADD_CMD:
      ReadIn(time, latNum, longNum, speedFloat);
      bit.addRecord(time, latNum, longNum, speedFloat);
      cout << "Record added for FitBit with ID " << FitBitID << endl;
      break;
   case DISTANCE_TRAVELED_CMD:
      returnedDistance = bit.Distance();
      cout << "Distance Traveled in feet for FitBit with ID "
           << FitBitID << " is " << returnedDistance << endl;
      break;
   case AVG_SPEED_CMD:

      cout << "Average Speed for FitBit with ID " << FitBitID
           << " is " << returnedAvgSpeed << endl;
      break;
   case TABLE_PRINT_CMD:
      cout << "Records for FitBit with ID " << FitBitID << endl;
      bit.PrintTable();
      break;
   }
}

void ReadIn(string &time, string &latNum, string &longNum, float &speedFloat)
{
   string trash;
   cin >> trash >> time >> trash >> latNum >> trash >> longNum
      >> trash >> speedFloat >> trash >> trash >> trash >> trash;
}

Input File:

A 2234 $GPRMC 204849 A 4243.636 N 09028.597 W 000.0 065.5 091297 000.2 W*7F
A 2234 $GPRMC 204851 A 4243.636 N 09028.594 W 006.4 074.4 091297 000.2 W*76
A 2234 $GPRMC 204853 A 4243.638 N 09028.586 W 011.7 067.9 091297 000.2 W*73
A 2234 $GPRMC 204855 A 4243.641 N 09028.574 W 014.2 067.5 091297 000.2 W*7A
T 2234
D 2234
S 2234
A 2234 $GPRMC 204903 A 4243.662 N 09028.593 W 018.7 066.2 090108 000.2 W*7A
T 2234
D 2234
S 2234
T 5327
D 5327
S 5327
A 5327 $GPRMC 204905 A 4273.667 N 09047.499 W 021.6 064.5 090108 000.2 W*78
T 5327
D 5327
S 5327
A 5327 $GPRMC 204907 A 4273.671 N 09047.480 W 027.3 065.4 090108 000.2 W*73
T 5327
D 5327
S 5327
A 7741 $GPRMC 204909 A 4273.679 N 09047.459 W 026.5 066.8 090108 000.2 W*77
A 7741 $GPRMC 204913 A 4273.689 N 09047.418 W 031.7 068.6 090108 000.2 W*7F
T 7741
D 7741
S 7741

My output:

Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204849  42.7273   -90.4766  0.0000                  200.0000  1.0101       
204851  42.7273   -90.4766  10.8020    12.8137      200.0000  1.0101       
204853  42.7273   -90.4764  19.7474    37.9431      200.0000  1.0101       
204855  42.7274   -90.4762  23.9669    54.9950      200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 2234 is 105
Average Speed for FitBit with ID 2234 is 0.0000
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204849  42.7273   -90.4766  0.0000                  200.0000  1.0101       
204851  42.7273   -90.4766  10.8020    12.8137      200.0000  1.0101       
204853  42.7273   -90.4764  19.7474    37.9431      200.0000  1.0101       
204855  42.7274   -90.4762  23.9669    54.9950      200.0000  1.0101       
204903  42.7277   -90.4765  31.5620    151.4476     200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 2234 is 257
Average Speed for FitBit with ID 2234 is 0.0000
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204905  43.2278   -90.7916  36.4567                 200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204905  43.2278   -90.7916  36.4567                 200.0000  1.0101       
204907  43.2279   -90.7913  46.0772    87.9045      200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 5327 is 87
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 7741
Record added for FitBit with ID 7741
Records for FitBit with ID 7741
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed
204909  43.2280   -90.7910  44.7270                 200.0000  1.0101       
204913  43.2281   -90.7903  53.5036    193.2789     200.0000  1.0101       
Distance Traveled in feet for FitBit with ID 7741 is 193
Average Speed for FitBit with ID 7741 is 0.0000
Average Speed for FitBit with ID 7741 is 0.0000
Normal Termination of Program 5.

Output I need to match:

Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204849  42.7273   -90.4766  0.0000     
204851  42.7273   -90.4766  10.8020    12           5.4010    5.4010       
204853  42.7273   -90.4764  19.7474    36           10.1831   4.4727       
204855  42.7274   -90.4762  23.9669    56           13.6291   2.1098       
Distance Traveled in feet for FitBit with ID 2234 is 104
Average Speed for FitBit with ID 2234 is 13.6291
Record added for FitBit with ID 2234
Records for FitBit with ID 2234
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204849  42.7273   -90.4766  0.0000     
204851  42.7273   -90.4766  10.8020    12           5.4010    5.4010       
204853  42.7273   -90.4764  19.7474    36           10.1831   4.4727       
204855  42.7274   -90.4762  23.9669    56           13.6291   2.1098       
204903  42.7277   -90.4765  31.5620    153          17.2157   0.9494       
Distance Traveled in feet for FitBit with ID 2234 is 257
Average Speed for FitBit with ID 2234 is 17.2157
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 0.0000
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204905  43.2278   -90.7916  36.4567    
Distance Traveled in feet for FitBit with ID 5327 is 0
Average Speed for FitBit with ID 5327 is 36.4567
Record added for FitBit with ID 5327
Records for FitBit with ID 5327
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204905  43.2278   -90.7916  36.4567    
204907  43.2278   -90.7913  46.0772    84           41.2670   4.8103       
Distance Traveled in feet for FitBit with ID 5327 is 84
Average Speed for FitBit with ID 5327 is 41.2670
Record added for FitBit with ID 7741
Record added for FitBit with ID 7741
Records for FitBit with ID 7741
Time    Latitude  Longitude Speed      Distance     Average   Acceleration 
                                       Traveled(ft) Speed     
204909  43.2280   -90.7910  44.7270    
204913  43.2281   -90.7903  53.5036    192          49.1153   2.1942       
Distance Traveled in feet for FitBit with ID 7741 is 192
Average Speed for FitBit with ID 7741 is 49.1153
Normal Termination of Program 5.
njuffa
  • 23,970
  • 4
  • 78
  • 130
ZachTheDev
  • 35
  • 7
  • 2
    Hi. Have you tried using a more precise constant for PI? I haven't checked all your code but 5 digits seems really low to me. – AlexG Dec 13 '19 at 00:28
  • @AlexG, I did, but that made the numbers even father off. The PI I was given has to be used, so I can't make it any more precise. – ZachTheDev Dec 13 '19 at 00:29
  • It looks like you may have your input routine a bit off. Looking at your input it is hard to see how you associate ID `2234` with Lat/Lon of `42.7273` and `-90.4766`. From your input it looks like those Lat/Lon go with ID `5327`?? – David C. Rankin Dec 13 '19 at 00:57
  • @DavidC.Rankin I just went through and removed the other id's from my input file. The output is the same, the math is just slightly off. This is for a school project, so they were strict about making the id not passed around. – ZachTheDev Dec 13 '19 at 01:05
  • @Zach: There are multiple ways to code the haversine computation. Depending on which one I choose, the results in the output log differ by up to two feet from your reference. This suggests that, considering round-off errors in the computation, `float` is not sufficient to provide 1 foot resolution, and that the only way to match the reference to with the same foot is to use the exact same sequence of floating-point operations and the exact same math library. The earth radius is 20,903,520 ft, another indication that we cannot expect 1 foot accuracy from `float` (24 total mantissa bits). – njuffa Dec 13 '19 at 01:06
  • @njuffa That's what I figured. So I changed everything to `double`'s and that didn't change anything. I have to use the CONST that were given, so I am not sure where to go from here. – ZachTheDev Dec 13 '19 at 01:08
  • @njuffa When I change everything over, the new output is this: https://pastebin.com/5ncjpfQz . The numbers are slightly higher, so having floats is closer to what I need. – ZachTheDev Dec 13 '19 at 01:12
  • Using `double` in your own computation won't help with matching a reference that is inaccurate and faking accuracy to within one foot although use of `float` throughout cannot provide that level of accuracy. Finding out what exact variant of the haversine formula was used *may* help you (provided compiler and math library don't cause further complications; I used the "strict" floating-point mode of my compiler but whoever generated the reference might have used some other mode, such as "fast math"). – njuffa Dec 13 '19 at 01:17
  • @njuffa I have been googling the harversine formula. I can't see anything about different variants, could you point me in the right direction about that? – ZachTheDev Dec 13 '19 at 01:29
  • 1
    One alternative can be found in [this question](https://stackoverflow.com/questions/42792939/implementation-of-sinpi-and-cospi-using-standard-c-math-library). – njuffa Dec 13 '19 at 02:13

1 Answers1

0

Solved it

I had to reuse an old piece of code that our professor never told us we needed to copy. It was a different implementation of the degree minute second converter, which was unrelated to the haversine formula.

Thanks for all the help!

ZachTheDev
  • 35
  • 7