FAST_FLOAT 라이브러리는 float 및 double 유형 및 정수 유형에 대한 C ++ From_chars 기능에 대한 빠른 헤더 전용 구현을 제공합니다. 이러한 함수는 소수점 값 (예 : 1.3e10 )을 나타내는 ASCII 문자열을 이진 유형으로 변환합니다. 우리는 정확한 반올림을 제공합니다 (라운드에서 짝수 포함). 우리의 경험에 따르면, 이러한 fast_float 는 기존 C ++ 표준 라이브러리의 비슷한 숫자 정당 기능보다 여러 번 더 빠르게 작동합니다.
구체적으로, fast_float C ++ 17- 유사 구문으로 플로팅 지점 번호를 구문 분석하기위한 다음 두 가지 기능을 제공합니다 (라이브러리 자체는 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 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 유형의 마지막 인수를 선택합니다. 그것은 bitset 값입니다 : 우리는 fmt & fast_float::chars_format::fixed 및 fmt & fast_float::chars_format::scientific 각각 고정점과 과학 표기법을 허용하는지 여부를 결정하는지 확인합니다. 기본값은 fixed fast_float::chars_format::general 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 유형)와 정확히 소수점 값을 나타내는 것은 일반적으로 불가능합니다. 우리는 가장 가까운 가치를 추구합니다. 우리는 두 개의 바이너리 플로팅 포인트 숫자 사이에있을 때 균일 한 Mantissa로 돌아갑니다.또한 다음과 같은 제한 사항이 있습니다.
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 언어는 이러한 작은 값이 범위를 벗어났다는 선례를 확립했습니다. 이 경우 작은 값을 0으로 구문 분석하는 것이 관례입니다. 이것이 C 언어의 동작입니다 (예 : stdtod ). 이것이 Fast_float 라이브러리가 이어지는 동작입니다.
구체적으로, 우리는 Jonathan Wakely의 표준 해석을 따릅니다.
어쨌든 결과 값은 패턴과 일치하는 문자열 값에 가장 가까운 최대 두 개의 부동 소수점 값 중 하나입니다.
또한 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 to compile 시간에 문자열을 구문 분석 할 수 있습니다.
// 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 로케일 독립적이어야한다고 규정합니다. 특히, 소수 분리기는 기간이어야합니다 ( . ). 그러나 일부 사용자는 여전히 Locale 의존적 방식으로 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 함수는 FAST_FLOAT에 의존합니다.Fastfloat 알고리즘은 LLVM 표준 라이브러리의 일부입니다. Adacore의 파생 구현 부분이 있습니다.
FAST_FLOAT 라이브러리는 FAST_DOUBLE_PARSER 라이브러리와 유사한 성능을 제공하지만 처음부터 다시 작업 한 업데이트 된 알고리즘을 사용하고 C ++ 프로그래머의 기대에 따라 API를 더 많이 제공합니다. FAST_DOUBLE_PARSER 라이브러리는 Microsoft LightgBM 기계 학습 프레임 워크의 일부입니다.
rcppfastfloat 라는 R 결합이 있습니다.fast-float-rust 트라고합니다.FastDoubleParser 라는 Fast_float 라이브러리의 Java 포트가 있습니다. Jackson과 같은 중요한 시스템에 사용됩니다.csFastFloat 라는 Fast_float 라이브러리의 C# 포트가 있습니다. 일부 시스템에서 임의의 부동 소수점 수를 1GB/s 속도로 구문 분석 할 수 있습니다. 우리는 종종 최고의 경쟁자보다 두 배나 빠르며 많은 표준 라이브러리 구현보다 몇 배나 빠릅니다.
$ ./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 파일은 단지 include 디렉토리에 대한 포인터 인 fast_float 대상을 제공합니다.
CMAKE 프로젝트에서 fast_float 저장소를 삭제하면 이러한 방식으로 사용할 수 있어야합니다.
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/amalgamate.py 원하는 경우 라이브러리의 단일 헤더 버전을 생성하는 데 사용될 수 있습니다. 이 저장소의 루트 디렉토리에서 스크립트를 실행하십시오. 명령 줄 도움말에 설명 된대로 원하는 경우 라이센스 유형 및 출력 파일을 사용자 정의 할 수 있습니다.
자동으로 생성 된 단일 헤더 파일을 직접 다운로드 할 수 있습니다.
https://github.com/fastfloat/fast_float/releases/download/v7.0.0/fast_float.h
fast_float-devel )가 포함됩니다. 이 작품은 많은 다른 사람들로부터 영감을 얻었지만,이 작품은 특히 그의 주요 통찰력으로 원래 연구를 동기를 부여한 Michael Eisel과의 교류와 귀중한 피드백을 제공 한 Nigel Tao와의 교환에서 혜택을 받았습니다. Rémy Oudompheng은 먼저 긴 숫자의 경우 우리가 사용하는 빠른 경로를 구현했습니다.
이 라이브러리에는 원래 Apache 2.0 라이센스에 따라 게시 된 Google Wuffs (Nigel Tao가 작성)에서 조정 된 코드가 포함되어 있습니다.