问题描述
我编写了两个程序来使用Gaussian elimination计算矩阵的逆,第一个程序是C#,第二个程序是CUDA C ++。这两个程序遵循完全相同的过程,并给出相同的最终结果。但是,当我在中间步骤中检查这些值时,发现值略有不同,相对误差小于1e-5。
这是两个程序的每个代码的一部分。
C#
int i,j,i1,n,y,z;
double[,] M = new double[n,n];
double[,] inv = new double[n,n];
for (i = 0; i < n; i++)
inv[i,i] = 1;
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
M[i,j] /= M[i,i];
for (j = 0; j < n; j++)
inv[i,i];
if (i != n - 1)
{
for (i1 = i + 1; i1 < n; i1++)
if (Math.Abs(M[i1,i]) >= 1e-9)
{
for (j = i + 1; j < n; j++)
M[i1,j] -= M[i1,i] * M[i,j];
for (j = 0; j < n; j++)
inv[i1,i] * inv[i,j];
}
f = new StreamWriter("cpu.csv");
for (y = 0; y < n; y++)
{
for (z = 0; z < n; z++)
f.Write(M[y,z].ToString() + ",");
for (z = 0; z < n; z++)
f.Write(ans[y,");
f.WriteLine();
}
f.Close();
}
}
for (i = n - 1; i > 0; i--)
{
for (i1 = 0; i1 < i; i1++)
if (Math.Abs(M[i1,i]) >= 1e-9)
for (j = 0; j < n; j++)
inv[i1,j];
}
CUDA C ++
int i,j;
double v;
double* d_A,* d_B,* d_v,* Z;
size = n * n * sizeof(double);
cudamalloc(&d_A,size);
cudamemcpy(d_A,A,size,cudamemcpyHostToDevice);
cudamalloc(&d_B,size);
cudamalloc(&d_v,sizeof(double));
Z = new double[n * n];
Unity <<<1,n>>> (d_B,n);
cudaDeviceSynchronize();
for (i = 0; i < n; i++)
{
GetVal <<<1,1>>> (d_A,i * (n + 1),d_v);
cudamemcpy(&v,d_v,sizeof(double),cudamemcpyDevicetoHost);
if (i != n - 1)
DivideRow <<<1,n - i - 1>>> (d_A,i * (n + 1) + 1,n - i - 1,v);
DivideRow <<<1,i * n,v);
cudaDeviceSynchronize();
cudamemcpy(Z,d_A,cudamemcpyDevicetoHost);
cudamemcpy(B,d_B,cudamemcpyDevicetoHost);
if (i != n - 1)
{
dim3 GridA(1,1);
dim3 BlockA(n - i - 1,n - i - 1);
dim3 GridB(1,1);
dim3 BlockB(n - i - 1,n);
ModifyRow <<<GridA,BlockA>>> (d_A,i,i + 1,n - i - 1);
ModifyRow <<<GridB,BlockB>>> (d_A,n);
cudaDeviceSynchronize();
cudamemcpy(Z,cudamemcpyDevicetoHost);
cudamemcpy(B,cudamemcpyDevicetoHost);
myfile.open("GPU.csv");
for (x = 0; x < n; x++)
{
for (y = 0; y < n; y++)
myfile << Z[x * n + y] << ",";
for (y = 0; y < n; y++)
myfile << B[x * n + y] << ",";
myfile << "\n";
}
myfile.close();
}
}
cudaFree(d_v);
for (i = n - 1; i > 0; i--)
{
dim3 GridB(1,1);
dim3 BlockB(i,n);
ModifyRow <<<GridB,n);
cudaDeviceSynchronize();
cudamemcpy(Z,cudamemcpyDevicetoHost);
}
cudamemcpy(B,cudamemcpyDevicetoHost);
cudaFree(d_A);
cudaFree(d_B);
我比较了 cpu.csv 和 GPU.csv 文件中的值,并发现了这些差异。
这可能是什么原因? CUDA C ++中的计算精度是否低于C#?
解决方法
从NVIDIA documentation(大约2/3)开始:
[取整]的结果是,不能期望不同的数学库为给定的输入计算出完全相同的结果。这也适用于GPU编程。为GPU编译的函数将使用NVIDIA CUDA数学库实现,而为CPU编译的函数将使用主机编译器数学库实现(例如,Linux上的glibc)。由于这些实现是独立的,并且不能保证都正确舍入,因此结果通常会略有不同。
告诉您所有您需要知道的,真的。