FAST_FLOATライブラリはfloatおよびdoubleタイプのC ++ From_Chars関数、および整数タイプの高速ヘッダーのみの実装を提供します。これらの関数は、小数値を表すASCII文字列(例えば、 1.3e10 )をバイナリタイプに変換します。正確な丸めを提供します(ラウンドを含む)。私たちの経験では、これらのfast_floatは、既存のC ++標準ライブラリからの同等の数字を並べる機能よりも数倍高速に機能します。
具体的には、 fast_float 、C ++ 17のような構文を使用して浮動小数点数を解析するために、次の2つの関数を提供します(ライブラリ自体には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関数に相当するロケールに依存しない形式を期待する浮動小数点数を解析します。結果の浮動小数点値は、2つの値の間で正しい値に落ちる値に対して「ラウンドから偶数」の慣習を使用して、最も近いフローティングポイント値( 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 and fmt & fast_float::chars_format::scientificそれぞれ固定点と科学表記を許可するかどうかを判断するかどうかを確認します。デフォルトはfast_float::chars_format::general scientific fixed
ライブラリは、C ++ 17(28.2.3。(6.1))の仕様に従うことを目指しています。
from_chars関数は、主要なホワイトスペース文字をスキップしません( fast_float::chars_format::chars_formatが設定されていない場合)。+サインは禁止されています( fast_float::chars_format::skip_white_spaceが設定されていない場合)。floatおよびdoubleタイプ)とまったく同じ小数値を表すことは不可能です。私たちは最も近い価値を求めます。 2つのバイナリフローティングポイント数の間にいるとき、私たちはさらにマンティッサに丸くなります。さらに、次の制限があります。
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を3回印刷します。
# 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の標準の解釈に従います。
いずれにせよ、結果の値は、パターンに一致する文字列の値に最も近い最大2つのフローティングポイント値の1つです。
また、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を考慮して、値を未修正のままにしたいユーザーは、2行のコードを追加することでそうすることができます。
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関数は、fast_floatに依存しています。FastFloatアルゴリズムは、LLVM標準ライブラリの一部です。 Adacoreの派生実装部分があります。
fast_floatライブラリは、fast_double_parserライブラリのパフォーマンスと同様のパフォーマンスを提供しますが、ゼロから再加工された更新されたアルゴリズムを使用し、C ++プログラマーの期待に沿ってAPIを提供します。 FAST_DOUBLE_PARSERライブラリは、Microsoft LightGBM Machine-Learningフレームワークの一部です。
rcppfastfloatと呼ばれるR結合があります。fast-float-rustと呼ばれます。FastDoubleParserと呼ばれるFast_FloatライブラリのJavaポートがあります。ジャクソンなどの重要なシステムに使用しました。csFastFloatと呼ばれるfast_floatライブラリのC#ポートがあります。 一部のシステムでは、ランダムな浮動小数点数を1 gb/sの速度で解析できます。多くの場合、利用可能な最高の競合他社の2倍の速さであり、多くの標準ライブラリの実装よりも速いことがわかります。
$ ./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ディレクトリへのポインターにすぎません。
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/fast_float.h
fast_float-develなど)が含まれます。 この作品は多くの異なる人々に触発されていますが、この作品は特に彼の重要な洞察を得た元の研究を動機付けたマイケル・アイゼルと、そして貴重なフィードバックを提供したナイジェル・タオとの交流から恩恵を受けました。 RémyOudomphengは、最初に長桁の場合に使用する高速パスを実装しました。
ライブラリには、もともとApache 2.0ライセンスの下で公開されていたGoogle Wuffs(Nigel Taoによって書かれた)から編集されたコードが含まれています。