你好我在C +中有这个循环,我试图将它转换为推力但没有得到相同的结果...... 有任何想法吗? 谢谢
C ++代码
for (i=0;i<n;i++)
for (j=0;j<n;j++)
values[i]=values[i]+(binv[i*n+j]*d[j]);
推力代码
thrust::fill(values.begin(), values.end(), 0);
thrust::transform(make_zip_iterator(make_tuple(
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))),
binv.begin(),
thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))))),
make_zip_iterator(make_tuple(
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))) + n,
binv.end(),
thrust::make_permutation_iterator(d.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n))) + n)),
thrust::make_permutation_iterator(values.begin(), thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n))),
function1()
);
推力功能
struct IndexDivFunctor: thrust::unary_function<int, int>
{
int n;
IndexDivFunctor(int n_) : n(n_) {}
__host__ __device__
int operator()(int idx)
{
return idx / n;
}
};
struct IndexModFunctor: thrust::unary_function<int, int>
{
int n;
IndexModFunctor(int n_) : n(n_) {}
__host__ __device__
int operator()(int idx)
{
return idx % n;
}
};
struct function1
{
template <typename Tuple>
__host__ __device__
double operator()(Tuple v)
{
return thrust::get<0>(v) + thrust::get<1>(v) * thrust::get<2>(v);
}
};
答案 0 :(得分:4)
首先,一些一般性评论。你的循环
for (i=0;i<n;i++)
for (j=0;j<n;j++)
v[i]=v[i]+(B[i*n+j]*d[j]);
等同于标准BLAS gemv操作
其中矩阵以行主要顺序存储。在设备上执行此操作的最佳方法是使用CUBLAS,而不是使用推力原语构建的。
话虽如此,你发布的推力代码绝对不会像你的串行代码那样做。您看到的错误不是浮点关联的结果。从根本上说,thrust::transform
将提供的函数应用于输入迭代器的每个元素,并将结果存储在输出迭代器中。为了得到与您发布的循环相同的结果,thrust::transform
调用将需要执行您发布的fmad仿函数的(n * n)个操作。显然它没有。此外,无法保证thrust::transform
能够以一种对记忆比赛安全的方式执行总和/减少操作。
正确的解决方案可能是:
在代码中,首先定义一个这样的仿函数:
struct functor
{
template <typename Tuple>
__host__ __device__
double operator()(Tuple v)
{
return thrust::get<0>(v) * thrust::get<1>(v);
}
};
然后执行以下操作来计算矩阵向量乘法
typedef thrust::device_vector<int> iVec;
typedef thrust::device_vector<double> dVec;
typedef thrust::counting_iterator<int> countIt;
typedef thrust::transform_iterator<IndexDivFunctor, countIt> columnIt;
typedef thrust::transform_iterator<IndexModFunctor, countIt> rowIt;
// Assuming the following allocations on the device
dVec B(n*n), v(n), d(n);
// transformation iterators mapping to vector rows and columns
columnIt cv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexDivFunctor(n));
columnIt cv_end = cv_begin + (n*n);
rowIt rv_begin = thrust::make_transform_iterator(thrust::make_counting_iterator(0), IndexModFunctor(n));
rowIt rv_end = rv_begin + (n*n);
dVec temp(n*n);
thrust::transform(make_zip_iterator(
make_tuple(
B.begin(),
thrust::make_permutation_iterator(d.begin(),rv_begin) ) ),
make_zip_iterator(
make_tuple(
B.end(),
thrust::make_permutation_iterator(d.end(),rv_end) ) ),
temp.begin(),
functor());
iVec outkey(n);
dVec Bd(n);
thrust::reduce_by_key(cv_begin, cv_end, temp.begin(), outkey.begin(), Bd.begin());
thrust::transform(v.begin(), v.end(), Bd.begin(), v.begin(), thrust::plus<double>());
当然,与使用目的设计的矩阵向量乘法代码(如CUBLAS中的dgemv
)相比,这是一种非常低效的计算方法。
答案 1 :(得分:0)
您的结果有多大差异?这是一个完全不同的答案,还是只在最后一位数字上有所不同?循环只执行一次,还是某种迭代过程?
由于精度问题,浮点运算,尤其是那些重复累加或乘以某些值的运算,不关联。此外,如果使用快速数学优化,则操作可能不是IEEE编译。
对于初学者,请查看此维基百科有关浮点数的部分:http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems