fast_float

fast_float

快速解析数值的C++库 性能超越标准库

fast_float是一个高性能C++头文件库,用于快速解析ASCII字符串中的数值。它提供类似C++17 from_chars的API,支持精确舍入,性能远超标准库实现。该库无需内存分配,可解析特殊值,支持C++20编译时计算,已被GCC、Chromium等重要项目采用。

fast_float数字解析C++库性能优化浮点数转换Github开源项目

fast_float 数字解析库:比 strtod 快 4 倍

fast_float 库为 C++ 的 floatdouble 类型以及整数类型提供了快速的仅头文件实现的 from_chars 函数。这些函数将表示十进制值的 ASCII 字符串(如 1.3e10)转换为二进制类型。我们提供精确舍入(包括向偶数舍入)。根据我们的经验,这些 fast_float 函数比现有 C++ 标准库中的同类数字解析函数快很多倍。

具体来说,fast_float 提供了以下两个函数来解析浮点数,语法类似于 C++17(库本身只需要 C++11):

from_chars_result from_chars(const char* first, const char* last, float& value, ...); from_chars_result from_chars(const char* first, const char* last, double& value, ...);

你也可以解析整数类型:

返回类型(from_chars_result)定义为以下结构体:

struct from_chars_result { const char* ptr; std::errc ec; };

它解析字符序列 [first,last) 中的数字。它解析浮点数时期望一种与 C++17 from_chars 函数等效的与区域设置无关的格式。 结果浮点值是最接近的浮点值(使用 float 或 double),对于恰好落在两个值之间的数值,使用"向偶数舍入"约定。 也就是说,我们根据 IEEE 标准提供精确解析。

解析成功时,返回值中的指针(ptr)被设置为指向解析后的数字之后,并且引用的 value 被设置为解析后的值。如果出错,返回的 ec 包含一个代表性错误,否则存储默认值(std::errc())。

实现不会抛出异常,也不会分配内存(例如,使用 newmalloc)。

它可以解析无穷大和 NaN 值。

示例:

#include "fast_float/fast_float.h" #include <iostream> int main() { const 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 << "解析失败\n"; return EXIT_FAILURE; } std::cout << "解析到的数字为 " << result << std::endl; return EXIT_SUCCESS; }

你可以解析带分隔符的数字:

const 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()) { // 检查错误 } // 此时 result == 234532.3426362 if(answer.ptr[0] != ',') { // 意外的分隔符 } answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result); if(answer.ec != std::errc()) { // 检查错误 } // 此时 result == 7869234.9823 if(answer.ptr[0] != ',') { // 意外的分隔符 } answer = fast_float::from_chars(answer.ptr + 1, input.data()+input.size(), result); if(answer.ec != std::errc()) { // 检查错误 } // 此时 result == 324562.645

与 C++17 标准一样,fast_float::from_chars 函数接受一个可选的最后参数,类型为 fast_float::chars_format。这是一个位集值:我们检查 fmt & fast_float::chars_format::fixedfmt & fast_float::chars_format::scientific 是否设置,以确定我们是否允许定点和科学计数法。默认值是 fast_float::chars_format::general,它允许 fixedscientific 两种格式。

该库遵循 C++17 规范(参见 20.19.3.(7.1))。

  • from_chars 函数不跳过前导空白字符。
  • 不允许前导 +
  • 通常不可能将十进制值精确表示为二进制浮点数(floatdouble 类型)。我们寻找最接近的值。当介于两个二进制浮点数之间时,我们向偶数尾数舍入。

此外,我们有以下限制:

  • 目前我们只支持 floatdouble 类型。
  • 我们只支持十进制格式:不支持十六进制字符串。
  • 对于非常大或非常小的值(例如 1e9999),我们用无穷大或负无穷大值表示,并将返回的 ec 设置为 std::errc::result_out_of_range

我们支持 Visual Studio、macOS、Linux、freeBSD。我们支持大端和小端。我们支持 32 位和 64 位系统。

我们假设舍入模式设置为最近值(std::fegetround() == FE_TONEAREST)。

整数类型

你也可以使用不同的进制(例如 2、10、16)解析整数类型。以下代码将打印数字 22250738585072012 三次:

uint64_t i; const char str[] = "22250738585072012"; auto answer = fast_float::from_chars(str, str + strlen(str), i); if (answer.ec != std::errc()) { std::cerr << "解析失败\n"; return EXIT_FAILURE; } std::cout << "解析到的数字为 "<< i << std::endl; const char binstr[] = "1001111000011001110110111001001010110100111000110001100"; answer = fast_float::from_chars(binstr, binstr + strlen(binstr), i, 2); if (answer.ec != std::errc()) { std::cerr << "解析失败\n"; return EXIT_FAILURE; } std::cout << "解析到的数字为 "<< i << std::endl; const char hexstr[] = "4f0cedc95a718c"; answer = fast_float::from_chars(hexstr, hexstr + strlen(hexstr), i, 16); if (answer.ec != std::errc()) { std::cerr << "解析失败\n"; return EXIT_FAILURE; } std::cout << "解析到的数字为 "<< i << std::endl;

C++20:编译时求值(constexpr)

在 C++20 中,你可以使用 fast_float::from_chars 在编译时解析字符串,如下例所示:

// consteval 在 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; } // 这个函数应该编译为一个仅返回 3.1415 的函数。 constexpr double constexptest() { return parse("3.1415 input"); }

C++23:固定宽度浮点类型

该库还支持固定宽度的浮点类型,如 std::float32_tstd::float64_t。例如,你可以这样写:

std::float32_t result; auto answer = fast_float::from_chars(f.data(), f.data() + f.size(), result);

非ASCII输入

我们还支持UTF-16和UTF-32输入,以及ASCII/UTF-8,如下例所示:

#include "fast_float/fast_float.h" #include <iostream> int main() { const 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; }

高级选项:使用逗号作为小数分隔符、JSON和Fortran

C++标准规定 from_chars 必须与区域设置无关。特别是,小数分隔符必须是句点(.)。然而,一些用户仍然希望以区域相关的方式使用 fast_float 库。通过使用名为 from_chars_advanced 的单独函数,我们允许用户传递一个包含自定义小数分隔符(例如逗号)的 parse_options 实例。你可以像这样使用它:

#include "fast_float/fast_float.h" #include <iostream> int main() { const 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; }

你也可以解析类似Fortran的输入:

#include "fast_float/fast_float.h" #include <iostream> int main() { const 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; }

你也可以强制使用JSON格式(RFC 8259):

#include "fast_float/fast_float.h" #include <iostream> int main() { const std::string input = "+.1"; // 不合法 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() { const std::string input = "inf"; // 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; } }

你可以使用非标准的 json_or_infnan 变体来允许它:

#include "fast_float/fast_float.h" #include <iostream> int main() { const std::string input = "inf"; // JSON中不合法,但我们通过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库是以下项目的一部分:

  • GCC(从版本12开始):GCC中的 from_chars 函数依赖于fast_float。
  • Chromium,Google Chrome和Microsoft Edge浏览器背后的引擎。
  • WebKit,Safari(苹果的网络浏览器)背后的引擎。
  • DuckDB
  • Apache Arrow,将数字解析速度提高了两到三倍。
  • Google Jsonnet
  • ClickHouse

fastfloat算法是LLVM标准库的一部分。AdaCore有一个衍生实现

fast_float库提供了与fast_double_parser库相似的性能,但使用了从头重新设计的更新算法,同时提供了更符合C++程序员期望的API。fast_double_parser库是Microsoft LightGBM机器学习框架的一部分。

参考文献

其他编程语言

它有多快?

在某些系统上,它可以以1 GB/s的速度解析随机浮点数。我们发现它通常比最好的可用竞争对手快两倍,比许多标准库实现快很多倍。

<img src="https://yellow-cdn.veclightyear.com/0a4dffa0/e9a76bcd-76fa-451e-8fd3-379bf577458e.png" width="400"> ``` $ ./build/benchmarks/benchmark # 解析范围在[0,1)的随机整数 体积 = 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 查看我们的基准测试代码。

视频

Go Systems 2020<br />

作为 CMake 依赖使用

本库设计为仅头文件。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/lemire/fast_float.git GIT_TAG tags/v1.1.2 GIT_SHALLOW TRUE) FetchContent_MakeAvailable(fast_float) target_link_libraries(myprogram PUBLIC fast_float)

您应该更改 GIT_TAG 行,以获取您希望使用的版本。

作为单一头文件使用

如果需要,可以使用 script/amalgamate.py 脚本生成库的单一头文件版本。 只需从此仓库的根目录运行脚本即可。 如果需要,您可以按照命令行帮助中的说明自定义许可证类型和输出文件。

您可以直接下载自动生成的单一头文件:

https://github.com/fastfloat/fast_float/releases/download/v6.1.4/fast_float.h

RFC 7159

如果您需要支持 RFC 7159(JSON 标准),您可能需要考虑使用 fast_double_parser 库。

致谢

尽管这项工作受到许多不同人的启发,但它特别受益于与 Michael Eisel 的交流,他以其关键见解激发了原始研究,以及与 Nigel Tao 的交流,他提供了宝贵的反馈。Rémy Oudompheng 首次实现了我们在长位数情况下使用的快速路径。

该库包含了改编自 Google Wuffs(由 Nigel Tao 编写)的代码,该代码最初是在 Apache 2.0 许可下发布的。

许可证

<sup> 根据 <a href="LICENSE-APACHE">Apache License, Version 2.0</a>、<a href="LICENSE-MIT">MIT license</a> 或 <a href="LICENSE-BOOST">BOOST license</a> 三者之一授权。 </sup> <br> <sub> 除非您另有明确声明,否则您有意提交以包含在本仓库中的任何贡献,如 Apache-2.0 许可中所定义,均应按上述方式三重许可,无任何附加条款或条件。 </sub>

编辑推荐精选

问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

下拉加载更多