Ensure the floating point parsing at least kind of works
This commit is contained in:
parent
19483a0f68
commit
5dd60e87e4
|
@ -2,3 +2,5 @@ shroom_server
|
||||||
shrooms.db
|
shrooms.db
|
||||||
auth_secret
|
auth_secret
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
||||||
|
test_float_parse
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#include <optional>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bool parseFloat(const char* buf, int len, float* v) {
|
||||||
|
float tmp = 0.0f;
|
||||||
|
float factor = 0.1f;
|
||||||
|
int exponent = 0;
|
||||||
|
bool is_negative = false, has_digit = false;
|
||||||
|
bool using_exponent = false, has_exponent = false;
|
||||||
|
bool exp_is_negative = false;
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
kPredecimal,
|
||||||
|
kPostdecimal, // after the decimal point
|
||||||
|
kExponent, // after the e
|
||||||
|
kExponentPostsign, // after the +/-
|
||||||
|
};
|
||||||
|
State state = kPredecimal;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
switch (state) {
|
||||||
|
case kPredecimal:
|
||||||
|
if (i == 0 && buf[i] == '-') {
|
||||||
|
is_negative = true;
|
||||||
|
} else if (buf[i] >= '0' && buf[i] <= '9') {
|
||||||
|
has_digit = true;
|
||||||
|
tmp = 10.0f * tmp + (buf[i] - '0');
|
||||||
|
} else if (buf[i] == '.') {
|
||||||
|
state = kPostdecimal;
|
||||||
|
} else if (buf[i] == 'e') {
|
||||||
|
state = kExponent;
|
||||||
|
using_exponent = true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kPostdecimal:
|
||||||
|
if (buf[i] >= '0' && buf[i] <= '9') {
|
||||||
|
has_digit = true;
|
||||||
|
tmp = tmp + factor * (buf[i] - '0');
|
||||||
|
factor *= 0.1f;
|
||||||
|
} else if (buf[i] == 'e') {
|
||||||
|
state = kExponent;
|
||||||
|
using_exponent = true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kExponent:
|
||||||
|
if (buf[i] == '+') {
|
||||||
|
state = kExponentPostsign;
|
||||||
|
} else if (buf[i] == '-') {
|
||||||
|
exp_is_negative = true;
|
||||||
|
state = kExponentPostsign;
|
||||||
|
} else if (buf[i] >= '0' && buf[i] <= '9') {
|
||||||
|
has_exponent = true;
|
||||||
|
exponent = (buf[i] - '0');
|
||||||
|
state = kExponentPostsign;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kExponentPostsign:
|
||||||
|
if (buf[i] >= '0' && buf[i] <= '9') {
|
||||||
|
has_exponent = true;
|
||||||
|
exponent = 10*exponent + (buf[i] - '0');
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_digit) return false;
|
||||||
|
if (using_exponent && !has_exponent) return false;
|
||||||
|
|
||||||
|
if (is_negative) {
|
||||||
|
tmp = -tmp;
|
||||||
|
}
|
||||||
|
if (has_exponent) {
|
||||||
|
if (exp_is_negative) {
|
||||||
|
for (int i = 0; i < exponent; i++) {
|
||||||
|
tmp *= 0.1f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < exponent; i++) {
|
||||||
|
tmp *= 10.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = tmp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<float> parseWrapper(const char* buf, int len) {
|
||||||
|
float tmp;
|
||||||
|
if (parseFloat(buf, len, &tmp)) {
|
||||||
|
return tmp;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT_VALID_MATCHES(s) \
|
||||||
|
do { \
|
||||||
|
auto tmp = parseWrapper(#s, sizeof(#s) - 1); \
|
||||||
|
if (!tmp) { \
|
||||||
|
std::cout << "failed to parse " << s << std::endl; \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
float err = (*tmp - s) / (s + 1e-12); \
|
||||||
|
if (err < 0) err = -err; \
|
||||||
|
if (err > 1e-6) { \
|
||||||
|
std::cout << "error out of range for " << #s << " err = " << err << ", parsed = " << *tmp << ", expected = " << s << std::endl; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ASSERT_VALID_MATCHES(1.);
|
||||||
|
ASSERT_VALID_MATCHES(0.1);
|
||||||
|
ASSERT_VALID_MATCHES(-0.1);
|
||||||
|
ASSERT_VALID_MATCHES(-0.1e3);
|
||||||
|
ASSERT_VALID_MATCHES(-0.1e-3);
|
||||||
|
ASSERT_VALID_MATCHES(1.2e-3);
|
||||||
|
ASSERT_VALID_MATCHES(.2e-3);
|
||||||
|
ASSERT_VALID_MATCHES(-.3e-4);
|
||||||
|
ASSERT_VALID_MATCHES(-.3e4);
|
||||||
|
ASSERT_VALID_MATCHES(-.0003342);
|
||||||
|
ASSERT_VALID_MATCHES(-.0073342e12);
|
||||||
|
ASSERT_VALID_MATCHES(3.141592);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue