Reputation: 89
I am learning to use BLAS in Fortran90, and wrote a simple program using the subroutine SAXPY and the function SNRM2. The program computes the distance between two points by subtracting one vector from the other, then taking the euclidean norm of the result.
I am specifying the return value of SNRM2 as external
according to the answer to a similar question, "Calling BLAS functions".
My full program:
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
The result of the program is:
difference vector: -3.00000000 4.00000000 0.00000000
length of diff vector: 0.00000000
The difference vector is correct, but the length ought to be 5. So why is SNRM2 returning a value of zero?
I know the variable dist
is modified by SNRM2, so I don't suspect my openBLAS installation is broken. I'm running macos10.13 and installed everything with homebrew.
I am compiling with gfortran with many flags enabled, and I get no warnings:
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
I tried looking at the code for snrm2.f, but I don't see any potential problems.
I also tried declaring my variables with real(4)
or real(selected_real_kind(6))
with no change in behavior.
Thanks!
Upvotes: 4
Views: 406
Reputation: 7395
According to this page, there seems to be some issue with single precision routines in the BLAS shipped with Apple's Accelerate Framework. On my Mac (OSX10.11), gfortran-8.1 (installed via Homebrew) + default BLAS (in the system) gives a wrong result:
$ 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
while explicitly linking with OpenBLAS (installed via Homebrew) gives the correct result:
$ 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
The above page suggests that the problem occurs when linking with the system BLAS in a way that is not compliant with the old g77 style. Indeed, attaching -ff2c
option gives the correct result:
$ gfortran-8 -ff2c test.f90 -lblas
$ ./a.out
difference vector: -3.00000000 4.00000000 0.00000000
length of diff vector: 5.00000000
But I guess it may be better to use the latest OpenBLAS (than using -ff2c
option) ...
The following is a separate test in C (to check that the problem is not specific to 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
As far as I've tried, the double-precision version (DNRM2) works even with the system BLAS, so the problem seems only with the single-precision version (as suggested in the above page).
Upvotes: 3