1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
#include "fast_float/fast_float.h"
#include <ios>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
#include <system_error>
#include <utility>
#include <vector>
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \
defined(sun) || defined(__sun)
// Anything at all that is related to cygwin, msys and so forth will
// always use this fallback because we cannot rely on it behaving as normal
// gcc.
#include <locale>
// workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) {
double d;
std::stringstream ss;
ss.imbue(std::locale::classic());
ss << start;
ss >> d;
if (ss.fail()) {
*end = nullptr;
}
if (ss.eof()) {
ss.clear();
}
auto nread = ss.tellg();
*end = const_cast<char *>(start) + nread;
return d;
}
float cygwin_strtof_l(char const *start, char **end) {
float d;
std::stringstream ss;
ss.imbue(std::locale::classic());
ss << start;
ss >> d;
if (ss.fail()) {
*end = nullptr;
}
if (ss.eof()) {
ss.clear();
}
auto nread = ss.tellg();
*end = const_cast<char *>(start) + nread;
return d;
}
#endif
std::pair<double, bool> strtod_from_string(char const *st) {
double d;
char *pr;
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \
defined(sun) || defined(__sun)
d = cygwin_strtod_l(st, &pr);
#elif defined(_WIN32)
static _locale_t c_locale = _create_locale(LC_ALL, "C");
d = _strtod_l(st, &pr, c_locale);
#else
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
d = strtod_l(st, &pr, c_locale);
#endif
if (st == pr) {
std::cerr << "strtod_l could not parse '" << st << std::endl;
return std::make_pair(0, false);
}
return std::make_pair(d, true);
}
std::pair<float, bool> strtof_from_string(char *st) {
float d;
char *pr;
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \
defined(sun) || defined(__sun)
d = cygwin_strtof_l(st, &pr);
#elif defined(_WIN32)
static _locale_t c_locale = _create_locale(LC_ALL, "C");
d = _strtof_l(st, &pr, c_locale);
#else
static locale_t c_locale = newlocale(LC_ALL_MASK, "C", NULL);
d = strtof_l(st, &pr, c_locale);
#endif
if (st == pr) {
std::cerr << "strtof_l could not parse '" << st << std::endl;
return std::make_pair(0.0f, false);
}
return std::make_pair(d, true);
}
bool tester() {
std::random_device rd;
std::mt19937 gen(rd());
for (int q = 18; q <= 27; q++) {
std::cout << "q = " << -q << std::endl;
uint64_t power5 = 1;
for (int k = 0; k < q; k++) {
power5 *= 5;
}
uint64_t low_threshold = 0x20000000000000 / power5 + 1;
uint64_t threshold = 0xFFFFFFFFFFFFFFFF / power5;
std::uniform_int_distribution<uint64_t> dis(low_threshold, threshold);
for (size_t i = 0; i < 10000; i++) {
uint64_t mantissa = dis(gen) * power5;
std::stringstream ss;
ss << mantissa;
ss << "e";
ss << -q;
std::string to_be_parsed = ss.str();
std::pair<double, bool> expected_double =
strtod_from_string(to_be_parsed.c_str());
double result_value;
auto result = fast_float::from_chars(
to_be_parsed.data(), to_be_parsed.data() + to_be_parsed.size(),
result_value);
if (result.ec != std::errc() &&
result.ec != std::errc::result_out_of_range) {
std::cout << to_be_parsed << std::endl;
std::cerr << " I could not parse " << std::endl;
return false;
}
if (result_value != expected_double.first) {
std::cout << to_be_parsed << std::endl;
std::cerr << std::hexfloat << result_value << std::endl;
std::cerr << std::hexfloat << expected_double.first << std::endl;
std::cerr << " Mismatch " << std::endl;
return false;
}
}
}
return true;
}
int main() {
if (tester()) {
std::cout << std::endl;
std::cout << "all ok" << std::endl;
return EXIT_SUCCESS;
}
std::cerr << std::endl;
std::cerr << "errors were encountered" << std::endl;
return EXIT_FAILURE;
}
|