c# - 为什么 C# 和 CUDA C++ 的矩阵逆计算中的中间值略有不同?
问题描述
我写了两个程序来使用高斯消元法计算矩阵的逆,第一个程序是在 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, j] /= M[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, j] -= M[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, z].ToString() + ",");
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] -= M[i1, i] * inv[i, 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, n>>> (d_B, i * n, n, v);
cudaDeviceSynchronize();
cudaMemcpy(Z, d_A, size, cudaMemcpyDeviceToHost);
cudaMemcpy(B, d_B, size, 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, i + 1, n - i - 1, n - i - 1);
ModifyRow <<<GridB, BlockB>>> (d_A, n, i, i, d_B, i + 1, 0, n - i - 1, n);
cudaDeviceSynchronize();
cudaMemcpy(Z, d_A, size, cudaMemcpyDeviceToHost);
cudaMemcpy(B, d_B, size, 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, BlockB>>> (d_A, n, i, i, d_B, 0, 0, i, n);
cudaDeviceSynchronize();
cudaMemcpy(Z, d_A, size, cudaMemcpyDeviceToHost);
cudaMemcpy(B, d_B, size, cudaMemcpyDeviceToHost);
}
cudaMemcpy(B, d_B, size, cudaMemcpyDeviceToHost);
cudaFree(d_A);
cudaFree(d_B);
我比较了CPU.csv和GPU.csv文件中的值,发现了这些差异。
这可能是什么原因?CUDA C++ 中的计算精度是否低于 C#?
解决方案
来自NVIDIA 文档(大约下降了 2/3):
[舍入] 的结果是,不能期望不同的数学库为给定的输入计算完全相同的结果。这也适用于 GPU 编程。为 GPU 编译的函数将使用 NVIDIA CUDA 数学库实现,而为 CPU 编译的函数将使用主机编译器数学库实现(例如 Linux 上的 glibc)。因为这些实现是独立的,并且都不能保证正确四舍五入,所以结果通常会略有不同。
告诉你所有你需要知道的,真的。
推荐阅读
- javascript - 无法读取未定义的属性“材料”。使用嵌套对象反应 useState
- php - 即使在同一页面上,PHP 会话变量也不会更新
- vsto - Powerpoint VSTO 加载项清单有哪些要求?
- javascript - Chrome 扩展中的 Ajax 发布请求
- python - 在 python3.7 中使用 group by 发送 mySql 查询时没有结果
- visual-studio-code - vscode如何禁用选项卡自动完成
- javascript - Java 有 .class 文件,它是可执行文件/二进制文件。同样,Python 或 Javascript 是什么?
- react-native - 无法解析模块“react-transform-hmr/lib/index.js”
- css - 从material-ui文档布局两个demo
- php - 如何在具有外键的模型中创建数据库条目 - 最佳实践?