Библиотека FAST_FLOAT обеспечивает быстрые реализации только для функций C ++ FROM_CHARS для float и double типов, а также типов целочисленных целого числа. Эти функции преобразуют строки ASCII, представляющие десятичные значения (например, 1.3e10 ) в двоичные типы. Мы обеспечиваем точное округление (включая раунд до даже). По нашему опыту, эти функции fast_float во много раз быстрее, чем сопоставимые функции номера из существующих стандартных библиотек C ++.
В частности, fast_float предоставляет следующие две функции, чтобы анализировать числа с плавающей точкой с помощью 17-подобного синтаксиса C ++ (сама библиотека требует только C ++ 11):
from_chars_result from_chars ( char const *first, char const *last, float &value, ...);
from_chars_result from_chars ( char const *first, char const *last, double &value, ...);Вы также можете проанализировать типы целочисленных целогох:
from_chars_result from_chars ( char const *first, char const *last, int &value, ...);
from_chars_result from_chars ( char const *first, char const *last, unsigned &value, ...); Возвратный тип ( from_chars_result ) определяется как struct:
struct from_chars_result {
char const *ptr;
std::errc ec;
}; Он анализирует последовательность символов [first, last) для числа. Он анализирует числа с плавающей точкой, ожидая, что независимый от локали формат, эквивалентный функции C ++ 17 FROM_CHARS. Полученное значение с плавающей точкой является наиболее близким значениями с плавающей точкой (с использованием либо float , либо double ), используя соглашение «от округа до даже» для значений, которое в противном случае упало бы прямо между двумя значениями. То есть мы предоставляем точный анализ в соответствии со стандартом IEEE.
Учитывая успешный анализ, указатель ( ptr ) в возвращенном значении устанавливается на точку сразу после проанализированного числа, а ссылка на value установлено на проанализированное значение. В случае ошибки возвращаемый ec содержит репрезентативную ошибку, в противном случае сохраняется значение по умолчанию ( std::errc() ).
Реализация не бросает и не выделяет память (например, с new или malloc ).
Это будет проанализировать бесконечность и значения NAN.
Пример:
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " 3.1416 xyz " ;
double result;
auto answer = fast_float::from_chars (input. data (), input. data () + input. size (), result);
if (answer. ec != std::errc ()) { std::cerr << " parsing failure n " ; return EXIT_FAILURE; }
std::cout << " parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}Вы можете проанализировать разграниченные цифры:
std::string input = " 234532.3426362,7869234.9823,324562.645 " ;
double result;
auto answer = fast_float::from_chars(input.data(), input.data() + input.size(), result);
if (answer.ec != std::errc()) {
// check error
}
// we have result == 234532.3426362.
if (answer.ptr[ 0 ] != ' , ' ) {
// unexpected delimiter
}
answer = fast_float::from_chars(answer.ptr + 1 , input.data() + input.size(), result);
if (answer.ec != std::errc()) {
// check error
}
// we have result == 7869234.9823.
if (answer.ptr[ 0 ] != ' , ' ) {
// unexpected delimiter
}
answer = fast_float::from_chars(answer.ptr + 1 , input.data() + input.size(), result);
if (answer.ec != std::errc()) {
// check error
}
// we have result == 324562.645. Как и стандарт C ++ 17, функции fast_float::from_chars принимают необязательный последний аргумент типа fast_float::chars_format . Это значение битсета: мы проверяем, fmt & fast_float::chars_format::fixed и fmt & fast_float::chars_format::scientific устанавливаются, чтобы определить, разрешаем ли мы фиксированную точку и научную нотацию соответственно. По умолчанию это fast_float::chars_format::general , которая позволяет как fixed , так и scientific .
Библиотека стремится следовать спецификации C ++ 17 (см. 28.2.3. (6.1))).
from_chars не пропускает ведущие символы белого пространства (если не установлен fast_float::chars_format::chars_format ).+ знак запрещен (если не установлен fast_float::chars_format::skip_white_space ).float и double типы). Мы ищем ближайшую ценность. Мы переходим к ровной мантиссе, когда мы находимся между двумя бинарными номерами с плавающей точкой.Кроме того, у нас есть следующие ограничения:
float и double , но не long double . Мы также поддерживаем типы с плавающей точкой с фиксированной шириной, такие как std::float32_t и std::float64_t .1e9999 ), мы представляем его, используя бесконечность или отрицательную бесконечность, а возвращаемый ec установлен на std::errc::result_out_of_range .Мы поддерживаем Visual Studio, MacOS, Linux, FreeBSD. Мы поддерживаем Большого и Маленького Эндиана. Мы поддерживаем 32-битные и 64-битные системы.
Мы предполагаем, что режим округления установлен на ближайший ( std::fegetround() == FE_TONEAREST ).
Вы также можете проанализировать типы целочисленных целого числа, используя различные основы (например, 2, 10, 16). Следующий код будет распечатать номер 22250738585072012 три раза:
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
uint64_t i;
std::string str = " 22250738585072012 " ;
auto answer = fast_float::from_chars (str. data (), str. data () + str. size (), i);
if (answer. ec != std::errc ()) {
std::cerr << " parsing failure n " ;
return EXIT_FAILURE;
}
std::cout << " parsed the number " << i << std::endl;
std::string binstr = " 1001111000011001110110111001001010110100111000110001100 " ;
answer = fast_float::from_chars (binstr. data (), binstr. data () + binstr. size (), i, 2 );
if (answer. ec != std::errc ()) {
std::cerr << " parsing failure n " ;
return EXIT_FAILURE;
}
std::cout << " parsed the number " << i << std::endl;
std::string hexstr = " 4f0cedc95a718c " ;
answer = fast_float::from_chars (hexstr. data (), hexstr. data () + hexstr. size (), i, 16 );
if (answer. ec != std::errc ()) {
std::cerr << " parsing failure n " ;
return EXIT_FAILURE;
}
std::cout << " parsed the number " << i << std::endl;
return EXIT_SUCCESS;
} При анализе значений с плавающей точкой числа иногда могут быть слишком маленькими (например, 1e-1000 ) или слишком большими (например, 1e1000 ). Язык C установил прецедент, что эти небольшие значения находятся вне диапазона. В таких случаях обычно разрабатывать небольшие значения по нулевым и большим значениям до бесконечности. Это поведение языка C (например, stdtod ). Это поведение, за которым следует библиотека FAST_FLOAT.
В частности, мы следим за интерпретацией Джонатана Уэйкли стандарта:
В любом случае, результирующее значение является одним из двух значений с плавающей точкой, наиболее близким к значению строки, соответствующей шаблону.
Это также подход, используемый библиотекой Microsoft C ++.
Следовательно, у нас есть следующие примеры:
double result = - 1 ;
std::string str = " 3e-1000 " ;
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
// r.ec == std::errc::result_out_of_range
// r.ptr == str.data() + 7
// result == 0 double result = - 1 ;
std::string str = " 3e1000 " ;
auto r = fast_float::from_chars(str.data(), str.data() + str.size(), result);
// r.ec == std::errc::result_out_of_range
// r.ptr == str.data() + 6
// result == std::numeric_limits<double>::infinity() Пользователи, которые хотят, чтобы значение было оставлено неизменным std::errc::result_out_of_range
double old_result = result; // make copy
auto r = fast_float::from_chars(start, end, result);
if (r.ec == std::errc::result_out_of_range) { result = old_result; } В C ++ 20 вы можете использовать fast_float::from_chars чтобы разобрать строки во время компиляции, как в следующем примере:
// consteval forces compile-time evaluation of the function in C++20.
consteval double parse (std::string_view input) {
double result;
auto answer = fast_float::from_chars (input. data (), input. data () + input. size (), result);
if (answer. ec != std::errc ()) { return - 1.0 ; }
return result;
}
// This function should compile to a function which
// merely returns 3.1415.
constexpr double constexptest () {
return parse ( " 3.1415 input " );
} Библиотека также поддерживает типы с плавающей точкой с фиксированной шириной, такие как std::float32_t и std::float64_t . Например, вы можете написать:
std:: float32_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);Мы также поддерживаем входы UTF-16 и UTF-32, а также ASCII/UTF-8, как в следующем примере:
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::u16string input = u" 3.1416 xyz " ;
double result;
auto answer = fast_float::from_chars (input. data (), input. data () + input. size (), result);
if (answer. ec != std::errc ()) { std::cerr << " parsing failure n " ; return EXIT_FAILURE; }
std::cout << " parsed the number " << result << std::endl;
return EXIT_SUCCESS;
} Стандарт C ++ предусматривает, что from_chars должен быть независимым от локали. В частности, десятичный сепаратор должен быть периодом ( . ). Тем не менее, некоторые пользователи по-прежнему хотят использовать библиотеку fast_float в зависимости от локализации. Используя отдельную функцию, вызванную from_chars_advanced , мы позволяем пользователям передавать экземпляр parse_options , который содержит пользовательский десятичный сепаратор (например, запятая). Вы можете использовать его следующим образом.
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " 3,1416 xyz " ;
double result;
fast_float::parse_options options{fast_float::chars_format::general, ' , ' };
auto answer = fast_float::from_chars_advanced (input. data (), input. data () + input. size (), result, options);
if ((answer. ec != std::errc ()) || ((result != 3.1416 ))) { std::cerr << " parsing failure n " ; return EXIT_FAILURE; }
std::cout << " parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " 1d+4 " ;
double result;
fast_float::parse_options options{fast_float::chars_format::fortran};
auto answer = fast_float::from_chars_advanced (input. data (), input. data () + input. size (), result, options);
if ((answer. ec != std::errc ()) || ((result != 10000 ))) { std::cerr << " parsing failure n " ; return EXIT_FAILURE; }
std::cout << " parsed the number " << result << std::endl;
return EXIT_SUCCESS;
}# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " +.1 " ; // not valid
double result;
fast_float::parse_options options{fast_float::chars_format::json};
auto answer = fast_float::from_chars_advanced (input. data (), input. data () + input. size (), result, options);
if (answer. ec == std::errc ()) { std::cerr << " should have failed n " ; return EXIT_FAILURE; }
return EXIT_SUCCESS;
} По умолчанию формат JSON не позволяет inf :
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " inf " ; // not valid in JSON
double result;
fast_float::parse_options options{fast_float::chars_format::json};
auto answer = fast_float::from_chars_advanced (input. data (), input. data () + input. size (), result, options);
if (answer. ec == std::errc ()) { std::cerr << " should have failed n " ; return EXIT_FAILURE; }
return EXIT_SUCCESS;
} Вы можете разрешить это с нестандартным вариантом json_or_infnan :
# include " fast_float/fast_float.h "
# include < iostream >
int main () {
std::string input = " inf " ; // not valid in JSON but we allow it with json_or_infnan
double result;
fast_float::parse_options options{fast_float::chars_format::json_or_infnan};
auto answer = fast_float::from_chars_advanced (input. data (), input. data () + input. size (), result, options);
if (answer. ec != std::errc () || (! std::isinf (result))) { std::cerr << " should have parsed infinity n " ; return EXIT_FAILURE; }
return EXIT_SUCCESS;
}Библиотека FAST_FLOAT является частью:
from_chars в GCC зависит от fast_float,Алгоритм FastFloat является частью стандартных библиотек LLVM. Существует производная реализация часть Adacore.
Библиотека FAST_FLOAT обеспечивает производительность, аналогичную производительности библиотеки FAST_DOUBLE_PARSER, но использование обновленного алгоритма, переработанного с нуля, и, предлагая API больше в соответствии с ожиданиями программистов C ++. Библиотека FAST_DOUBLE_PARSER является частью машинного обучения Microsoft Lightgbm.
rcppfastfloat .fast-float-rust .FastDoubleParser . Он использовался для важных систем, таких как Джексон.csFastFloat . Он может анализировать случайные числа с плавающей точкой со скоростью 1 ГБ/с в некоторых системах. Мы обнаруживаем, что это часто в два раза быстрее, чем лучший доступный конкурент, и много раз быстрее, чем многие реализации стандартных библиотечных средств.
$ ./build/benchmarks/benchmark
# parsing random integers in the range [0,1)
volume = 2.09808 MB
netlib : 271.18 MB/s (+/- 1.2 %) 12.93 Mfloat/s
doubleconversion : 225.35 MB/s (+/- 1.2 %) 10.74 Mfloat/s
strtod : 190.94 MB/s (+/- 1.6 %) 9.10 Mfloat/s
abseil : 430.45 MB/s (+/- 2.2 %) 20.52 Mfloat/s
fastfloat : 1042.38 MB/s (+/- 9.9 %) 49.68 Mfloat/sСм. Https://github.com/lemire/simple_fastfloat_benchmark для нашего кода сравнительного анализа.
Эта библиотека только для заголовка по дизайну. Файл CMAKE предоставляет цель fast_float , которая является просто указателем на каталог include .
Если вы бросите репозиторий fast_float в свой проект CMAKE, вы сможете использовать его таким образом:
add_subdirectory (fast_float)
target_link_libraries (myprogram PUBLIC fast_float)Или вы можете автоматически получить зависимость, если у вас есть достаточно недавняя версия Cmake (по крайней мере, 3,11 или лучше):
FetchContent_Declare(
fast_float
GIT_REPOSITORY https://github.com/fastfloat/fast_float.git
GIT_TAG tags/v6.1.6
GIT_SHALLOW TRUE )
FetchContent_MakeAvailable(fast_float)
target_link_libraries (myprogram PUBLIC fast_float) Вы должны изменить линию GIT_TAG , чтобы вы восстановили версию, которую хотите использовать.
Вы также можете использовать CPM, как так:
CPMAddPackage(
NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v6.1.6) Script script/amalgamate.py может использоваться для создания одной версии библиотеки с одним заголовком, если это необходимо. Просто запустите сценарий из корневого каталога этого репозитория. Вы можете настроить тип лицензии и выходной файл при желании, как описано в справочнике командной строки.
Вы можете напрямую загружать автоматически сгенерированные файлы с одним заголовками:
https://github.com/fastfloat/fast_float/releases/download/v7.0.0/fast_float.h
fast_float-devel ). Хотя эта работа вдохновлена множеством разных людей, эта работа получила выгоду, особенно из обменов с Майклом Эйзелем, который мотивировал первоначальное исследование своим ключевым пониманием, и с Найджелом Тао, который предоставил бесценную обратную связь. Rémy Oudompheng сначала реализовал быстрый путь, который мы используем в случае длинных цифр.
Библиотека включает в себя код, адаптированный из Google Wuffs (написанный Найджелом Тао), который был первоначально опубликован по лицензии Apache 2.0.