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
|
||||
auth_secret
|
||||
__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