Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在fortran中对数组子集使用BLAS?gemm_Arrays_Fortran_Slice_Blas - Fatal编程技术网

Arrays 在fortran中对数组子集使用BLAS?gemm

Arrays 在fortran中对数组子集使用BLAS?gemm,arrays,fortran,slice,blas,Arrays,Fortran,Slice,Blas,BLAS=90中的数组片(而不是某个数组元素的地址),我认为Fortran代码中的以下行 call dgemm('n','n', 100,100,100, 1d0, a,200, a(1:100,101:200),200, 0d0, a(101:200,1:100),200 ) 可能应该修改为 call dgemm('n','n', 100,100,100, 1d0, a,200, a(1:100,101:200),100, 0d0, a(101:200,1:100),100 ) 其中后两个

BLAS
函数的各种
LDx
参数可以在较大阵列的切片上进行操作。例如,这个小C程序对(200200)矩阵的左上和右上(100100)子矩阵进行矩阵乘法,并将结果存储在左下(100100)子矩阵中

#include <stdlib.h>
#include <stdio.h>
#include <cblas.h>
int main()
{
    double * a = malloc(200*200*sizeof(double));
    for(int i = 0; i < 200*200; i++) a[i] = 1;
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 100, 100, 100, 1, a, 200, a+100*200, 200, 0, a+100, 200);
    printf("%f\n", a[100]);
    return 0;
}

$ gcc -o cblas_test{,.c} -lcblas
$ ./cblas_test
100.000000
我做错了什么

编辑:如果我先将
a
按摩到1d数组中,则此选项有效:

program fblas_example2
    use, intrinsic :: iso_c_binding
    implicit none
    real(8), target, allocatable :: a(:,:)
    real(8), pointer :: fa(:)
    allocate(a(200,200))
    a = 1
    call c_f_pointer(c_loc(a), fa, [size(a)])
    call dgemm('n','n',100,100,100,1d0,fa,200,fa(100*200+1:),200,0d0,fa(101:),200)
    write(*,*) fa(101)
end program

$ gfortran -o fblas_example2{,.f90} -lblas
$ ./fblas_example2
   100.00000000000000
但很奇怪的是,人们必须通过ISOC绑定才能从fortran调用fortran库


我要说的是:我知道人们可以复制出这些块,对它们进行处理,然后再将它们复制回来。但是我在这里要问的是如何使用BLAS自己的支持来处理数组的子集。

当您给出
LDx
时,您声明了矩阵的实际大小(前导维度)。然后,
BLAS
使用此值从乘法中跳过未使用的数据

我认为你应该像在
C
中一样使用
dgemm
。我的意思是不应该传递子矩阵
a(1:100101:200)
,而是传递子矩阵的第一个值
a(1101)
的位置

#include <stdlib.h>
#include <stdio.h>
#include <cblas.h>
int main()
{
    double * a = malloc(200*200*sizeof(double));
    for(int i = 0; i < 200*200; i++) a[i] = 1;
    cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 100, 100, 100, 1, a, 200, a+100*200, 200, 0, a+100, 200);
    printf("%f\n", a[100]);
    return 0;
}

$ gcc -o cblas_test{,.c} -lcblas
$ ./cblas_test
100.000000
我测试了以下各项,似乎效果良好

program fblas_example
  implicit none
  real(8), allocatable :: a(:,:)
  allocate(a(200,200))
  a = 1
  call dgemm('n','n',100,100,100,1d0,a,200,a(1,101),200,0d0,a(101,1),200)
  write(*,*) a(101,1)
end program

$ gfortran dgemm.f -lblas
$ ./a.out 
  100.00000000000000   

如果要传递Fortran>=90中的数组片(而不是某个数组元素的地址),我认为Fortran代码中的以下行

call dgemm('n','n', 100,100,100, 1d0, a,200, a(1:100,101:200),200, 0d0, a(101:200,1:100),200 )
可能应该修改为

call dgemm('n','n', 100,100,100, 1d0, a,200, a(1:100,101:200),100, 0d0, a(101:200,1:100),100 )
其中后两个阵列切片(或子阵列)的前导尺寸已从200更改为100

更具体地说,
a(1:100101:200)
a(101:200,1:100)
通过隐式接口传递给
dgemm
,其中数组片在内存中不连续。在这种情况下,编译器将首先为每个子数组准备两个大小为100x100的数组临时数组,将原始数组
a
的矩阵元素复制到数组临时数组,并传递临时数组的第一个元素的地址。通过
dgemm
完成计算后,临时数组的内容将被适当地复制回原始数组
a
。如果出现这种情况,
dgemm
接收两个前导尺寸为100(而不是200)的数组

您可以通过
-fcheck array temporaries
(在gfortran中)和
-check arg\u temp\u created
(在ifort中)选项来检查数组temporaries的生成。例如,后者给出了

forrtl: warning (402): fort: (1): In call to DGEMM, an array temporary was created for argument #9
forrtl: warning (402): fort: (1): In call to DGEMM, an array temporary was created for argument #12
100.000000000000

是的,我当然可以复制到新阵列中。有时这甚至会更快。但并非总是如此。我要问的是如何在不复制到新阵列的情况下执行此操作。毕竟,这就是LDx参数的目的,所以它显然是可能的。啊,对了,因为值在fortran中是通过引用传递的,所以
a(1101)
实际上是指向该元素的指针。这是有道理的,没错
Fortran
倾向于隐藏东西,而使用
C
可以解释行为。谢谢。这是有道理的,也解释了这个错误。但我更喜欢另一个答案,因为我的目标是避免复制数组。@amaurea没问题,实际上我也更喜欢另一个答案,因为我通常试图避免出现这样的数组临时值:)