我正在计算向量元素的均值和标准差.我有两个版本,我很困惑为什么使用标准算法的版本比使用普通循环的版本慢.
两个版本都使用此结构作为返回类型:
struct MeanAndSigma {
double mean;
double sigma;
};
Run Code Online (Sandbox Code Playgroud)
带循环的版本是这样的:
MeanAndSigma getMeanAndSigma(const DVector& v){
MeanAndSigma ms;
ms.mean = 0;
for (int i=0;i<v.size();++i){ms.mean += v[i];}
ms.mean = ms.mean / v.size();
double sqsum = 0;
for (int i=0;i<v.size();++i){sqsum += (v[i]-ms.mean)*(v[i]-ms.mean);}
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
Run Code Online (Sandbox Code Playgroud)
而算法的那个:
MeanAndSigma getMeanAndSigma2(const DVector& v){
MeanAndSigma ms;
ms.mean = std::accumulate(v.begin(),v.end(),0.0) / v.size();
DVector diff(v.size());
std::transform(v.begin(),v.end(),diff.begin(),
std::bind2nd(std::minus<double>(), ms.mean));
double sqsum = std::inner_product(diff.begin(),diff.end(),diff.begin(),0.0);
ms.sigma = std::sqrt(sqsum / (v.size()-1));
return ms;
}
Run Code Online (Sandbox Code Playgroud)
当我使用带有10k元素的向量测量每10k调用的时间时,对于带有循环的版本,我得到~2.0秒,对于具有算法的版本,我得到~3.2秒.为什么是这样?
我已经比较了cpu时间和实时,但似乎两个都在单个cpu上运行(如预期的那样).我在使用算法时做了一些愚蠢的错误吗?
编辑:我没有声称,这两个版本是等价的.不过我原本预计第二个版本会更快.正如在评论和答案中所指出的那样,第二个版本对元素使用额外的迭代和额外的迭代DVector …
我有以下代码:
#include <iostream>
#include <vector>
namespace X {
std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
for (int i=0;i<v.size();i++){os << v[i] << " ";}
return os;
}
namespace Y {
struct A {std::vector<double> x;};
std::ostream& operator<<(std::ostream& os,const A& a){
os << a.x << std::endl;
return os;
}
}
}
using namespace X;
int main(int argc, char** argv) {
std::vector<double> v(10,0);
std::cout << v << std::endl;
Y::A a;
std::cout << a << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
第一个重载是有效的,但第二个没有.由于某种原因,它找不到第一个.我收到错误:
no match for 'operator<<' (operand types are …
Run Code Online (Sandbox Code Playgroud) 假设有一个具有默认值的函数:
int foo(int x=42);
Run Code Online (Sandbox Code Playgroud)
如果这是由其他人这样调用:
int bar(int x=42) { return foo(x); }
int moo(int x=42) { return bar(x); }
Run Code Online (Sandbox Code Playgroud)
这当然只是一个人为的例子.但是,我有时情况非常相似.该参数仅从最高级别(moo
)传递到最低级别,并且仅在实际使用时才传递.关于这一点的坏处是,当我更改foo
为具有不同于42
我必须搜索所有调用者的默认值并相应地更改默认值时.
是否有一些模式/成语可以避免这种情况?
我想到的唯一简单的解决方案是
int bar() { return foo(); }
int bar(int x) { return foo(x); }
Run Code Online (Sandbox Code Playgroud)
但是,由于我有点懒,而且在实际代码中这会导致相当多的代码重复,我想避免这种情况.
我有一种情况,我希望有一个地图,不允许在初始化后添加/删除键,但允许更改值(因此我不能简单地制作地图const
).即
/*semi-const*/ map<int,int> myMap = initMap();
myMap[1] = 2; // NOT OK, because potentially adds a new key
myMap.at(1) = 2; // OK, because works only if key is present
for (auto & element : myMap) {
element.second = 0; // OK, values may change
}
Run Code Online (Sandbox Code Playgroud)
我可以编写自己的包装器std::map
,但我觉得这是不太常见的事情,所以我想知道是否已有现有的解决方案.
是否有一些标准习惯用于地图不允许添加/删除键,而值可能会改变?
ps:我知道单独的标题有点模糊,因为键在地图中已经是常量,但我希望很清楚我的意思是什么......
我在玩 www.godbolt.org 来检查哪些代码会生成更好的汇编代码,但我不明白为什么这两种不同的方法会生成不同的结果(在汇编命令中)。
第一种方法是声明一个字符串,然后再设置一个值:
#include <string>
int foo() {
std::string a;
a = "abcdef";
return a.size();
}
Run Code Online (Sandbox Code Playgroud)
其中,在我的 gcc 7.4 ( -O3
) 输出中:
.LC0:
.string "abcdef"
foo():
push rbp
mov r8d, 6
mov ecx, OFFSET FLAT:.LC0
xor edx, edx
push rbx
xor esi, esi
sub rsp, 40
lea rbx, [rsp+16]
mov rdi, rsp
mov BYTE PTR [rsp+16], 0
mov QWORD PTR [rsp], rbx
mov QWORD PTR [rsp+8], 0
call std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned …
Run Code Online (Sandbox Code Playgroud) 我想用来std::for_each
并行迭代范围内的向量索引,计算Weierstrass 函数[a, b)
的值并将其写入:std::vector
std::vector<std::array<float, 2>> values(1000);
auto range = /** equivalent of Pyhthon range(0, values.size()) **/;
std::for_each(std::execution::par, range.begin(), range.end(), [&](auto &&i) {
values[i][0] = static_cast<float>(i) / resolution;
values[i][1] = weierstrass(a, b, static_cast<float>(i) / resolution);
});
// a, b, and resolution are some constants defined before
// weierstrass() is the Weierstrass function
Run Code Online (Sandbox Code Playgroud)
我在互联网上找到了一些解决方案,但所有这些解决方案都需要包含一些第三方库或创建我自己的范围类。有没有标准的解决方案?
有一个类模板Foo<T>
。对于某些特定类型,函数应该使用lock_guard
. 这是示例代码:
#include <type_traits>
#include <mutex>
#include <vector>
template<typename T>
class Foo {
public:
void do_something(int k) {
if constexpr(std::is_same_v<T, NeedMutexType>) {
std::lock_guard<std::mutex> lock(mtx_);
}
resource_.push_back(k);
// code for task with resource_ ...
}
private:
std::mutex mtx_;
std::vector<int> resource_;
};
Run Code Online (Sandbox Code Playgroud)
将会std::lock_guard
在 if constexpr 范围的末尾被破坏。(如果不正确,请纠正。)
为了处理这个问题,我可以将下面的任务代码复制resource_
到 if constexpr 范围中,或者只使用原始的,std::mutex
例如mtx_.lock()
& mtx_.unlock()
。
有什么方法可以处理这个问题std::lock_guard
吗?谢谢。
我想在整个双范围内生成随机数.这样做
std::uniform_real_distribution<double> doubleDist(std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::max());
Run Code Online (Sandbox Code Playgroud)
然而,产生IND/NaN.我花了一段时间才明白这是根据文档:
需要
a ? b
和b-a ? std::numeric_limits<RealType>::max()
显然std::numeric_limits<double>::max() - std::numeric_limits<double>::lowest()
大于::max
,因为:lowest
是负的(不像::min
).
为什么我不能以这种方式在最低和最高之间生成数字,背后的理由是什么?
我刚刚发现在库基础知识 TS v2 中有一个make_array
( std::experimental::make_array
) 模板,可以从其参数中推断出数组类型。我想主要目的是启用auto
类似于 cppreference 示例的用法:
auto x = std::experimental::make_array(1,2,3,4,5);
Run Code Online (Sandbox Code Playgroud)
有没有我没有看到的不同动机?
有了 C++20 中新的类型推导工具,人们还能期待make_array
有一天它会成为标准,还是已经过时了?
首先很抱歉标题模糊,如果我的问题没有被理解。英语是我的第三语言,很难清楚地表述问题。这是我的问题,我想引入一个化学物质公式,如 H3PO4,程序应该将 H 分开,并给他一个变量名称,如 x(我们将有 3x,因为它的 H3)和 PO4 作为另一个变量,如 y。或者更简单的物质,如 HCl,程序应该将其分离为 H 和 Cl 。
c++ ×9
optimization ×2
templates ×2
algorithm ×1
c ×1
c++11 ×1
c++20 ×1
const ×1
dictionary ×1
function ×1
lock-guard ×1
mutex ×1
ostream ×1
random ×1
runtime ×1
std ×1
visual-c++ ×1