Die Fast_float-Bibliothek bietet Fast-Header-Implementierungen für das C ++ von _chars-Funktionen für float und double sowie Ganzzahltypen. Diese Funktionen wandeln ASCII -Zeichenfolgen, die Dezimalwerte (z. B. 1.3e10 ) darstellen, in binäre Typen um. Wir bieten eine genaue Rundung (einschließlich Runde bis gleich). Nach unserer Erfahrung sind diese fast_float -Funktionen um ein Vielfaches schneller als vergleichbare Funktionen der Zahlenparsing aus vorhandenen C ++-Standardbibliotheken.
Insbesondere bietet fast_float die folgenden zwei Funktionen, um Schwimmpunktzahlen mit einer C ++ 17-ähnlichen Syntax zu analysieren (die Bibliothek selbst erfordert nur 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, ...);Sie können auch Ganzzahltypen analysieren:
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, ...); Der Rückgabetyp ( from_chars_result ) ist definiert als die Struktur:
struct from_chars_result {
char const *ptr;
std::errc ec;
}; Es analysiert die Zeichensequenz [first, last) für eine Zahl. Es analysiert schwimmende Punktzahlen und erwartet ein landschemaunabhängiges Format, das der C ++ 17-Funktion von _chars entspricht. Der resultierende Floating-Punkt-Wert ist die engsten Floating-Punkt-Werte (entweder float oder double ), wobei die "runde" Konvention für Werte verwendet wird, die sonst zwischen zwei Werten direkt fallen würden. Das heißt, wir bieten eine genaue Parsen nach dem IEEE -Standard.
Bei einem erfolgreichen Analyse wird der Zeiger ( ptr ) im zurückgegebenen Wert direkt nach der analysierten Zahl auf Punkt gesetzt, und der verwiesene value wird auf den Parsen -Wert festgelegt. Bei Fehler enthält die zurückgegebene ec einen repräsentativen Fehler, ansonsten wird der Wert ( std::errc() ) gespeichert.
Die Implementierung wirft nicht aus und gibt keinen Speicher zu (z. B. mit new oder malloc ).
Es wird Unendlichkeits- und NAN -Werte analysieren.
Beispiel:
# 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;
}Sie können abgrenzte Zahlen analysieren:
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. Wie der C ++ 17 Standard nehmen die Funktionen fast_float::from_chars ein optionales letztes Argument des Typs fast_float::chars_format . Es ist ein Bitset -Wert: Wir prüfen, ob fmt & fast_float::chars_format::fixed und fmt & fast_float::chars_format::scientific werden festgelegt, ob wir den Fixpunkt und die wissenschaftliche Notation zulassen. Die Standardeinstellung ist fast_float::chars_format::general was sowohl fixed als auch scientific ermöglicht.
Die Bibliothek versucht, die Spezifikation von C ++ 17 zu folgen (siehe 28.2.3. (6.1)).
from_chars überspringt keine führenden weißen Space-Zeichen (es sei denn, fast_float::chars_format::chars_format ist gesetzt).+ Zeichen ist verboten (es sei denn, fast_float::chars_format::skip_white_space ist festgelegt).float und double ) darzustellen. Wir suchen den nächsten Wert. Wir runden zu einer sogar Mantissa, wenn wir zwischen zwei binären Schwimmpunktzahlen sind.Darüber hinaus haben wir die folgenden Einschränkungen:
float und double , aber nicht long double . Wir unterstützen auch die Floating-Punkt-Typ mit fester Breite wie std::float32_t und std::float64_t .1e9999 ), repräsentieren wir sie unter Verwendung des Unendlichkeits- oder negativen Infinity -Werts und die zurückgegebene ec wird auf std::errc::result_out_of_range eingestellt.Wir unterstützen Visual Studio, MacOS, Linux, FreeBSD. Wir unterstützen Big and Little Endian. Wir unterstützen 32-Bit- und 64-Bit-Systeme.
Wir gehen davon aus, dass der Rundungsmodus auf am nächsten gesetzt ist ( std::fegetround() == FE_TONEAREST ).
Sie können auch ganzzahlige Typen mit verschiedenen Basen analysieren (z. B. 2, 10, 16). Der folgende Code druckt dreimal die Nummer 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;
} Bei der Parsen von Gleitkommawerten können die Zahlen manchmal zu klein (z. B. 1e-1000 ) oder zu groß (z. B. 1e1000 ) sein. Die C -Sprache hat den Präzedenzfall festgestellt, dass diese kleinen Werte außerhalb des Bereichs sind. In solchen Fällen ist es üblich, kleine Werte auf Null und große Werte an unendlich zu analysieren. Das ist das Verhalten der C -Sprache (z. B. stdtod ). Das ist das Verhalten der Fast_float -Bibliothek.
Insbesondere folgen wir Jonathan Wakelys Interpretation des Standards:
In jedem Fall ist der resultierende Wert einer der beiden zwei Schwimmpunktwerte, die dem Wert des Zeichens, der dem Muster entspricht, am nächsten kommt.
Es ist auch der Ansatz der Microsoft C ++ - Bibliothek.
Daher haben wir die folgenden Beispiele:
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() Benutzer std::errc::result_out_of_range die sich wünschen, dass der Wert nicht modifiziert wird
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; } In C ++ 20 können Sie fast_float::from_chars verwenden, um Strings bei der Kompilierungszeit zu analysieren, wie im folgenden Beispiel:
// 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 " );
} Die Bibliothek unterstützt auch die Floating-Punkt-Typen fester Breite wie std::float32_t und std::float64_t . ZB, Sie können schreiben:
std:: float32_t result;
auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);Wir unterstützen auch UTF-16- und UTF-32-Eingänge sowie ASCII/UTF-8, wie im folgenden Beispiel:
# 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;
} Der C ++-Standard muss feststellen, dass from_chars ein Ortsschema-unabhängig sein muss. Insbesondere muss der Dezimaltrennzeichen der Zeitraum sein ( . ). Einige Benutzer möchten jedoch die fast_float -Bibliothek in lokalabhängiger Weise verwenden. Mit einer separaten Funktion from_chars_advanced ermöglichen wir den Benutzern eine parse_options -Instanz, die einen benutzerdefinierten Dezimaltrennzeichen (z. B. das Komma) enthält. Sie können es wie folgt verwenden.
# 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;
} Standardmäßig erlaubt das JSON -Format inf nicht:
# 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;
} Sie können es mit einer nicht standardmäßigen json_or_infnan Variante zulassen:
# 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;
}Die Fast_float -Bibliothek ist Teil von:
from_chars in GCC stützt sich auf Fast_float.Der Fastfloat -Algorithmus ist Teil der LLVM -Standardbibliotheken. Es gibt einen abgeleiteten Implementierungsteil von Adacore.
Die Fast_float -Bibliothek bietet eine ähnliche Leistung wie die der Fast_Double_Parser -Bibliothek, aber ein aktualisierter Algorithmus, der von Grund auf überarbeitet wurde, und zwar eine API mehr im Einklang mit den Erwartungen an C ++ - Programmierer. Die Fast_Double_Parser-Bibliothek ist Teil des Microsoft LightGBM Machine-Lern-Frameworks.
rcppfastfloat bezeichnet wird.fast-float-rust bezeichnet wird.FastDoubleParser . Es wurde für wichtige Systeme wie Jackson verwendet.csFastFloat . Es kann zufällige Floating-Punkt-Zahlen mit einer Geschwindigkeit von 1 GB/s auf einigen Systemen analysieren. Wir stellen fest, dass es oft doppelt so schnell ist wie der beste verfügbare Konkurrent und um viele Male schneller als viele Standard-Bibliothek-Implementierungen.
$ ./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/sIn https://github.com/lemire/simple_fastfloat_benchmark finden Sie unseren Benchmarking -Code.
Diese Bibliothek ist nur für das Header für Design. Die CMake -Datei bietet das fast_float -Ziel, das lediglich ein Zeiger auf das include -Verzeichnis ist.
Wenn Sie das fast_float -Repository in Ihrem CMake -Projekt fallen lassen, sollten Sie es auf diese Weise verwenden können:
add_subdirectory (fast_float)
target_link_libraries (myprogram PUBLIC fast_float)Oder Sie möchten die Abhängigkeit automatisch abrufen, wenn Sie eine ausreichend aktuelle Version von CMake (zumindest besser) haben:
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) Sie sollten die GIT_TAG -Zeile ändern, damit Sie die Version wiederherstellen, die Sie verwenden möchten.
Sie können auch CPM verwenden, wie SO:
CPMAddPackage(
NAME fast_float
GITHUB_REPOSITORY "fastfloat/fast_float"
GIT_TAG v6.1.6) Das Skript script/amalgamate.py kann verwendet werden, um bei Bedarf eine einzelne Header -Version der Bibliothek zu generieren. Führen Sie einfach das Skript aus dem Stammverzeichnis dieses Repositorys aus. Sie können den Lizenztyp und die Ausgabedatei anpassen, falls dies in der Befehlszeile Hilfe gewünscht wird.
Sie können automatisch generierte Einzelhader-Dateien direkt herunterladen:
https://github.com/fastfloat/fast_float/releases/download/v7.0.0/fast_float.h
fast_float-devel ). Obwohl diese Arbeit von vielen verschiedenen Menschen inspiriert ist, profitierte diese Arbeit insbesondere aus dem Austausch mit Michael Eisel, der die ursprüngliche Forschung mit seinen wichtigsten Erkenntnissen motivierte, und mit Nigel Tao, der unschätzbares Feedback gab. Rémy Ou als Dimompeng hat zuerst einen schnellen Pfad implementiert, den wir bei langen Ziffern verwenden.
Die Bibliothek enthält Code, die von Google Wuffs (geschrieben von Nigel Tao) adaptiert wurden und ursprünglich unter der Apache 2.0 -Lizenz veröffentlicht wurde.