【问题标题】:Transfer from Column Major to Row Major从列专业转移到行专业
【发布时间】:2015-06-23 15:53:56
【问题描述】:

我正在尝试将使用 Fortran 编写并使用列主要排序的算法转换为使用行主要排序的 C。 该算法使用 gemv blas 调用。

我在 cblas 界面中更改了对行主要布局的调用:

  • 切换转置标志
  • M 和 N 互换
  • 更改前导尺寸

但算法的行为并不相同。我得到不同的结果。 我创建了一个显示行为的最小样本。

#include <stdio.h>

void dgemv_( const char * t, const int * m, const int * n, const double * alpha, const double * A, const int *lda, const double * X, const int * incx, 
    const double * beta, double * Y, const int *incy );

int main()
{
    const int M = 2, N = 2;
    const int one = 1;
    const double alpha = -1.0, beta = 1.0;
    const char trans = 'T';
    const char noTrans = 'N';

    double Yc[4] = { 0x1.42c7bd3b6266cp+4, 0x1.6c6ff393729dp+4, 0x1.acee1f3938c0bp-2, 0x1.b0cd5ba440d93p+0 };
    double Yr[4] = { 0x1.42c7bd3b6266cp+4, 0x1.acee1f3938c0bp-2, 0x1.6c6ff393729dp+4, 0x1.b0cd5ba440d93p+0 };

    double A[2] = { 0x1.11acee560242ap-2, 0x1p+0 };

    double Bc[2] = { 0x1.8p+2, 0x1.cp+2 };
    double Br[2] = { 0x1.8p+2, 0x1.cp+2 };

    dgemv_( &noTrans, &M, &N, &alpha, Yc, &M, A, &one, &beta, Bc, &one );

    printf("Result Column Major\n");
    printf("%a %a\n", Bc[0], Bc[1]);

    dgemv_( &trans, &N, &M, &alpha, Yr, &N, A, &one, &beta, Br, &one );

    printf("Result Row Major\n");
    printf("%a %a\n", Br[0], Br[1]);
}

我使用格式字符串 %a 来获取值的十六进制表示来比较它们。使用列主版本生成的向量如下所示:

0x1.8402515a17beap-3 -0x1.8e67415bce3aep-1

虽然排成一排的专业看起来像这样:

0x1.8402515a17bep-3 -0x1.8e67415bce3bp-1

这是如何解释的以及可以做些什么来使算法工作相同?

【问题讨论】:

  • 你真的觉得十六进制数字更容易阅读吗?我不知道他们有多大的不同。可能这只是一个小的舍入误差。

标签: c algorithm fortran blas


【解决方案1】:

如果结果与十进制表示比较

double x = 0x1.8402515a17beap-3, y = 0x1.8402515a17bep-3;
printf( "%40.30f\n", x );
printf( "%40.30f\n", y );
printf( "%40.30f\n", x - y );

他们同意最多 15 个有效数字

    0.189457545816338168709336287066
    0.189457545816337891153580130776
    0.000000000000000277555756156289

所以对于double 的双精度计算,差异似乎足够小。至于-0x1.8e67415bce3aep-1-0x1.8e67415bce3bp-1,差别也在1.0e-15以下。

   -0.778131525475250773737911913486
   -0.778131525475250995782516838517
    0.000000000000000222044604925031

为了获得更好的一致性,可能需要四倍(或更高)的精度。

【讨论】:

  • 我知道这个例子的差别真的很小,但这只是算法的一小部分。在此 gemv 调用之前,结果是二进制相同的。在迭代过程中,失败将总结起来,因此结果将真正不同。在将算法从列主要布局转移到行主要布局时,有什么我没有提到的吗?
  • 嗨@Schrigga 我认为具有有限精度的数值计算或多或少会受到舍入误差及其累积的影响,其程度取决于计算的完成方式(例如,@987654322 @)。如果错误似乎随着迭代的进行而增加,则编辑问题以添加更多信息(甚至发布一个专注于算法部分的新问题)可能会很有用。
  • @Schrigga 至于矩阵转置,我猜 dgemv() 可能会在内部执行不同顺序的算术运算(或算法),具体取决于“T”或“N”,这可能会导致结果略有不同(在舍入误差内)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 2018-07-07
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多