FAST_FLOAT庫為float和double類型以及整數類型的C ++功能提供了快速的僅標頭實現。這些函數將代表小數值(例如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相當的語言獨立格式從_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 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類型)。我們尋求最近的價值。當我們介於兩個二進制浮點數之間時,我們到達了一個均勻的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語言確定了這些小值超出範圍的先例。在這種情況下,通常將小值分析為零,而無限大。這就是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中,您可以在compile-time時使用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功能依賴於fast_float,FastFloat算法是LLVM標準庫的一部分。 Adacore有一個派生的實現部分。
FAST_FLOAT庫提供了類似於Fast_Double_Parser庫的性能,但使用從頭開始重新設計的更新算法,同時提供了與C ++程序員的期望更一致的API。 Fast_Double_Parser庫是Microsoft LightGBM機器學習框架的一部分。
rcppfastfloat的R綁定。fast-float-rust 。FastDoubleParser 。它用於傑克遜等重要係統。csFastFloat 。 它可以在某些系統上以1 GB/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文件提供了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/amalgamate.py來生成庫的單個標頭版本。只需從此存儲庫的根目錄中運行腳本即可。如果需要,您可以根據命令行幫助中所述自定義許可類型和輸出文件。
您可以直接下載自動生成的單頭文件:
https://github.com/fastfloat/fast_float/releases/download/v7.0.0.0/fast_float.h
fast_float-devel )。 儘管這項工作的靈感來自許多不同的人,但這項工作尤其受益於與邁克爾·艾塞爾(Michael Eisel)的交流,邁克爾·艾塞爾(Michael Eisel)以他的主要見解激發了原始研究,以及提供了寶貴反饋的奈傑爾·陶(Nigel Tao)。 RémyOudompheng首先實施了我們在長位數的情況下使用的快速路徑。
該庫包括根據Google Wuffs(由Nigel Tao撰寫)改編的代碼,該代碼最初是在Apache 2.0許可下發布的。