I'm trying to write a (mostly)* C program that sorts numerical results and eliminates duplicates. The results are stored as STRUCTS that contain a string, an integer, and 4 doubles. The doubles are what is relevant for determining if two results are duplicates.
To do this, I sprintf a string using the 4 doubles to some precision i.e.
#define PRECISION 5
sprintf(hashString, "%.*lf %.*lf %.*lf %.*lf", PRECISION, result.v1, PRECISION, result.v2, PRECISION, result.v3, PRECISION, result.v4);
I then use this as a hashkey for a tr1::unordered_map<string, ResultType>
. Then the program checks to see if the hashtable already contains an entry for that key, if so, the result is a duplicate and can be discarded. Otherwise, it gets added to the hashtable.
The problem is that sometimes one of my values will be rounded to zero from, for example, -10E-9, by sprintf; As a result, the string will contain "-0.00000" rather than "0.00000". These two values will obviously generate different hashkeys, despite representing the same result.
Is there something built into sprintf or even the C language that will allow me to deal with this? I've come up with a bit of a work around (see post below) -- but if there's something built in, I would much rather use that.
*the program is written in C because that's the language I'm most comfortable in, but I'll end up compiling with g++ in order to use the unordered_map.
I've come up with the following workaround. But A) I'm hoping there's a builtin solution and B) I don't have a very deep understanding of atof or floating point math, so I'm not sure if the condition if(doubleRepresentation == 0.0)
will always trip when it should.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PRECISION 5
#define ACCURACY 10E-6
double getRidOfNegZeros (double number)
{
char someNumAsStr[PRECISION + 3]; // +3 accounts for a possible minus sign, the leading 0 or 1, and the decimal place.
sprintf(someNumAsStr, "%.*lf", PRECISION, number);
double doubleRepresentation = atof(someNumAsStr);
if((doubleRepresentation < ACCURACY) && (doubleRepresentation > -ACCURACY))
{
doubleRepresentation = 0.0;
}
return doubleRepresentation;
}
int main()
{
printf("Enter a number: \n");
double somenum;
scanf("%lf",&somenum);
printf("The new representation of double \"%.*lf\" is \"%.*lf\"\n", PRECISION, somenum, PRECISION, getRidOfNegZeros(somenum));
return 0;
}
#include <string>
#define PRECISION 5
#define LIMIT 5e-6
std::string string_rep (double x) {
char buf[32];
double xtrunc = ((x > -LIMIT) && (x < LIMIT)) ? 0.0 : x;
std::sprintf (buf, "%.*f", PRECISION, xtrunc);
return std::string(buf);
}
std::string make_key (double x, double y, double z, double w) {
std::string strx = string_rep (x);
std::string stry = string_rep (y);
std::string strz = string_rep (z);
std::string strw = string_rep (w);
return strx + " " + stry + " " + strz + " " + strw;
}