我正在尝试使用CUDA :: Thurst迭代器来实现在GPU上运行的ODE求解程序,以解决GPU中的一堆方程式,详细介绍,这里只是一小段代码:
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/fill.h>
#include <thrust/replace.h>
#include <thrust/functional.h>
#include <thrust/for_each.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f(float x, float y)
{
return cos(y)*sin(x);
}
struct euler_functor
{
const float h;
euler_functor(float _h) : h(_h) {};
__host__ __device__
float operator()( float(*f)(double,double),const float& x, const float& y) const {
y += h * (*f)( x, y );
x += h;
}
};
int main(void)
{
// allocate three device_vectors with 10 elements
thrust::device_vector<int> X(10);
// initilaize to random vaues
thrust::generate(X.begin(), X.end(), rand);
// apply euler for each element of X
thrust::for_each(X.begin(),X.end(),euler_functor(f,0.0,X));
// print the values
for(int i = 0; i < 10; i++) std::cout<< X[i]<< std::endl;
}
但是当我编译
nvcc euler.cu -o euler.x -lm 发生以下错误:
lala.cu(29): error: explicit type is missing ("int" assumed)
lala.cu(29): error: expected a ";"
lala.cu(33): error: expression must be a modifiable lvalue
lala.cu(34): error: expression must be a modifiable lvalue
lala.cu(35): warning: missing return statement at end of non-void function "euler_functor::operator()"
lala.cu(46): error: no suitable constructor exists to convert from "float (float, float)" to "euler_functor"
lala.cu(46): error: expected a ")"
似乎不可能以我正在尝试的方式使用函数指针?
更好地实现Euler过程并使用迭代器运行它的方法将非常受欢迎。
前者的方法是兼顾性和性能之间的良好折衷吗?
最后希望对我来说理想的解决方案是能够定义一个指向以下函数的指针数组:
typedef int (*foo_ptr_t)( int );
foo_ptr_t foo_ptr_array[2];
int f1( int );
int f2( int );
foo_ptr_array[0] = f1;
foo_ptr_array[1] = f2;
foo_ptr_array[0]( 1 );
将foo_ptr_array作为参数传递给euler仿函数。有可能吗?
感谢您的回答。
可行的改进:
在我尝试下面的方法时,是否可以将一组耦合微分方程定义为元组上的函数?我可以从数字方法中获得一些错误信息吗?
这将是
答案 0 :(得分:1)
最终,你要求在主机代码中使用__device__
函数参数,然后将其作为(函数)指针传递给最终(在引擎盖下)由推力生成的内核参数。
在主机代码中获取__device__
函数参数的地址是illegal,因此以这种方式将__device__
函数指针作为参数传递将不起作用。
可以通过创建额外的__device__
变量(指针)来在设备上存储函数指针来解决这个问题。然后使用cudaGetSymbolAddress
构建一个指向函数指针的表。这将需要运行前驱内核来设置设备上的函数指针。看起来相当混乱。
参数化仿函数以根据参数选择设备函数可能更简单。 Lke this:
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sequence.h>
#include <thrust/copy.h>
#include <thrust/fill.h>
#include <thrust/replace.h>
#include <thrust/functional.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <math.h>
__host__ __device__ float f1(float x)
{
return sinf(x);
}
__host__ __device__ float f2(float x)
{
return cosf(x);
}
struct euler_functor
{
unsigned h;
euler_functor(unsigned _h) : h(_h) {};
__host__ __device__
void operator()(float &y) const {
if (h == 1) y = f1(y);
else if (h == 2) y = f2(y);
}
};
int main(void)
{
const unsigned N = 8;
// allocate three device_vectors with 10 elements
thrust::device_vector<float> X(N);
// initilaize to random vaues
thrust::sequence(X.begin(), X.end(), 0.0f, (float)(6.283/(float)N));
// apply euler for each element of X
thrust::for_each(X.begin(),X.end(),euler_functor(1));
// print the values
for(int i = 0; i < N; i++) std::cout<< X[i]<< std::endl;
std::cout << "******************" << std::endl;
thrust::sequence(X.begin(), X.end(), 0.0f, (float)(6.283/(float)N));
// apply euler for each element of X
thrust::for_each(X.begin(),X.end(),euler_functor(2));
// print the values
for(int i = 0; i < N; i++) std::cout<< X[i]<< std::endl;
}