Project Icon

fast_float

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

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

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的速度解析随机浮点数。我们发现它通常比最好的可用竞争对手快两倍,比许多标准库实现快很多倍。

``` $ ./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

作为 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 许可下发布的。

许可证

根据 Apache License, Version 2.0MIT licenseBOOST license 三者之一授权。
除非您另有明确声明,否则您有意提交以包含在本仓库中的任何贡献,如 Apache-2.0 许可中所定义,均应按上述方式三重许可,无任何附加条款或条件。
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号