gpt4 book ai didi

c++ - 使用 istream_iterators 构建 vector 比使用 string/std::atof 的 while 循环慢,为什么?

转载 作者:太空狗 更新时间:2023-10-29 12:08:38 24 4
gpt4 key购买 nike

我正在从 std::cin 中读取值流,并从中构建一个 std::vector。最初,我将 while 循环与临时 std::string 对象一起使用,并将 std::atof 与临时字符串中的 c_str() 一起使用。那里有几个电话,通常有很多电话。我将它替换为范围构造函数,将 std::istream_iterator 与 std::cin 一起使用,认为它看起来更简单,速度更快。令我惊讶的是,它有点慢,尽管它看起来确实更干净。

我的问题是:为什么在下面的代码中,使用 std::istream_iterator 构造 std::vector 比使用函数调用混搭的替代方法慢?另外,有没有一种方法可以使用 std::istreambuf_iterator 来修改范围构造,从而使这两种方法的性能等效?我看到的答案表明我应该将 std::ios_base::sync_with_stdio(false); 添加到代码中。虽然这会提高性能,但在这两种情况下都是如此,并且这两种方法之间仍然存在差异。

最小工作示例:

#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;

int main()
{
/* Faster Method */
string temporary_line{};
vector<double> data{};
while(cin>> temporary_line)
data.push_back(atof(temporary_line.c_str()));

/* Slower Method */
//vector<double> data{ istream_iterator<double>{cin},
// stream_iterator<double>{} };

cout<< data.back() << '\n';
}

我通过 5 个不同的编译器运行代码,g++-{7,8} 和 clang++-{6,7,8}。代码是在 -O2 下为所有运行编译的,每次代表 5 次运行的平均值。时间非常紧迫,增加更多的试验并不重要。结果显示所有编译器都有相同的行为,在这两种方法上,g++ 仅以少量时间领先于 clang++。

enter image description here

要进行测试,请创建一个包含约 1,000,000 个随机整数的文件:

$ for i in {0..999999};做 echo $RANDOM >> 数据文件;完成

编译:

$ g++ -o ds descriptive_statistics.cpp -O2

使用生成的示例数据运行:

$时间猫数据文件| ./ds

完整代码:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <numeric>
#include <string>
#include <vector>

class DS {

public:
DS() = default;
DS(const DS& ) = default;
DS(DS&& ) = default;
DS(const double*, std::size_t length);
DS(const double*, const double*);
virtual ~DS() = default;

DS& operator=(const DS& ) = default;
DS& operator=(DS&& ) = default;

friend std::ostream& operator<<(std::ostream& , const DS& );

bool operator<(const DS& ) = delete;
bool operator>(const DS& ) = delete;
bool operator==(const DS& ) = delete;

private:
double min;
double first_quartile;
double mean;
double median;
double third_quartile;
double max;
double sum;
double variance;
double standard_deviation;
};

DS::DS(const double* begin, const double* end) {

const std::size_t size = std::distance(begin, end) ;

min = *begin;

first_quartile = begin[ size/4 ] ;

sum = std::accumulate(begin, end, double{});

mean = sum / size ;

const std::size_t idx{ size / 2 };
median = begin[ idx ] ;
if( ! (size & 1) ) {
median += begin[ idx - 1 ];
median *= 0.5;
}

third_quartile = begin[ 3*size/4 ] ;

variance = std::accumulate(begin, end, double{},
[&] (double a, double b) {
return a + std::pow(b - mean, 2.0);
}) / size ;

standard_deviation = std::sqrt(variance);

max = *std::prev(end);
}

DS::DS(const double* begin, std::size_t length) {
const double* end = begin + length;
*this = DS(begin,end);
}

std::ostream& operator<<(std::ostream& os, const DS& ds) {
os << ds.min << '\n'
<< ds.first_quartile << '\n'
<< ds.mean << '\n'
<< ds.median << '\n'
<< ds.third_quartile << '\n'
<< ds.max << '\n'
<< ds.sum << '\n'
<< ds.variance << '\n'
<< ds.standard_deviation << '\n';
return os;
}

int main(int argc, char** argv)
{
// This section is faster than the section below
std::string temporary_line{};
std::vector<double> data{};
while(std::cin>> temporary_line) {
data.push_back(std::atof(temporary_line.c_str()));
}

// This section is slower than the section above
// std::vector<double> data{
// std::istream_iterator<double>{std::cin},
// std::istream_iterator<double>{}
// };

if(! std::is_sorted(data.cbegin(), data.cend()) ) {
std::sort(data.begin(), data.end());
}

DS ds(&*data.cbegin(), &*data.cend());
std::cout<< ds << std::endl;

return(EXIT_SUCCESS);
}

最佳答案

看一下 std::istream_iterator<double> 的实现你可以注意到这样做

std::vector<double> data{ std::istream_iterator<double>{file},
std::istream_iterator<double>{} };

实际上相当于做

double temporary_line;
std::vector<double> data{};
while (file>>temporary_line) {
data.push_back(temporary_line);
}

godbolt上查看汇编代码的区别|

所以你的整个问题归结为为什么 std::atofoperator>> 快.

正如您在带有 gcc 的 O2 中注意到的那样,有一个对 strtod 的调用而不是 call std::basic_istream<char, std::char_traits<char> >& std::basic_istream<char, std::char_traits<char> >::_M_extract<double>(double&) https://www.godbolt.org/z/Od-FIk但代码结构基本相同。

我相信时差的原因是 locale . std::atof部分忘记了 locale 另一方面(它看到 C 语言环境)operator>>使用指定的约束进行解析 C++ locale并最终使用 UNICODE 编码器。

做更复杂的操作需要更多的时间。但是考虑到 UNICODE 和每个 locale 的惩罚时间为 50%这不是很糟糕,你不觉得吗?

关于c++ - 使用 istream_iterators 构建 vector 比使用 string/std::atof 的 while 循环慢,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57939299/

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