-
How to debug atof()?
Hey guys,
So... my puny little humain brain has reached its limits here. My pitiful little mere-mortal perspective has no logical explanation here... so, given this code:
Code:
// Compiling on Linux Mint x64 with gcc.
// Where "tokens" is was i.e. "-4 + -4"
char whatThe[10000];
sprintf(whatThe, "%s", tokens + start - 1);
printf("My string is \"%s\"\n", whatThe);
printf("f1 = %g\n", atof(whatThe));
printf("Okay, so then why the PUCK does this work? %g\n", atof("-123.45"));
I get this output:
Code:
My string is "-4"
f1 = 0
Okay, so then why the PUCK does this work? -123.45
So.............?????????????????????.............. ...............................
My code works fine with positive numbers, and it's giving me correct strings when using negative numbers, but there's something in atof that feels the need to drive me to drink tonight. One website says this: "double value corresponding to the contents of str on success. If the converted value falls out of range of the return type, the return value is undefined. If no conversion can be performed, 0.0 is returned." Zero is what I'm getting... soooooooo......... (scratches head)...........??????????????????????? I suppose a logical question might be, how do I discover the reason the compiler thinks "no conversion can be performed"? I'm guessing I must've made some ultra-subtle infuriating micromistake that is causing this nonsense. I'm at the point of DIY'ing my own atof() replacement that is human-reasoning-compliant. :D
Code:
while(true) {
hair--;
frustration++;
exhaustion++;
if (asleep) printf("Finally, a break from depuzzling!"); // :D
}
-
Should:
Code:
sprintf(whatThe, "%s", tokens + start - 1);
Be:
Code:
sprintf(whatThe, "%f", tokens + start - 1);
-
Hahahahahahaha wow, I can't believe I did that! :D
Having said that... it's still very interesting how C's decimal-point-number APIs work. Here is what I eventually came up with:
Code:
float string_to_double(char* str) {
/* Declare variables */
size_t i = 0, start = 0, length = 0, end = 0, place = 1;
char* point = NULL;
double result = 0;
bool is_negative = false;
/* If the string is NULL or empty, the answer is easy */
if (str == NULL) return 0;
length = strlen(str);
if (length == 0) return 0;
/* Move past the sign, if there is one */
start = 0;
if (str[0] == '+')
start++;
else if (str[0] == '-') {
is_negative = true;
start++;
}
/* Figure out the decimal part, if there is one */
point = strchr(str, '.');
while (point != NULL) {
point++;
place *= 10;
if (point[0] < '0' || point[0] > '9') break;
result += (double)(point[0] - '0') / place;
}
/* Figure out the last character before the decimal point.
If there was no decimal point, use the last char in the string. */
end = length - 1;
point = strchr(str, '.');
if (point != NULL) end = point - str - 1;
/* Figure out teh whole part, if there is one */
place = 1;
while(end != start - 1) {
if (str[end] < '0' || str[end] > '9') break;
result += (double)(str[end] - '0') * place;
place *= 10;
end--;
}
if (is_negative) result *= -1;
return result;
}
And it works! But with a limit of like 8 decimal places. If I pass it "123.456789" I get ti rounded (which makes sense, cuz there is a limit to the size of floats/doubles). The higher the number on the left of the decimal point, the fewer numbers after it. I think what I'm ramming my head against is just how decimal numbers (floats and doubles I mean) were rigged up "under the hood". No wonder the people who designed the compiler had to say "undefined behavior is a thing" lol
Anyway, thanks for the pointer (no cheesy pun intended) and have a nice nite! :)
-
I'd recommend that you use strtod() instead of atof() which can silently fail.
-
Works as expected for me. I had to assume the value of start since you didn't say what it was.
Code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
const char *tokens = "-4 + -4";
int start = 6;
char whatThe[10000];
sprintf(whatThe, "%s", tokens + start - 1);
printf("My string is \"%s\"\n", whatThe);
printf("f1 = %g\n", atof(whatThe));
printf("Okay, so then why the PUCK does this work? %g\n", atof("-123.45"));
return 0;
}
Code:
My string is "-4"
f1 = -4
Okay, so then why the PUCK does this work? -123.45
Please post a minimal but complete and compilable program (i.e., a Minimal Reproducible Example) that shows the problem.
Edit to add: I would also avoid re-implementing string-to-float conversion functions. It's a lot trickier to get right than you might think. Use strtod() instead.