Merge pull request #31 from lemire/dlemire/issue30

Build with pedantic flags under GNU GCC.
This commit is contained in:
Daniel Lemire 2020-11-13 13:19:46 -05:00 committed by GitHub
commit 8e1103d93e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 80 additions and 59 deletions

View File

@ -71,7 +71,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
// a multiplication by 10 is cheaper than an arbitrary integer
// multiplication
i = 10 * i +
(*p - '0'); // might overflow, we will handle the overflow later
uint64_t(*p - '0'); // might overflow, we will handle the overflow later
++p;
}
int64_t exponent = 0;
@ -236,11 +236,15 @@ fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) n
}
answer.decimal_point += (neg_exp ? -exp_number : exp_number);
}
answer.decimal_point += answer.num_digits;
answer.decimal_point += int32_t(answer.num_digits);
if(answer.num_digits > max_digits) {
answer.truncated = true;
answer.num_digits = max_digits;
}
// In very rare cases, we may have fewer than 19 digits, we want to be able to reliably
// assume that all digits up to max_digit_without_overflow have been initialized.
for(uint32_t i = answer.num_digits; i < max_digit_without_overflow; i++) { answer.digits[i] = 0; }
return answer;
}
} // namespace fast_float

View File

@ -104,11 +104,11 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
// value128 product = compute_product(q, w);
// but in practice, we can win big with the compute_product_approximation if its additional branch
// is easily predicted. Which is best is data specific.
uint64_t upperbit = product.high >> 63;
int upperbit = int(product.high >> 63);
answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
answer.power2 = power(int(q)) + upperbit - lz - binary::minimum_exponent();
answer.power2 = int(power(int(q)) + upperbit - lz - binary::minimum_exponent());
if (answer.power2 <= 0) { // we have a subnormal?
// Here have that answer.power2 <= 0 so -answer.power2 >= 0
if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.
@ -143,7 +143,7 @@ adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
// answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);
// ... we dropped out only zeroes. But if this happened, then we can go back!!!
if((answer.mantissa << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) == product.high) {
answer.mantissa &= ~1; // flip it so that we do not round up
answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up
}
}

View File

@ -149,9 +149,10 @@ struct decimal {
// Moves are allowed:
decimal(decimal &&) = default;
decimal &operator=(decimal &&other) = default;
// Generates a mantissa by truncating to 19 digits; this function assumes
// that num_digits >= 19 (the caller is responsible for the check).
// Generates a mantissa by truncating to 19 digits.
// This function should be reasonably fast.
// Note that the user is responsible to ensure that digits are
// initialized to zero when there are fewer than 19.
inline uint64_t to_truncated_mantissa() {
uint64_t val;
// 8 first digits
@ -175,7 +176,7 @@ struct decimal {
}
// Generate san exponent matching to_truncated_mantissa()
inline int32_t to_truncated_exponent() {
return decimal_point - max_digit_without_overflow;
return decimal_point - int32_t(max_digit_without_overflow);
}
};

View File

@ -77,7 +77,7 @@ from_chars_result from_chars(const char *first, const char *last,
from_chars_result answer;
while ((first != last) && fast_float::is_space(*first)) {
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
first++;
}
if (first == last) {

View File

@ -2,6 +2,10 @@
function(fast_float_add_cpp_test TEST_NAME)
add_executable(${TEST_NAME} ${TEST_NAME}.cpp)
add_test(${TEST_NAME} ${TEST_NAME})
if(NOT WIN32)
target_compile_options(${TEST_NAME} PUBLIC -Werror -Wall -Wextra -Weffc++)
target_compile_options(${TEST_NAME} PUBLIC -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wsign-conversion)
endif()
target_link_libraries(${TEST_NAME} PUBLIC fast_float)
endfunction(fast_float_add_cpp_test)
fast_float_add_cpp_test(short_random_string)

View File

@ -10,7 +10,7 @@ template <typename T> std::string to_string(T d) {
std::string s(64, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.*e",
std::numeric_limits<T>::max_digits10 - 1, d);
s.resize(written);
s.resize(size_t(written));
return s;
}
@ -18,7 +18,7 @@ template <typename T> std::string to_long_string(T d) {
std::string s(4096, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.*e",
std::numeric_limits<T>::max_digits10 * 10, d);
s.resize(written);
s.resize(size_t(written));
return s;
}
@ -134,7 +134,7 @@ bool issue8() {
auto answer = fast_float::from_chars(s, s + strlen(s) - i, d);
if(answer.ec != std::errc()) { std::cerr << "parsing failure\n"; return false; }
if(d != 0x1.921fb54442d18p+1) {
printf("%.*s\n", int(strlen(s) - i), s);
printf("%.*s\n", int(strlen(s) - size_t(i)), s);
std::cout << std::hexfloat << d << std::endl;
std::cout << std::defaultfloat << d << std::endl;
return false;
@ -192,7 +192,6 @@ bool test_scientific_only() {
return false;
}
input = "3.14e10";
result;
answer = fast_float::from_chars(input.data(), input.data()+input.size(), result, fast_float::chars_format::scientific);
if(answer.ec != std::errc()) {
std::cerr << "It is scientific!\n";
@ -309,7 +308,7 @@ bool test_fixed_only() {
for (int i = start_point; i <= 308; ++i) {// large negative values should be zero.
std::cout << ".";
std::cout.flush();
size_t n = snprintf(buf, sizeof(buf), "1e%d", i);
size_t n = size_t(snprintf(buf, sizeof(buf), "1e%d", i));
if (n >= sizeof(buf)) { abort(); }
double actual;
auto result = fast_float::from_chars(buf, buf + 1000, actual);
@ -335,6 +334,7 @@ int main() {
Assert(issue19());
Assert(check_behavior());
std::cout << "======= 64 bits " << std::endl;
Assert(basic_test_64bit("1.1920928955078125e-07",1.1920928955078125e-07));
Assert(basic_test_64bit("INF",std::numeric_limits<double>::infinity()));
Assert(basic_test_64bit("-INF",-std::numeric_limits<double>::infinity()));
Assert(basic_test_64bit("INFINITY",std::numeric_limits<double>::infinity()));
@ -450,7 +450,7 @@ int main() {
Assert(basic_test_32bit("0.0015924838953651488",0x1.a175cap-10f));
Assert(basic_test_32bit("0.0008602388261351734",0.0008602388261351734f));
Assert(basic_test_32bit("0.00036393293703440577",0x1.7d9c82p-12f));
Assert(basic_test_32bit("0.00013746770127909258",0.00013746770127909258));
Assert(basic_test_32bit("0.00013746770127909258",0.00013746770127909258f));
Assert(basic_test_32bit("16407.9462890625", 16407.9462890625f));
Assert(basic_test_32bit("1.1754947011469036e-38", 0x1.000006p-126f));
Assert(basic_test_32bit("7.0064923216240854e-46", 0x1p-149f));
@ -458,7 +458,7 @@ int main() {
Assert(basic_test_32bit("0e9999999999999999999999999999", 0));
Assert(basic_test_32bit("1234456789012345678901234567890e9999999999999999999999999999", std::numeric_limits<float>::infinity()));
Assert(basic_test_32bit("4.7019774032891500318749461488889827112746622270883500860350068251e-38",4.7019774032891500318749461488889827112746622270883500860350068251e-38f));
Assert(basic_test_32bit("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679));
Assert(basic_test_32bit("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679", 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f));
Assert(basic_test_32bit("2.3509887016445750159374730744444913556373311135441750430175034126e-38", 2.3509887016445750159374730744444913556373311135441750430175034126e-38f));
Assert(basic_test_32bit("+1", 1));
Assert(basic_test_32bit("2e3000", std::numeric_limits<float>::infinity()));
@ -472,9 +472,9 @@ int main() {
Assert(basic_test_32bit("3.4028234665e38", 0x1.fffffep+127f));
Assert(basic_test_32bit("3.4028234666e38", 0x1.fffffep+127f));
Assert(basic_test_32bit("0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625", 0.000000000000000000000000000000000000011754943508222875079687365372222456778186655567720875215087517062784172594547271728515625));
Assert(basic_test_32bit("0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125", 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125));
Assert(basic_test_32bit("0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875", 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875));
Assert(basic_test_32bit("0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875", 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875));
Assert(basic_test_32bit("0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125", 0.00000000000000000000000000000000000000000000140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125f));
Assert(basic_test_32bit("0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875", 0.00000000000000000000000000000000000002350988561514728583455765982071533026645717985517980855365926236850006129930346077117064851336181163787841796875f));
Assert(basic_test_32bit("0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875", 0.00000000000000000000000000000000000001175494210692441075487029444849287348827052428745893333857174530571588870475618904265502351336181163787841796875f));
std::cout << std::endl;
Assert(powers_of_ten());

View File

@ -19,7 +19,7 @@ void allvalues() {
std::cout << ".";
std::cout.flush();
}
uint32_t word = w;
uint32_t word = uint32_t(w);
memcpy(&v, &word, sizeof(v));
{

View File

@ -11,6 +11,37 @@ template <typename T> char *to_string(T d, char *buffer) {
return buffer + written;
}
bool basic_test_64bit(std::string vals, double val) {
double result_value;
auto result = fast_float::from_chars(vals.data(), vals.data() + vals.size(),
result_value);
if (result.ec != std::errc()) {
std::cerr << " I could not parse " << vals << std::endl;
return false;
}
if(copysign(1,result_value) != copysign(1,val)) {
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
<< std::endl;
return false;
} else if (std::isnan(val)) {
if (!std::isnan(result_value)) {
std::cerr << vals << std::endl;
std::cerr << "not nan" << result_value << std::endl;
return false;
}
} else if (result_value != val) {
std::cerr << vals << std::endl;
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << val
<< std::endl;
std::cerr << std::dec;
std::cerr << "string: " << vals << std::endl;
return false;
}
return true;
}
void all_32bit_values() {
char buffer[64];
for (uint64_t w = 0; w <= 0xFFFFFFFF; w++) {
@ -25,28 +56,9 @@ void all_32bit_values() {
{
const char *string_end = to_string(v, buffer);
double result_value;
auto result = fast_float::from_chars(buffer, string_end, result_value);
if (result.ec != std::errc()) {
std::cerr << "parsing error ? " << buffer << std::endl;
abort();
}
if(copysign(1,result_value) != copysign(1,v)) {
std::cerr << buffer << std::endl;
std::cerr << "I got " << std::hexfloat << result_value << " but I was expecting " << v
<< std::endl;
abort();
} else if (std::isnan(v)) {
if (!std::isnan(result_value)) {
std::cerr << "not nan" << buffer << std::endl;
abort();
}
} else if (result_value != v) {
std::cerr << "no match ? " << buffer << std::endl;
std::cout << "started with " << std::hexfloat << v << std::endl;
std::cout << "got back " << std::hexfloat << result_value << std::endl;
std::cout << std::dec;
abort();
std::string s(buffer, size_t(string_end-buffer));
if(!basic_test_64bit(s,v)) {
return;
}
}
}

View File

@ -53,7 +53,7 @@ void allvalues() {
std::cout << ".";
std::cout.flush();
}
uint32_t word = w;
uint32_t word = uint32_t(w);
memcpy(&v, &word, sizeof(v));
if(std::isfinite(v)) {
float nextf = std::nextafterf(v, INFINITY);
@ -64,7 +64,7 @@ void allvalues() {
double v2{nextf};
assert(float(v2) == nextf);
double midv{v1 + (v2 - v1) / 2};
float expected_midv(midv);
float expected_midv = float(midv);
const char *string_end = to_string(midv, buffer);
float str_answer;

View File

@ -24,7 +24,7 @@ double cygwin_strtod_l(const char* start, char** end) {
class RandomEngine {
public:
RandomEngine() = delete;
RandomEngine(int new_seed) { wyhash64_x_ = new_seed; };
RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) {};
uint64_t next() {
// Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
// Inspired from
@ -47,7 +47,7 @@ public:
/* if (min == max) {
return min;
}*/
int s = max - min + 1;
uint64_t s = uint64_t(max - min + 1);
uint64_t x = next();
fast_float::value128 m = fast_float::full_multiplication(x, s);
uint64_t l = m.low;
@ -59,7 +59,7 @@ public:
l = m.low;
}
}
return (m.high) + min;
return int(m.high) + min;
}
int next_digit() { return next_ranged_int(0, 9); }
@ -78,8 +78,8 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
number_of_digits = rand.next_ranged_int(1, 2000);
}
int location_of_decimal_separator = rand.next_ranged_int(1, number_of_digits);
for (size_t i = 0; i < number_of_digits; i++) {
if (i == location_of_decimal_separator) {
for (size_t i = 0; i < size_t(number_of_digits); i++) {
if (i == size_t(location_of_decimal_separator)) {
buffer[pos++] = '.';
}
buffer[pos++] = char(rand.next_digit() + '0');
@ -98,7 +98,7 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
}
}
number_of_digits = rand.next_ranged_int(1, 3);
for (size_t i = 0; i < number_of_digits; i++) {
for (size_t i = 0; i < size_t(number_of_digits); i++) {
buffer[pos++] = char(rand.next_digit() + '0');
}
}
@ -146,7 +146,7 @@ std::pair<float, bool> strtof_from_string(char *st) {
* We generate random strings and we try to parse them with both strtod/strtof,
* and we verify that we get the same answer with with fast_float::from_chars.
*/
bool tester(int seed, size_t volume) {
bool tester(uint64_t seed, size_t volume) {
char buffer[4096]; // large buffer (can't overflow)
RandomEngine rand(seed);
for (size_t i = 0; i < volume; i++) {

View File

@ -24,7 +24,7 @@ double cygwin_strtod_l(const char* start, char** end) {
class RandomEngine {
public:
RandomEngine() = delete;
RandomEngine(int new_seed) { wyhash64_x_ = new_seed; };
RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed) { };
uint64_t next() {
// Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
// Inspired from
@ -47,7 +47,7 @@ public:
/* if (min == max) {
return min;
}*/
int s = max - min + 1;
uint64_t s = uint64_t(max - min + 1);
uint64_t x = next();
fast_float::value128 m = fast_float::full_multiplication(x, s);
uint64_t l = m.low;
@ -59,7 +59,7 @@ public:
l = m.low;
}
}
return (m.high) + min;
return int(m.high) + min;
}
int next_digit() { return next_ranged_int(0, 9); }
@ -74,8 +74,8 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
}
int number_of_digits = rand.next_ranged_int(1, 19);
int location_of_decimal_separator = rand.next_ranged_int(1, number_of_digits);
for (size_t i = 0; i < number_of_digits; i++) {
if (i == location_of_decimal_separator) {
for (size_t i = 0; i < size_t(number_of_digits); i++) {
if (i == size_t(location_of_decimal_separator)) {
buffer[pos++] = '.';
}
buffer[pos++] = char(rand.next_digit() + '0');
@ -94,7 +94,7 @@ size_t build_random_string(RandomEngine &rand, char *buffer) {
}
}
number_of_digits = rand.next_ranged_int(1, 3);
for (size_t i = 0; i < number_of_digits; i++) {
for (size_t i = 0; i < size_t(number_of_digits); i++) {
buffer[pos++] = char(rand.next_digit() + '0');
}
}
@ -142,7 +142,7 @@ std::pair<float, bool> strtof_from_string(char *st) {
* We generate random strings and we try to parse them with both strtod/strtof,
* and we verify that we get the same answer with with fast_float::from_chars.
*/
bool tester(int seed, size_t volume) {
bool tester(uint64_t seed, size_t volume) {
char buffer[4096]; // large buffer (can't overflow)
RandomEngine rand(seed);
for (size_t i = 0; i < volume; i++) {

View File

@ -30,7 +30,7 @@ template <typename T> std::string to_string(T d) {
std::string s(64, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.*e",
std::numeric_limits<T>::max_digits10 - 1, d);
s.resize(written);
s.resize(size_t(written));
return s;
}