博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Thrust快速入门教程(三)——算法 2
阅读量:6375 次
发布时间:2019-06-23

本文共 4538 字,大约阅读时间需要 15 分钟。

Reductions

Reduction算法使用二元操作将输入序列规约为一个单值。例如,需要获得一数列的和,可以通过加运算规约此数组得到。数列的求和的规约操作可以由thrust::reduce如下实现:

[cpp]
  1. int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0, thrust :: plus <int >());  
int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0, thrust :: plus <int >()); 

 

开始的两个参数定义了需要规约的数组,第三和第四个参数分别提供了初始值和相关的规约操作。实际上,通常使用的时候我们选择默认情况下没有初始值和不特别指出规约方法。所以下面三行代码是等同的:

[cpp]
  1. int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0, thrust :: plus <int >());  
  2. int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0);  
  3. int sum = thrust :: reduce (D. begin () , D. end ())  
int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0, thrust :: plus <int >()); int sum = thrust :: reduce (D. begin () , D. end () , ( int ) 0); int sum = thrust :: reduce (D. begin () , D. end ()) 

 

虽然thrust::reduce能够有效的满足大部分的规约操作,但是,Thrust库依然提供了另外的一些函数以便使用(类似于STL)。例如,thrust::count能够返回给定序列的特定值的数量。

[cpp]
  1. # include <thrust / count .h>   
  2. # include <thrust / device_vector .h>   
  3. ...  
  4. // put three 1s in a device_vector   
  5. thrust :: device_vector <int > vec (5 ,0);  
  6. vec [1] = 1;  
  7. vec [3] = 1;  
  8. vec [4] = 1;  
  9. // count the 1s   
  10. int result = thrust :: count ( vec . begin () , vec .end () , 1);  
  11. // result is three  
# include <thrust / count .h> # include <thrust / device_vector .h> ... // put three 1s in a device_vector thrust :: device_vector <int > vec (5 ,0); vec [1] = 1; vec [3] = 1; vec [4] = 1; // count the 1s int result = thrust :: count ( vec . begin () , vec .end () , 1); // result is three 

 

另一些规约操作,包括thrust::count_ifthrust::min_elementthrust::max_elementthrust::is_sortedthrust::inner_product等,详细请参考documentation

Transformations篇章中的SAXPY例子使用transformation内核展示了融合内核如何来减少内存交换。我们也可以使用thrust::transform_reduce实现融合内核来规约。下面的例子用来计算向量的模:

[cpp]
  1. # include <thrust / transform_reduce .h>   
  2. # include <thrust / functional .h>   
  3. # include <thrust / device_vector .h>   
  4. # include <thrust / host_vector .h>   
  5. # include <cmath >   
  6. // square <T> computes the square of a number f(x) -> x*x   
  7. template <typename T>  
  8. struct square  
  9. {  
  10. __host__ __device__  
  11. T operator ()( const T& x) const {  
  12. return x * x;  
  13. }  
  14. };  
  15. int main ( void )  
  16. {  
  17. // initialize host array   
  18. float x [4] = {1.0 , 2.0 , 3.0 , 4.0};  
  19. // transfer to device   
  20. thrust :: device_vector <float > d_x (x, x + 4);  
  21. // setup arguments   
  22. square <float > unary_op ;  
  23. thrust :: plus <float > binary_op ;  
  24. float init = 0;  
  25. // compute norm   
  26. float norm = std :: sqrt ( thrust :: transform_reduce ( d_x . begin () , d_x . end () ,  -  
  27. unary_op , init , binary_op ) );  
  28. std :: cout << norm << std :: endl ;  
  29. return 0;  
  30. }  
# include <thrust / transform_reduce .h> # include <thrust / functional .h> # include <thrust / device_vector .h> # include <thrust / host_vector .h> # include <cmath > // square <T> computes the square of a number f(x) -> x*x template <typename T> struct square { __host__ __device__ T operator ()( const T& x) const { return x * x; } }; int main ( void ) { // initialize host array float x [4] = {1.0 , 2.0 , 3.0 , 4.0}; // transfer to device thrust :: device_vector <float > d_x (x, x + 4); // setup arguments square <float > unary_op ; thrust :: plus <float > binary_op ; float init = 0; // compute norm float norm = std :: sqrt ( thrust :: transform_reduce ( d_x . begin () , d_x . end () , - unary_op , init , binary_op ) ); std :: cout << norm << std :: endl ; return 0; } 

 

这里有一个叫平方的一元操作,将输入序列的每个元素平方。然后,平方的和由标准的加法规约操作得到。类似较慢版本的SAXPY transformation,我们可以这样实现:首先将原数列同伙乘法转换成平方存储在一个临时数组,然后使用加法规约。但是显然这样做会带来不必要的浪费,速度降低。通过在规约内核中融合平方操作,我们就可以获得与自己编写内核一样的高性能。

 

Prefix-Sums

并行的前追求和,也叫scan操作,与压实流、基数排序等都是并行算法的重要模块。下面的源码将举例说明使用默认加法的inclusive scan

[cpp]
  1. # include <thrust / scan .h>   
  2. int data [6] = {1, 0, 2, 2, 1, 3};  
  3. thrust :: inclusive_scan (data , data + 6, data ); // in - place scan   
  4. // data is now {1, 1, 3, 5, 6, 9}  
# include <thrust / scan .h> int data [6] = {1, 0, 2, 2, 1, 3}; thrust :: inclusive_scan (data , data + 6, data ); // in - place scan // data is now {1, 1, 3, 5, 6, 9} 

 

Inclusive scan的每个输出元素为输入数列的相应部分和。例如,data[2] = data[0] + data[1] + data[2]Exclusive scan类似,但是右移一个位置:

[cpp]
  1. # include <thrust / scan .h>   
  2. int data [6] = {1, 0, 2, 2, 1, 3};  
  3. thrust :: exclusive_scan (data , data + 6, data ); // in - place scan   
  4. // data is now {0, 1, 1, 3, 5, 6}  
# include <thrust / scan .h> int data [6] = {1, 0, 2, 2, 1, 3}; thrust :: exclusive_scan (data , data + 6, data ); // in - place scan // data is now {0, 1, 1, 3, 5, 6} 

 

现在为data[2] = data[0] + data[1]。由例子可见,inclusive_sacnexclusive_scan允许原址操作。Thrust也提供了函数transform_inclusive_scantransform_exclusive_scan可以实现在scan操作前对输入数列进行一元操作。完整的scan变体说明请参见documentation

转载地址:http://mxjqa.baihongyu.com/

你可能感兴趣的文章
iOS客户端的APNS服务简介与实现
查看>>
DPM灾难切换应用场景
查看>>
简单配置Oracle10g DataGuard物理备库
查看>>
网曝支付宝漏洞:手机丢了,支付宝也就完了
查看>>
4 在vCenter Server安装View Composer组件
查看>>
SFB 项目经验-24-为持久聊天室-查询或者增加成员
查看>>
Linux下配置Squid基础教程
查看>>
当Cacti遭遇大流量
查看>>
Outlook Anywhere 客户端配置详解
查看>>
来,测一下你的学习能力!
查看>>
《Windows Server 2008 R2系统管理实战》前言与内容提要
查看>>
轻巧的网络流量实时监控工具NTOPNG
查看>>
MySQL的log_bin和sql_log_bin 到底有什么区别?
查看>>
Access、Sql 获取当前插入的主键ID
查看>>
聚类算法之DBScan(Java实现)
查看>>
为什么要使用AOP?
查看>>
VC :模板类
查看>>
对C++中string类型的总结
查看>>
SharePoint的数据库性能需要注意的一点
查看>>
Oracle发布公共云Public Cloud
查看>>