Jac*_*ern 5 c++ templates expression simplify
通过表达模板技术,一个矩阵表达式就像
D = A*B+sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
就计算性能而言,它与手写for循环几乎相同.
现在,假设我有以下两个表达式
D = A*B+sin(C)+3.;
F = D*E;
cout << F << "\n";
Run Code Online (Sandbox Code Playgroud)
在表达模板的"经典"实现中,计算性能将与for顺序中的两个循环的计算性能几乎相同.这是因为在=遇到运算符后立即计算表达式.
我的问题是:是否有任何技术(例如,使用占位符?)来识别D实际上未使用的值,并且感兴趣的值是唯一的元素F,因此只有表达式
F = E*(A*B+sin(C)+3.);
Run Code Online (Sandbox Code Playgroud)
评估并且整个性能等同于单个for循环的性能?
当然,这种假设技术也应该能够返回来评估表达
D = A*B+sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
如果稍后在代码D中需要值.
预先感谢您的任何帮助.
编辑:结果试验了Evgeny提出的解决方案
原始说明:
Result D=A*B-sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
计算时间:32ms
两步说明:
Result Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
计算时间:43ms
解决方案auto:
auto&& Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
计算时间:32ms.
总之,auto&&能够恢复单个指令案例的原始计算时间.
编辑:根据Evgeny的建议总结相关链接
当您将结果保存到某些特殊类型时,通常会发生表达式模板的评估:
Result D = A*B+sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
表达式的结果类型:
A*B+sin(C)+3.
Run Code Online (Sandbox Code Playgroud)
不是Result,但它可以转换为Result.并且在这种转换期间进行评估.
我的问题是:是否有任何技术(例如,使用占位符?)来识别D的值实际上是未使用的
这种"转型":
Result D = A*B+sin(C)+3.;
Result F = D*E;
Run Code Online (Sandbox Code Playgroud)
至
Result F = (A*B+sin(C)+3.)*E;
Run Code Online (Sandbox Code Playgroud)
当您不评估时,可以使用D.为此,通常您应该捕获D,因为它是真实的表达式类型.例如,在auto的帮助下:
auto &&D = A*B+sin(C)+3.;
Result F = D*E;
Run Code Online (Sandbox Code Playgroud)
但是,你应该小心 - 有时表达式模板会捕获对它的操作数的引用,如果你有一些rvalue会在它的表达式之后到期:
auto &&D = A*get_large_rvalue();
// At this point, result of **get_large_rvalue** is destructed
// And D has expiried reference
Result F = D*E;
Run Code Online (Sandbox Code Playgroud)
其中get_large_rvalue是:
LargeMatrix get_large_rvalue();
Run Code Online (Sandbox Code Playgroud)
它的结果是rvalue,它在调用get_large_rvalue时在完整表达式结束时到期.如果表达式中的某些内容将存储指针/引用(以供以后评估),并且您将"推迟"评估 - 指针/引用将比指向/引用的对象更长.
为了防止这种情况,你应该这样做:
auto &&intermediate = get_large_rvalue(); // it would live till the end of scope
auto &&D = A*intermediate ;
Result F = D*E;
Run Code Online (Sandbox Code Playgroud)
我不熟悉C++ 11,但据我所知,auto要求编译器从初始化时确定变量的类型
对,就是这样.这称为类型推断/演绎.
C++ 98/03只有模板函数的类型推导,在C++ 11中有auto.
你知道CUDA和C++ 11如何相互影响吗?
我没有使用过CUDA(虽然我使用的是OpenCL),但我想在使用C++ 11的主机代码中没有任何问题.设备代码中可能不支持某些C++ 11功能,但出于您的目的 - 您只需要在主机代码中自动执行
最后,有没有可能只有C++?
你的意思是预C++ 11吗?即C++ 98/C++ 03?是的,它是可能的,但它有更多的语法噪音,也许这是拒绝它的理由:
// somehwhere
{
use_D(A*B+sin(C)+3.);
}
// ...
template<typename Expression>
void use_D(Expression D) // depending on your expression template library
// it may be better to use (const Expression &e)
{
Result F = D*E;
}
Run Code Online (Sandbox Code Playgroud)
我现在在Windows下使用CUDA/Visual Studio 2010.你可以推荐一个编译器/工具集/环境,让OS'在我感兴趣的框架中使用C++ 11(GPGPU和CUDA,你知道吗)
MSVC 2010确实支持C++ 11的某些部分.特别是它支持auto.所以,如果你只需要来自C++ 11的自动 - MSVC2010就行了.
但是,如果您可以使用MSVC2012 - 我建议坚持使用它 - 它有更好的C++ 11支持.
此外,技巧auto && intermediate = get_large_rvalue(); 似乎对第三方用户"不透明"(不应该知道这样的问题).我对吗?还有其他选择
如果表达式模板存储对某些值的引用,则推迟它的评估.你应该确定它的所有引用都在评估的地方存在.使用您想要的任何方法 - 它可以在没有自动的情况下完成,例如:
LargeMatrix temp = get_large_rvalue();
Run Code Online (Sandbox Code Playgroud)
或者甚至可能是全局/静态变量(不太喜欢的方法).
最后一条评论/问题:使用auto && D = A*B + sin(C)+3.似乎我应该重载operator = for两个表达式之间的赋值,对吧?
不,这种形式不需要也不需要复制/移动赋值运算符或复制/移动构造函数.
基本上它只是命名临时值,并将其寿命延长到范围的末尾.检查这个.
但是,如果你要使用另一种形式:
auto D = A*B+sin(C)+3.;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,可能需要复制/移动/转换构造函数才能编译(尽管编译器可以通过使用Copy Ellision优化实际复制)
此外,在使用auto(对于中间表达式)和Result强制计算之间切换对于第三方用户来说似乎是不透明的.还有其他选择
我不确定是否有其他选择.这是表达模板的本质.当你在表达式中使用它们时 - 它们会返回一些内部中间类型,但是当你存储到某些"特殊"类型时 - 会触发评估.
| 归档时间: |
|
| 查看次数: |
993 次 |
| 最近记录: |