首页 > 解决方案 > BLAS 函数在 Fortran90 中返回零

问题描述

我正在学习在 Fortran90 中使用 BLAS,并使用子程序SAXPY和函数SNRM2编写了一个简单的程序。该程序通过从另一个向量中减去一个向量来计算两点之间的距离,然后取结果的欧几里得范数。

external根据类似问题“调用 BLAS 函数”的答案指定 SNRM2 的返回值。我的完整程序:

program test
implicit none

real :: dist
real, dimension(3) :: a, b
real, external :: SNRM2

a = (/ 3.0, 0.0, 0.0 /)
b = (/ 0.0, 4.0, 0.0 /)

call SAXPY(3, -1.0, a,1, b,1)
print *, 'difference vector: ', b

dist = 6.66  !to show that SNRM2 is doing something
dist = SNRM2(3, b, 1) 
print *, 'length of diff vector: ', dist

end program test

该程序的结果是:

difference vector:   -3.00000000       4.00000000       0.00000000    
length of diff vector:    0.00000000

差分向量是正确的,但长度应该是 5。那么为什么 SNRM2 返回值为零?


我知道这个变量dist是由 SNRM2 修改的,所以我不怀疑我的 openBLAS 安装被破坏了。我正在运行 macos10.13 并使用自制软件安装了所有内容。

我正在使用启用了许多标志的 gfortran 进行编译,但没有收到任何警告:

gfortran test.f90 -lblas -g -fimplicit-none -fcheck=all -fwhole-file -fcheck=all -fbacktrace -Wall -Wextra -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wconversion -Wno-unused-parameter -pedantic -o test

我尝试查看snrm2.f 的代码,但没有发现任何潜在问题。

我还尝试在行为改变real(4)或不改变的情况下声明我的变量。real(selected_real_kind(6))

谢谢!

标签: fortranfortran90blasopenblas

解决方案


根据此页面,Apple Accelerate Framework 附带的 BLAS 中的单精度例程似乎存在一些问题。在我的 Mac (OSX10.11) 上,gfortran-8.1(通过 Homebrew 安装)+ 默认 BLAS(在系统中)给出了错误的结果:

$ gfortran-8 test.f90 -lblas
or
$ gfortran-8 test.f90 -L/System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/Versions/Current/ -lBLAS
$ ./a.out
 difference vector:   -3.00000000       4.00000000       0.00000000    
 length of diff vector:    0.00000000  

而与 OpenBLAS 显式链接(通过 Homebrew 安装)给出了正确的结果:

$ gfortran-8 test.f90 -L/usr/local/Cellar/openblas/0.2.20_2/lib -lblas
$ ./a.out
 difference vector:   -3.00000000       4.00000000       0.00000000    
 length of diff vector:    5.00000000 

上面的页面表明,以不符合旧 g77 样式的方式与系统 BLAS 链接时会出现问题。事实上,附加-ff2c选项给出了正确的结果:

$ gfortran-8 -ff2c test.f90 -lblas
$ ./a.out
 difference vector:   -3.00000000       4.00000000       0.00000000    
 length of diff vector:    5.00000000  

但我想使用最新的 OpenBLAS 可能会更好(比使用-ff2c选项)...


以下是 C 中的单独测试(检查问题是否特定于 gfortran)。

// test.c
#include <stdio.h>
float snrm2_( int*, float*, int* );

int main()
{
    float b[3] = { -3.0f, 4.0f, 0.0f };
    int n = 3, inc = 1;

    float dist = snrm2_( &n, b, &inc );

    printf( "b = %10.7f %10.7f %10.7f\n", b[0], b[1], b[2] );
    printf( "dist = %10.7f\n", dist );
    return 0;
}

$ gcc-8 test.c -lblas
$ ./a.out
b = -3.0000000  4.0000000  0.0000000
dist =  0.0000000

$ gcc-8 test.c -lblas -L/usr/local/Cellar/openblas/0.2.20_2/lib
$ ./a.out
b = -3.0000000  4.0000000  0.0000000
dist =  5.0000000

据我尝试,双精度版本 (DNRM2) 甚至可以与系统 BLAS 一起使用,因此问题似乎只与单精度版本有关(如上页所示)。


推荐阅读