快速解析浮点数的C++库:fast_float的from_chars函数

需积分: 9 1 下载量 112 浏览量 更新于2024-11-14 收藏 133KB ZIP 举报
资源摘要信息:"快速实现浮点和双精度类型的C ++ from_chars函数-C/C++开发" 本资源聚焦于介绍一个名为fast_float的库,它提供了一个仅用于头文件的快速实现,用于在C++中将ASCII字符串转换为浮点类型(float)和双精度类型(double)。这个库被称为fast_float数字解析库,它专注于处理浮点数和双精度数的字符串到二进制类型的转换,并且提供了精确的舍入控制,包括了所谓的“舍入到偶数”(round-to-even,也就是银行家舍入法)。根据开发者的说法,fast_float库提供的这些函数在性能上优于其他可比较的数字解析库。 接下来,我们将详细介绍fast_float库的关键知识点,包括它解决的问题、它的实现机制、性能特点以及如何使用它。 ### 关键知识点 #### 1. C++ from_chars函数的作用 在C++中,`from_chars`是一个用于字符串和数值类型之间转换的函数,它可以在标准库中找到,例如在`<charconv>`头文件中。这个函数允许程序员将表示数字的字符串(如"1234"、"1.234"、"3.14e-2"等格式)转换为相应的数值类型(如`int`、`float`、`double`等)。这个函数很强大,因为它不仅提供了转换的功能,而且还支持可配置的舍入模式和格式化错误处理。 #### 2. fast_float库的优势 fast_float库在设计上是轻量级的,并且专注于处理浮点数和双精度数的字符串到数值类型的转换。它提供了以下两个主要的函数: - `from_chars`:用于将ASCII字符串转换为float类型的数值。 - `from_chars`:用于将ASCII字符串转换为double类型的数值。 fast_float库的优势在于其速度。开发者声称,fast_float的实现比任何其他现有的、可比较的C++浮点数解析库都要快。它之所以快速,很大程度上是因为它尽可能减少了不必要的转换步骤,以及利用了现代编译器和硬件的优化特性。 #### 3. 精确的舍入控制 快速并不意味着牺牲精度。fast_float库提供了精确的舍入控制,其中包括了舍入到偶数的选项。这种舍入模式是一种常见的数值分析中用来最小化累积误差的策略,它在一些金融和科学计算中是特别重要的。快速实现精确舍入的浮点数转换是一个挑战,但fast_float库通过其高效的算法和编码实践,成功地做到了这一点。 #### 4. 使用场景和限制 虽然fast_float提供了很多优点,但它仍然有它的使用场景限制。首先,它依赖于C++的某些特定编译器特性,这意味着它的可移植性可能会受到限制。其次,它主要关注浮点数和双精度数的解析,对于其他数值类型(如整数、长双精度等)并不提供优化的实现。此外,它主要适用于性能敏感的应用场景,比如科学计算、图形渲染、游戏开发等。 #### 5. 如何使用fast_float 要使用fast_float库,用户需要将其头文件包含到C++源代码中。由于fast_float仅提供头文件,因此不需要进行编译链接。在使用前,需要确保你的编译器支持C++17标准或更高,因为`from_chars`函数在C++17中引入。用户可以通过简单的包含操作来调用库提供的函数,并传入相应的ASCII字符串和输出变量来完成转换。 #### 6. 性能分析和基准测试 fast_float库在发布时通常会附带基准测试结果,这些结果展示了与其他知名解析库(如`std::from_chars`、第三方库如`tinyexpr`、`mpark`等)的性能对比。通常这些测试会针对不同的输入数据集(包括各种大小、格式和复杂度的数字字符串)执行,并报告解析速度、吞吐量以及是否满足库声称的性能指标。 ### 总结 fast_float库为C++开发者提供了一个快速而精确的浮点数和双精度数解析方法。其设计目标是为性能敏感型应用提供一个高效的解决方案,同时没有牺牲标准和精确性。在选择使用fast_float时,开发者应该考虑到其性能优势和适用场景,并进行适当的测试来确保它满足应用需求。

static void check_efuse(void) { #if CONFIG_IDF_TARGET_ESP32 //Check if TP is burned into eFuse if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { printf("eFuse Two Point: Supported\n"); } else { printf("eFuse Two Point: NOT supported\n"); } //Check Vref is burned into eFuse if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) { printf("eFuse Vref: Supported\n"); } else { printf("eFuse Vref: NOT supported\n"); } #elif CONFIG_IDF_TARGET_ESP32S2 if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { printf("eFuse Two Point: Supported\n"); } else { printf("Cannot retrieve eFuse Two Point calibration values. Default calibration values will be used.\n"); } #else #error "This example is configured for ESP32/ESP32S2." #endif } static void print_char_val_type(esp_adc_cal_value_t val_type) { if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) { printf("Characterized using Two Point Value\n"); } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) { printf("Characterized using eFuse Vref\n"); } else { printf("Characterized using Default Vref\n"); } } void app_main(void) { //Check if Two Point or Vref are burned into eFuse check_efuse(); //Configure ADC if (unit == ADC_UNIT_1) { adc1_config_width(width); adc1_config_channel_atten(channel, atten); } else { adc2_config_channel_atten((adc2_channel_t)channel, atten); } //Characterize ADC adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars); print_char_val_type(val_type); //Continuously sample ADC1 while (1) { uint32_t adc_reading = 0; //Multisampling for (int i = 0; i < NO_OF_SAMPLES; i++) { if (unit == ADC_UNIT_1) { adc_reading += adc1_get_raw((adc1_channel_t)channel); } else { int raw; adc2_get_raw((adc2_channel_t)channel, width, &raw); adc_reading += raw; } } adc_reading /= NO_OF_SAMPLES; //Convert adc_reading to voltage in mV uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars); printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage); vTaskDelay(pdMS_TO_TICKS(1000)); } }

2023-06-09 上传