gpt4 book ai didi

c++ - 为什么 snprintf 在打印单个数字时始终比 ostringstream 快 2 倍?

转载 作者:搜寻专家 更新时间:2023-10-31 00:27:26 25 4
gpt4 key购买 nike

我正在测试用 C++ 格式化 double 的各种方法,下面是我想出的一些代码:

#include <chrono>
#include <cstdio>
#include <random>
#include <vector>
#include <sstream>
#include <iostream>

inline long double currentTime()
{
const auto now = std::chrono::steady_clock::now().time_since_epoch();
return std::chrono::duration<long double>(now).count();
}

int main()
{
std::mt19937 mt(std::random_device{}());
std::normal_distribution<long double> dist(0, 1e280);
static const auto rng=[&](){return dist(mt);};
std::vector<double> numbers;
for(int i=0;i<10000;++i)
numbers.emplace_back(rng());

const int precMax=200;
const int precStep=10;

char buf[10000];
std::cout << "snprintf\n";
for(int precision=10;precision<=precMax;precision+=precStep)
{
const auto t0=currentTime();
for(const auto num : numbers)
std::snprintf(buf, sizeof buf, "%.*e", precision, num);
const auto t1=currentTime();
std::cout << "Precision " << precision << ": " << t1-t0 << " s\n";
}

std::cout << "ostringstream\n";
for(int precision=10;precision<=precMax;precision+=precStep)
{
std::ostringstream ss;
ss.precision(precision);
ss << std::scientific;
const auto t0=currentTime();
for(const auto num : numbers)
{
ss.str("");
ss << num;
}
const auto t1=currentTime();
std::cout << "Precision " << precision << ": " << t1-t0 << " s\n";
}
}

让我奇怪的是,起初,当精度小于 40 时,我或多或少获得了相同的性能。但是,2.1x 的区别在于 snprintf。查看我在 Core i7-4765T、Linux 32 位、g++ 5.5.0、libc 2.14.1 上的输出,使用 -march=native -O3 编译:

snprintf
Precision 10: 0.0262963 s
Precision 20: 0.035437 s
Precision 30: 0.0468597 s
Precision 40: 0.0584917 s
Precision 50: 0.0699653 s
Precision 60: 0.081446 s
Precision 70: 0.0925062 s
Precision 80: 0.104068 s
Precision 90: 0.115419 s
Precision 100: 0.128886 s
Precision 110: 0.138073 s
Precision 120: 0.149591 s
Precision 130: 0.161005 s
Precision 140: 0.17254 s
Precision 150: 0.184622 s
Precision 160: 0.195268 s
Precision 170: 0.206673 s
Precision 180: 0.218756 s
Precision 190: 0.230428 s
Precision 200: 0.241654 s
ostringstream
Precision 10: 0.0269695 s
Precision 20: 0.0383902 s
Precision 30: 0.0497328 s
Precision 40: 0.12028 s
Precision 50: 0.143746 s
Precision 60: 0.167633 s
Precision 70: 0.190878 s
Precision 80: 0.214735 s
Precision 90: 0.238105 s
Precision 100: 0.261641 s
Precision 110: 0.285149 s
Precision 120: 0.309025 s
Precision 130: 0.332283 s
Precision 140: 0.355797 s
Precision 150: 0.379415 s
Precision 160: 0.403452 s
Precision 170: 0.427337 s
Precision 180: 0.450668 s
Precision 190: 0.474012 s
Precision 200: 0.498061 s

所以我的主要问题是:造成这种双重差异的原因是什么?此外,如何使 ostringstream 的性能更接近 snprintf

注意:另一个问题,Why is snprintf faster than ostringstream or is it? ,和我的不一样。首先,那里没有具体的答案,为什么不同精度的单个数字的格式化速度较慢。其次,这个问题问的是“为什么它通常比较慢”,这个问题太宽泛,无法回答我的问题,而这个问题问的是格式化单个 double 数字的一种特定情况。

最佳答案

std::ostringstream电话 vsnprintf两次:第一次尝试使用小缓冲区,第二次尝试使用正确大小的缓冲区。参见 locale_facets.tcc大约第 1011 行(此处 std::__convert_from_vvsnprintf 的代理):

#if _GLIBCXX_USE_C99_STDIO
// Precision is always used except for hexfloat format.
const bool __use_prec =
(__io.flags() & ios_base::floatfield) != ios_base::floatfield;

// First try a buffer perhaps big enough (most probably sufficient
// for non-ios_base::fixed outputs)
int __cs_size = __max_digits * 3;
char* __cs = static_cast<char*>(__builtin_alloca(__cs_size));
if (__use_prec)
__len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
__fbuf, __prec, __v);
else
__len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
__fbuf, __v);

// If the buffer was not large enough, try again with the correct size.
if (__len >= __cs_size)
{
__cs_size = __len + 1;
__cs = static_cast<char*>(__builtin_alloca(__cs_size));
if (__use_prec)
__len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
__fbuf, __prec, __v);
else
__len = std::__convert_from_v(_S_get_c_locale(), __cs, __cs_size,
__fbuf, __v);
}

这与观察结果完全吻合,即对于小要求的精度性能与 snprintf 相同,而对于更高的精度,它的精度要差 2 倍。

此外,由于使用的缓冲区不依赖于 std::ostringstream 的任何属性缓冲区,仅在 __max_digits 上,定义为 __gnu_cxx::__numeric_traits<_ValueT>::__digits10 , 除了修复 libstdc++ 之外似乎没有任何自然的修复方法本身。

我已经 reported它是 libstdc++ 的错误。

关于c++ - 为什么 snprintf 在打印单个数字时始终比 ostringstream 快 2 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49002264/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com