Функция BLAS возвращает ноль в Fortran90 - PullRequest
0 голосов
/ 13 мая 2018

Я учусь использовать BLAS в Fortran90 и написал простую программу с использованием подпрограммы SAXPY и функции SNRM2 . Программа вычисляет расстояние между двумя точками, вычитая один вектор из другого, затем принимая евклидову норму результата.

Я указываю возвращаемое значение SNRM2 как external в соответствии с ответом на аналогичный вопрос, "Вызов функций BLAS" . Моя полная программа:

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 и установил все вместе с homebrew.

Я компилирую с помощью 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)) без изменений в поведении.

Спасибо!

1 Ответ

0 голосов
/ 14 мая 2018

Согласно этой странице , существует некоторая проблема с процедурами с одинарной точностью в BLAS, поставляемом с Apple Accelerate Framework. На моем 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 

На этой странице показано, что проблема возникает при соединении с системой BLAS способом, который не соответствует старому стилю g77. Действительно, добавление опции -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, поэтому проблема возникает только с версией с одинарной точностью (как предложено на предыдущей странице).

...