replace float/double conversion with fast_float, update unit tests, update meson

This commit is contained in:
ado 2021-02-07 11:33:16 +01:00
parent a1ca012203
commit 9408c385d6
5 changed files with 25 additions and 107 deletions

View File

@ -2,6 +2,7 @@
#include "type_traits.hpp" #include "type_traits.hpp"
#include <cstring> #include <cstring>
#include <fast_float/fast_float.h>
#include <functional> #include <functional>
#include <limits> #include <limits>
#include <optional> #include <optional>
@ -14,104 +15,17 @@ namespace ss {
//////////////// ////////////////
// number converters // number converters
//////////////// ////////////////
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T> pow10(int n) {
T ret = 1.0;
T r = 10.0;
if (n < 0) {
n = -n;
r = 0.1;
}
while (n) {
if (n & 1) {
ret *= r;
}
r *= r;
n >>= 1;
}
return ret;
}
// TODO not working with large number of digits
template <typename T> template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num( std::enable_if_t<std::is_floating_point_v<T>, std::optional<T>> to_num(
const char* begin, const char* const end) { const char* begin, const char* const end) {
if (begin == end) { T ret;
auto answer = fast_float::from_chars(begin, end, ret);
if (answer.ec != std::errc() || answer.ptr != end) {
return std::nullopt; return std::nullopt;
} }
int sign = 1; return ret;
T int_part = 0.0;
T frac_part = 0.0;
bool has_frac = false;
bool has_exp = false;
// +/- sign
if (*begin == '-') {
++begin;
sign = -1;
}
while (begin != end) {
if (*begin >= '0' && *begin <= '9') {
int_part = int_part * 10 + (*begin - '0');
} else if (*begin == '.') {
has_frac = true;
++begin;
break;
} else if (*begin == 'e') {
has_exp = true;
++begin;
break;
} else {
return std::nullopt;
}
++begin;
}
if (has_frac) {
T frac_exp = 0.1;
while (begin != end) {
if (*begin >= '0' && *begin <= '9') {
frac_part += frac_exp * (*begin - '0');
frac_exp *= 0.1;
} else if (*begin == 'e') {
has_exp = true;
++begin;
break;
} else {
return std::nullopt;
}
++begin;
}
}
// parsing exponent part
T exp_part = 1.0;
if (begin != end && has_exp) {
int exp_sign = 1;
if (*begin == '-') {
exp_sign = -1;
++begin;
} else if (*begin == '+') {
++begin;
}
int e = 0;
while (begin != end && *begin >= '0' && *begin <= '9') {
e = e * 10 + *begin - '0';
++begin;
}
exp_part = pow10<T>(exp_sign * e);
}
if (begin != end) {
return std::nullopt;
}
return sign * (int_part + frac_part) * exp_part;
} }
inline std::optional<short> from_char(char c) { inline std::optional<short> from_char(char c) {
@ -249,7 +163,7 @@ bool shift_and_add_overflow(T& value, T digit, F add_last_digit_owerflow) {
} }
#else #else
#warning "use clang or gcc!!!" #warning "Use clang or gcc if possible."
template <typename T, typename U> template <typename T, typename U>
bool shift_and_add_overflow(T& value, T digit, U is_negative) { bool shift_and_add_overflow(T& value, T digit, U is_negative) {
digit = (is_negative) ? -digit : digit; digit = (is_negative) ? -digit : digit;

View File

@ -4,5 +4,12 @@ project('ssp', 'cpp',
'cpp_std=c++17', 'cpp_std=c++17',
'buildtype=debugoptimized']) 'buildtype=debugoptimized'])
includes = include_directories('include') fast_float_sub = subproject('fast_float')
fast_float_dep = fast_float_sub.get_variable('fast_float_dep')
ssp_dep = declare_dependency(
include_directories: include_directories('include'),
dependencies: fast_float_dep
)
subdir('test') subdir('test')

View File

@ -0,0 +1,3 @@
[wrap-git]
url = https://github.com/red0124/fast_float
revision = meson

View File

@ -9,11 +9,11 @@ test_sources = files([
doctest_proj = subproject('doctest') doctest_proj = subproject('doctest')
doctest_dep = doctest_proj.get_variable('doctest_dep') doctest_dep = doctest_proj.get_variable('doctest_dep')
test_exe = executable('test_ssp', test_exe = executable(
'test_ssp',
sources: test_sources, sources: test_sources,
dependencies: doctest_dep, dependencies: [doctest_dep, ssp_dep],
include_directories: includes,
cpp_args: '-lstdc++fs' cpp_args: '-lstdc++fs'
) )
test('tests_ssp', test_exe) test('test_ssp', test_exe)

View File

@ -2,11 +2,9 @@
#include <algorithm> #include <algorithm>
#include <ss/extract.hpp> #include <ss/extract.hpp>
constexpr auto eps = 0.000001;
using ld = long double;
#define CHECK_FLOATING_CONVERSION(input, type) \ #define CHECK_FLOATING_CONVERSION(input, type) \
{ \ { \
auto eps = std::numeric_limits<type>::min(); \
std::string s = #input; \ std::string s = #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
@ -14,6 +12,7 @@ using ld = long double;
} \ } \
{ \ { \
/* check negative too */ \ /* check negative too */ \
auto eps = std::numeric_limits<type>::min(); \
auto s = std::string("-") + #input; \ auto s = std::string("-") + #input; \
auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \ auto t = ss::to_num<type>(s.c_str(), s.c_str() + s.size()); \
REQUIRE(t.has_value()); \ REQUIRE(t.has_value()); \
@ -23,23 +22,18 @@ using ld = long double;
TEST_CASE("testing extract functions for floating point values") { TEST_CASE("testing extract functions for floating point values") {
CHECK_FLOATING_CONVERSION(123.456, float); CHECK_FLOATING_CONVERSION(123.456, float);
CHECK_FLOATING_CONVERSION(123.456, double); CHECK_FLOATING_CONVERSION(123.456, double);
CHECK_FLOATING_CONVERSION(123.456, ld);
CHECK_FLOATING_CONVERSION(69, float); CHECK_FLOATING_CONVERSION(69, float);
CHECK_FLOATING_CONVERSION(69, double); CHECK_FLOATING_CONVERSION(69, double);
CHECK_FLOATING_CONVERSION(69, ld);
CHECK_FLOATING_CONVERSION(420., float); CHECK_FLOATING_CONVERSION(420., float);
CHECK_FLOATING_CONVERSION(420., double); CHECK_FLOATING_CONVERSION(420., double);
CHECK_FLOATING_CONVERSION(420., ld);
CHECK_FLOATING_CONVERSION(0.123, float); CHECK_FLOATING_CONVERSION(0.123, float);
CHECK_FLOATING_CONVERSION(0.123, double); CHECK_FLOATING_CONVERSION(0.123, double);
CHECK_FLOATING_CONVERSION(0.123, ld);
CHECK_FLOATING_CONVERSION(123e4, float); CHECK_FLOATING_CONVERSION(123e4, float);
CHECK_FLOATING_CONVERSION(123e4, double); CHECK_FLOATING_CONVERSION(123e4, double);
CHECK_FLOATING_CONVERSION(123e4, ld);
} }
#define CHECK_DECIMAL_CONVERSION(input, type) \ #define CHECK_DECIMAL_CONVERSION(input, type) \