Digistump Forums
The Oak by Digistump => Oak Support => Topic started by: postuma on January 02, 2017, 01:18:46 pm
-
Function atof, used to convert a character array containing a number, i.e. "200" or "1E2" to its corresponding float, does not work with exponents, i.e.
f = atof("200"); //returns 200.0
f = atof("1E2"); //returns 0.0
Does anyone have a functional replacement handy?
(Note: atof is a direct alias for strtod, as defined in core_esp8266_noniso.c - so it's the exact same problem.)
This problem is specific to the Oak/ESP8266 architecture (reported here: http://www.esp8266.com/viewtopic.php?f=28&t=12802&p=59111&hilit=atof#p59111 as well), and I haven't been able to find a corrected function.
More details (for those that care): function description at http://www.cplusplus.com/reference/cstdlib/atof/.
Oak's atof is defined in core_esp8266_noniso.c and strtod in libc_replacements.c.
The AVR version does implement scientific notation: https://github.com/vancegroup-mirrors/avr-libc/blob/06cc6ff5e6120b36f1b246871728addee58d3f87/avr-libc/libc/stdlib/strtod.c.
I may well end up adapting this version - though their coding style is much different from mine and I'll probably start from the ground up, unless someone has already done it? I'm thinking it would be nice if atof actually parsed the whole string and returned an error if invalid characters were encountered - rather than stopping interpretation when such a character is encountered but still returning a result based on a few digits that matched format. So you get a result, implying success, even though the string is garbage.
-
I've taken the basic code for strtod and modified it to create function atof_e.
(Initially, I had simply modified strtod in libc_replacements.c so atof and strtod would work properly - but this would require more work for someone else if they wish to use this code. Also, if I or someone else later updates to a newer version of the Oak library the modification might well be overwritten with the old bugged version, and I/you will probably have forgotten about this modification.)
Usage: double atof_e (const char* str);
Identically to atof(), atof_e() parses the string str, interpreting its content as a floating point number and returns its value as a double. As per the C++ 98 specification, it may optionally followed by an exponent part (an e or E character followed by an optional sign and a sequence of digits).
double atof_e(const char* str) {
char ** endptr;
double result = 0.0;
double factor = 1.0;
bool exp_factor = 1; //default 1 - positive exponent. Use 0 for negative
double exponent = 0;
double multiplier = 1; //multiplier for exponent
bool decimals = false;
char c;
while(isspace(*str)) {
str++;
}
if(*str == 0x00) {
// only space in str?
if (endptr) *endptr = (char*) str;
return result;
}
if(*str == '-') {
factor = -1;
str++;
} else if(*str == '+') {
str++;
}
while((c = *str)) {
if(c == '.') {
decimals = true;
str++;
continue;
}
if (c == 'e' || c == 'E') {
str++;
if(*str == '-') {
exp_factor = 0;
str++;
} else if(*str == '+') {
str++;
}
while (c = *str) { //this while loop for the exponent
int d = c - '0';
if (d < 0 || d > 9) {
break;
}
exponent = exponent * 10 + d;
str++;
}
}
else {
int d = c - '0';
if(d < 0 || d > 9) {
break;
}
result = 10.0 * result + d;
if(decimals) {
factor *= 0.1;
}
str++;
}
}
if (endptr) *endptr = (char*) str;
result *= factor;
if (exponent) {
multiplier = pow(10, exponent);
if (exp_factor) result *= multiplier;
else result /= multiplier;
}
return result;
}
-
I just logged the changes to GitHub and put in a pull request ;)