توفر مكتبة Fast_float تطبيقات سريعة للرأس فقط لوظائف C ++ From_Chars float الأنواع double وكذلك أنواع عدد صحيح. تقوم هذه الوظائف بتحويل سلاسل ASCII التي تمثل القيم العشرية (على سبيل المثال ، 1.3e10 ) إلى أنواع ثنائية. نحن نقدم تقريب الدقيق (بما في ذلك الجولة حتى). في تجربتنا ، تعمل 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 ).
سوف تحليل اللانهاية وقيم النان.
مثال:
# 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 يتم تعيينهم لتحديد ما إذا كنا نسمح للنقطة الثابتة والترميز العلمي على التوالي. الافتراضي هو 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. نحن ندعم Endian الكبير والسيخ. نحن ندعم أنظمة 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 ولكن باستخدام خوارزمية محدثة تم إعادة صياغتها من الألف إلى الياء ، وبينما تقدم واجهة برمجة التطبيقات أكثر تمشيا مع توقعات مبرمجي 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/amalgamate.py لإنشاء إصدار رأس واحد من المكتبة إذا رغبت في ذلك. فقط قم بتشغيل البرنامج النصي من الدليل الجذر لهذا المستودع. يمكنك تخصيص نوع الترخيص وملف الإخراج إذا رغبت في ذلك كما هو موضح في تعليمات سطر الأوامر.
يمكنك تنزيل ملفات رأس واحدة يتم إنشاؤها تلقائيًا:
https://github.com/fastfloat/fast_float/release/download/v7.0.0/fast_float.h
fast_float-devel ). على الرغم من أن هذا العمل مستوحى من العديد من الأشخاص المختلفين ، إلا أن هذا العمل استفاد خاصة من التبادلات مع مايكل إيسيل ، الذي حفز البحث الأصلي برؤىه الرئيسية ، ومع نايجل تاو الذي قدم ردود فعل لا تقدر بثمن. قام Rémy Oudompheng بتنفيذ مسار سريع نستخدمه في حالة الأرقام الطويلة.
تتضمن المكتبة رمزًا مقتبسًا من Google Wuffs (كتبه Nigel Tao) والذي تم نشره في الأصل بموجب ترخيص Apache 2.0.