表达式模板:提高表达式求值的性能?

2023-11-25

通过表达式模板技术,矩阵表达式如

D = A*B+sin(C)+3.;

就计算性能而言,几乎相当于手写的for loop.

现在,假设我有以下两个表达式

D = A*B+sin(C)+3.;
F = D*E;
cout << F << "\n";

在表达式模板的“经典”实现中,计算性能与两个表达式模板的计算性能几乎相同for按顺序循环。这是因为表达式在=遇到运算符。

我的问题是:是否有任何技术(例如,使用占位符?)来识别D实际上未使用,并且感兴趣的值是唯一的元素F,因此只有表达式

F = E*(A*B+sin(C)+3.);

进行评估,整体性能相当于单个for loop?

当然,这样的假设技​​术也应该能够返回计算表达式

D = A*B+sin(C)+3.;

如果稍后在代码中的值D需要。

预先感谢您的任何帮助。

编辑:实验 Evgeny 建议的解决方案的结果

原始指令:

Result D=A*B-sin(C)+3.;

计算时间:32ms

两步指令:

Result Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;

计算时间:43ms

解决方案与auto:

auto&& Intermediate=A*B;
Result D=Intermediate-sin(C)+3.;

计算时间:32ms。

综上所述,auto&&能够恢复单指令情况下的原始计算时间。

编辑:根据 Evgeny 的建议总结相关链接

复制省略

汽车告诉我们什么

C++11 中的通用引用

C++ 右值引用解释

C++ 及未来 2012 年:Scott Meyers - C++11 中的通用参考


评估表达模板通常当您将结果保存到某些special键入如下:

Result D = A*B+sin(C)+3.;

表达式的结果类型:

A*B+sin(C)+3.

is not Result,但它可以转换为Result。评估发生在这种转换过程中。


我的问题是:是否有任何技术(例如,使用占位符?)来识别 D 的值实际上未使用

这样的“转变”:

Result D = A*B+sin(C)+3.;
Result F = D*E;

to

Result F = (A*B+sin(C)+3.)*E;

当您不评估 D 时,这是可能的。为此,通常您应该捕获 D,因为它是真实的,表达类型。例如,在auto:

auto &&D = A*B+sin(C)+3.;
Result F = D*E;

但是,您应该小心 - 有时表达式模板会捕获对其操作数的引用,并且如果您有一些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;

Where 获取大右值 is:

LargeMatrix get_large_rvalue();

其结果是rvalue,它在完整表达结束时到期获取大右值被称为。如果表达式中的某些内容将存储指向它的指针/引用(以供以后求值)并且您将“推迟”求值 - 指针/引用将比指向/引用的对象更长寿。

为了防止这种情况,您应该这样做:

auto &&intermediate = get_large_rvalue(); // it would live till the end of scope
auto &&D = A*intermediate ;
Result F = D*E;

我不熟悉 C++11,但据我了解, auto 要求编译器从变量的初始化中确定变量的类型

对,就是这样。这就是所谓的类型推断/演绎.

C++98/03 仅针对模板函数进行类型推导,在 C++11 中auto.

你知道 CUDA 和 C++11 是如何交互的吗?

我没用过CUDA(虽然我用过OpenCL),但我想不会有任何问题Host使用 C++11 编写代码。也许某些 C++11 功能不受支持Device代码,但为了你的目的 - 你需要auto只有在Host code

最后,只用C++有可能吗?

您是指 C++11 之前的版本吗? IE。 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;
}

我现在在 Windows 下使用 CUDA/Visual Studio 2010。您能否为两个操作系统推荐一个编译器/工具集/环境,以便在我感兴趣的框架中使用 C++11(GPGPU 和 CUDA,您知道吗)

MSVC 2010 确实支持 C++11 的某些部分。特别是它支持auto。所以,如果你只需要auto从 C++11 - MSVC2010 可以。

但如果您可以使用 MSVC 2012 - 我建议坚持使用它 - 它具有更好的 C++11 支持。

另外,技巧 auto &&intermediate = get_large_rvalue();似乎对第三方用户不“透明”(第三方用户不应该知道这样的问题)。我对吗?还有其他选择吗?

如果表达式模板存储对某些值的引用,并且您推迟了它的评估。您应该确保所有引用在评估位置都有效。使用任何你想要的方法 - 它可以在没有 auto 的情况下完成,例如:

LargeMatrix temp = get_large_rvalue();

或者甚至可能是全局/静态变量(不太优选的方法)。

最后一个评论/问题:使用 auto &&D = A*B+sin(C)+3。;看来我应该重载operator=来进行两个表达式之间的赋值,对吧?

不,这种形式不需要复制/移动赋值运算符或复制/移动构造函数。

基本上它只是命名临时值,并将其生命周期延长到范围的末尾。检查这个SO.

但是,如果您使用另一种形式:

auto D = A*B+sin(C)+3.;

在这种情况下,可能需要复制/移动/转换构造函数才能编译(尽管编译器可以使用以下方法来优化实际的复制)复制省略)

此外,使用 auto (用于中间表达式)和 Result 之间的切换来强制计算对于第三方用户来说似乎是不透明的。还有其他选择吗?

我不确定是否还有其他选择。这是表达式模板的本质。当您在表达式中使用它们时 - 它们返回一些内部中间类型,但是当您存储到某些“特殊”类型时 - 会触发评估。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

表达式模板:提高表达式求值的性能? 的相关文章

  • C 编程 - 文件 - fwrite

    我有一个关于编程和文件的问题 while current NULL if current gt Id Doctor 0 current current gt next id doc current gt Id Doctor if curre
  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 显示UnityWebRequest的进度

    我正在尝试使用下载 assetbundle统一网络请求 https docs unity3d com ScriptReference Networking UnityWebRequest GetAssetBundle html并显示进度 根
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐