- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在从 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++。
要进行测试,请创建一个包含约 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::atof
比 operator>>
快.
正如您在带有 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/
我在使用 gradle 构建一个特定应用程序时遇到问题。该应用程序可以用 eclipse 编译和构建,它在平板电脑上运行良好。当我尝试使用 Gradle 构建它时,“compileDebugJava”
我有一个 C 程序,是一位离开的开发人员留给我的。我试图弄清楚他到底在做什么,并将软件重新安排成更合乎逻辑的东西,这样我就可以更轻松地构建它。我正在使用 CMake 构建,而他使用的是 Make。 有
我刚开始阅读“Pro Spring MVC with web flow”,它附带了一个我想遵循的代码示例。 我要什么 - 我想像书中那样构建应用程序,使用 Gradle 有什么问题 - 我没用过 Gr
我希望有人已经这样做了。我正在尝试为我的一个 angular 2 项目在 teamcity 中建立一个连续的构建。在做了一些研究之后,我按照以下步骤操作: 构建步骤 1:为 teamcity 安装 j
我有一个旧的 ASP.Net 网站解决方案,看起来像: 当我在 Visual Studio 中构建解决方案时,我得到以下输出: ------ Build started: Project: C:\..
我使用 gulp-usref、gulp-if、gulp-uglify、gulp-csso 和 gulp-file-include 来构建我的应用程序。除了 HTML 保持原样外,构建中的一切都运行良好
我正在使用 ionic2 开发内部移动应用程序。我可以通过以下方式成功构建 ios: ionic build ios and ionic build ios --prod 但当我这样做时,它一直失败
我是一位经验丰富的 .NET/C# 开发人员,但对这里的几乎所有技术/库(包括 SQL/DB 工作)都是新手。 我正在开发一个具有 Azure/Entity Framework .NET 后端和可移植
我正在使用 VS 2008。我可以使用 IDE 成功编译我的解决方案。但是,当我尝试使用 devenv.com 构建它时,它失败并提示“错误:找不到项目输出组'(无法确定名称)的输出”。该组、其配置或
版本: ember.js 2.7,ember-data 2.7 ember-cli 2.9.1//同样适用于 ember-cli 2.7 node 6.9.1, npm 3.10.9//也适用于 no
我第一次修补 AzureDevops,设置一些 CI 任务。 我有一个公共(public)存储库(开源)和一个包含 3 个 F# 项目的解决方案(.sln)。该解决方案在 Windows/Mac/Li
目前 5.1.5 版本或 STLPort CVS 存储库似乎仍不支持 VS2008。如果有人已经完成了这项工作,那么如果可能的话,分享会很有用:) 同样,了解 VS2005 或 2008 x64 构建
我有一个 Python 2.7 项目,到目前为止一直使用 gfortran 和 MinGW 来构建扩展。我使用 MinGW,因为它似乎支持 Fortran 代码中的写入语句和可分配数组,而 MSVC
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
我想知道为什么在 Zimbra Wiki 中只列出了构建过程的特定平台。这意味着不可能在其他 Linux 发行版上构建 Zimbra? Zimbra 社区选择一个特殊的 Linux 发行版来构建 Zi
我将在 Swift 中构建一个 CLI 工具。我用这个命令创建了项目 swift package init --type executable当我构建我的项目并解析 时读取别名 Xcode 中的参数并
我想为添加到 docker 镜像的文件设置文件权限。我有这个简单的 Dockerfile: FROM ubuntu:utopic WORKDIR /app RUN groupadd -g 1000 b
当我使用 clBuildProgram在我的 OpenCl 代码中,它失败并显示错误代码 -11,没有任何日志信息。 这是我的代码的样子: ret = clBuildProgram(program
我有一个底部导航栏,它有一个列表页面,该页面使用状态块。 class _MainPageState extends State { int _index = 0; @override Wi
我在本地计算机上使用Jenkins(Jenkins URL未通过Internet公开,但该计算机上已启用Internet。) 我进行了以下配置更改: 在Jenkins工具上安装了Git和Github插
我是一名优秀的程序员,十分优秀!