我开始使用OpenCL,我可以看到添加矢量示例并理解它。但我在考虑梯形方法。这是[a,b]中x ^ 2的积分计算的代码(C)。
double f(double x)
{
return x*x;
}
double Simple_Trap(double a, double b)
{
double fA, fB;
fA = f(a);
fB = f(b);
return ((fA + fB) * (b-a)) / 2;
}
double Comp_Trap( double a, double b)
{
double Suma = 0;
double i = 0;
i = a + INC;
Suma += Simple_Trap(a,i);
while(i < b)
{
i+=INC;
Suma += Simple_Trap(i,i + INC);
}
return Suma;
}
问题是如何使用梯形方法获得用于积分计算的内核?
所以,我正在考虑这个想法:partials [i] = integration(a,a + offset),然后创建一个内核来计算部分的总和,如Patrick87所述。
但是,这是最好的方法吗?
答案 0 :(得分:3)
梯形法只是略微改进了黎曼和。要并行执行此操作,您需要将间隔分成所需数量的子间隔,以便存在线程;然后,让每个线程在其子区间上集成该函数。最后,对前一阶段计算的所有积分进行全局和减少。您可以尝试为每个阶段使用多少个线程。
答案 1 :(得分:2)
这就是我想出的。我没有做这个内核的端到端测试。我会花更多时间做更新。
comp_trap是基本的分歧&amp;根据您上面的代码征服方法。 comp_trap_multi通过让每个工作项划分其子部分来提高准确性
您只需在主机中分配一个双精度数组,以便每个工作组都有一个双精度数来返回其结果。这有助于减少您想要避免的矢量分配。
如果有任何问题,请告诉我。
更新:
1)将所有double引用更改为float,因为double在opencl
中是可选的2)将工作组大小硬编码为64.该值在我的系统中是最佳的,应该通过实验确定。我更喜欢硬编码这个值而不是传递一个本地浮动数组来使用,因为主程序最终只会使用目标系统上的最佳值。
3)修正了错误的计算(a1错了,现在应该更好)
/*
numerical-integration.cl
*/
float f(float x)
{
return x*x;
}
float simple_trap(float a, float b)
{
float fA, fB;
fA = f(a);
fB = f(b);
return ((fA + fB) * (b-a)) / 2;
}
__kernel void comp_trap(
float a,
float b,
__global float* sums)
{
/*
- assumes 1D global and local work dimensions
- each work unit will calculate 1/get_global_size of the total sum
- the 0th work unit of each group then accumulates the sum for the
group and stores it in __global * sums
- memory allocation: sizeof(sums) = get_num_groups(0) * sizeof(float)
- assumes local scratchpad size is at lease 8 bytes per work unit in the group
ie sizeof(wiSums) = get_local_size(0) * sizeof(float)
*/
__local float wiSums[64];
int l_id = get_local_id(0);
//cumpute range for this work item is: a1, b1
float a1 = a+((b-a)/get_global_size(0))*get_global_id(0);
float b1 = a1+(b-a)/get_global_size(0);
wiSums[l_id] = simple_trap(a1,b1);
barrier(CLK_LOCAL_MEM_FENCE);
int i;
if(l_id == 0){
for(i=1;i<get_local_size(0);i++){
wiSums[0] += wiSums[i];
}
sums[get_group_id(0)] = wiSums[0];
}
}
__kernel void comp_trap_multi(
float a,
float b,
__global float* sums,
int divisions)
{
/*
- same as above, but each work unit further divides its range into
'divisions' equal parts, yielding a more accurate result
- work units still store only one sum in the local array, which is
used later for the final group accumulation
*/
__local float wiSums[64];
int l_id = get_local_id(0);
float a1 = a+((b-a)/get_global_size(0))*get_global_id(0);
float b1 = a1+(b-a)/get_global_size(0);
float range;
if(divisions > 0){
range = (b1-a1)/divisions;
}else{
range = (b1-a1);
}
int i;
wiSums[l_id] = 0;
for(i=0;i<divisions;i++){
wiSums[l_id] += simple_trap(a1+range*i,a1+range*(i+1));
}
barrier(CLK_LOCAL_MEM_FENCE);
if(l_id == 0){
for(i=1;i<get_local_size(0);i++){
wiSums[0] += wiSums[i];
}
sums[get_group_id(0)] = wiSums[0];
}
}