#include #include 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 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; }