I'm trying to write a function to replace the standard std::stod(...). I want to parse the following valid inputs:
/[+-]?\d+(?:\.\d+)?(?:e[-+]?\d+)?/g
Here's the RegExr link.
And also the words infinity, +infinity, -infinity, undefined, +undefined and -undefined. Note, if I remember well, infinity and +infinity are the same underlying values while undefined, +undefined and -undefined are all different NaN values.
So I came up with this:
#include <iostream>
#include <cmath>
#include <limits>
#include <cstring>
using namespace std;
class invalid_number { };
static bool is_digit(char c) {
// probably faster than `return c >= '0' && c <= '9';`?
switch (c) {
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': return true;
default: return false;
}
}
double safe_pow(double a, double b) {
if (b < 0) return 1.0 / pow(a, abs(b));
else return pow(a, b);
}
// parses /[+-]?\d+(?:\.\d+)?(?:e[-+]?\d+)?/g
static double s2d(char * s) {
bool negative = (s[0] == '-');
bool positive = (s[0] == '+');
if (positive || negative) s++;
// + infinity == infinity
if (!strcmp(s, "infinity\0")) {
if (negative) return - numeric_limits<double>::infinity();
return numeric_limits<double>::infinity();
}
// + undefined != undefined != - undefined
if (!strcmp(s, "undefined\0")) {
if (negative) return - numeric_limits<double>::quiet_NaN();
if (positive) return + numeric_limits<double>::quiet_NaN();
return numeric_limits<double>::quiet_NaN();
}
if (!is_digit(* s)) throw invalid_number();
int64_t x = 0, point = 0, d = 0;
while (is_digit(* s)) {
x = (x * 10) + (* s) - '0';
s++; point++; d++;
}
if ((* s) == '.') {
s++;
if (!is_digit(* s)) throw invalid_number();
while (is_digit(* s)) {
x = x * 10 + (* s) - '0';
s++; d++;
}
} else point = 0;
if (negative) x *= -1;
uint64_t e = 0; bool ne = false;
if ((* s) == 'e') {
s++;
if ((* s) == '-') { ne = true; s++; }
else if ((* s) == '+') s++;
if (!is_digit(* s)) throw invalid_number();
while (is_digit(* s)) {
e = (e * 10) + (* s) - '0';
s++;
}
}
if (!point) return x;
point = d - point;
if (ne) point += e; else point -= e;
return x / safe_pow(10, point);
}
int main(int argc, char * argv[]) {
cout << "test number: ";
string number;
getline(cin, number);
/* test cases:
-537e+4
+20
34.3e-10
2e5
-5e3
-2
-22.27e0
*/
try {
cout << s2d((char *)number.c_str()) << endl;
} catch (invalid_number & inv) {
cout << "invalid number" << endl;
}
return 0;
}
\0in your strings? Note that in the comparisons that doesn't do anything since the compare stops at the first\0. \$\endgroup\$"123."to be acceptable, yet it appears/[+-]?\d+(?:\.\d+)?(?:e[-+]?\d+)?/gdoes not allow. \$\endgroup\$undefinedis not certainly different from both+undefinedand-undefined. \$\endgroup\$