xxyxxyxyx1
xxyxxyxyx1

Reputation: 89

BLAS function returns zero in Fortran90

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

Answers (1)

roygvib
roygvib

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

Related Questions