2013-05-24 5 views
2

Я пытаюсь перекодировать старую C++-программу в Fortran, чтобы использовать LAPACK (я знаю, что C++ имеет LAPACK ++, но у меня много проблем с его установкой, поэтому я дал вверх).Функция return type несоответствие

У меня изначально не возникало проблем с компиляцией, но это было тогда, когда у меня были все переменные, объявленные как REAL. Когда я начал кодировать раздел программы, требующий LAPACK, я обнаружил, что все параметры, переданные в DSYEV, должны быть DOUBLE PRECISION. Поэтому я попытался изменить все на двойную точность (включая изменение всех жестко закодированных чисел на их двойные копии точности, то есть 0.0 -> 0.0D0). Теперь, когда я пытаюсь скомпилировать, я получаю следующую ошибку для всех функций и подпрограмм, которые я 've написал:

Error: Return type mismatch of function <function> at (1) (REAL(4)/REAL(8)) 

Я не уверен, откуда это происходит, поскольку все в программе было изменено на двойную точность.

Например, я заявил следующее:

double precision :: alpha(3),d(3),zeta1,zeta2 
double precision :: A1(3),A2(3),D1(3),D2(3) 
double precision :: PI 
PI = 3.14159265359D0 
alpha = (/0.109818D0, 0.405771D0, 2.22766D0/) 
d = (/0.444635D0, 0.535328D0, 0.154329D0 /) 

do 10 i=1,3 

A1(i) = alpha(i)*zeta1**2.0D0 
A2(i) = alpha(i)*zeta2**2.0D0 
D1(i) = d(i)*(2.0D0*A1(i)/PI)**(3.0D0/4.0D0) 
D2(i) = d(i)*(2.0D0*A2(i)/PI)**(3.0D0/4.0D0) 

10 continue 

И функции:

subroutine createS(S,A1,A2,D1,D2,r) 
double precision A1(3),A2(3),D1(3),D2(3) 
double precision r 
double precision S(2,2) 
integer :: i,j 
S(1,1) = 1.0D0 
S(2,2) = 1.0D0 
do 80 i=1,3 
do 90 j=1,3 

S(1,2) = S(1,2) + getS(A1(i),A2(j),r)*D1(i)*D2(j) 

90 continue 
80 continue 
S(2,1) = S(1,2) 
return 
end 

double precision function getS(a,b,r) 
double precision :: PI 
double precision a,b,r 
double precision :: S 
PI = 3.14159265359D0 
S = (PI/(a+b))**1.5D0 
S = S*dexp(-(a*b*r*r)/(a+b)) 
getS = S 
return 
end 

И тогда я получаю ошибку

HFSTO3G.f:85.28: 

    S(1,2) = S(1,2) + getS(A1(i),A2(j),r)*D1(i)*D2(j)     
         1 
    Error: Return type mismatch of function 'gets' at (1) (REAL(4)/REAL(8)) 

Я использую gfortran Скомпилировать. Это может быть проблема? Я не новичок в программировании, но новичок в Fortran. Не программировать это в Фортране не вариант.

+0

есть и другие библиотеки для C++, которые делают линейную алгебру, просто говоря альтернативный :) – steabert

ответ

4

Вы поместили свои подпрограммы и функции в модуль и use этот модуль? В противном случае, вероятно, происходит то, что вы получаете неявное типирование getS в подпрограмме createS как единственную точность реального, но фактически возвращает двойную точность. Другое предложение: всегда используйте implicit none, чтобы найти необъявленную переменную. Если вы забудете включить в исходный код implicit none, gfortran предоставляет параметры компилятора -fimplicit-none. Неявное типирование является пагубным и, вероятно, продолжено в Fortran для поддержки устаревшего кода.

P.S. double precision также устарел, но гораздо менее рискован, чем неявный ввод. Если у вас есть последняя версия gfortran, вы можете использовать следующее:

use ISO_FORTRAN_ENV 
real (real64) :: 

См. Руководство gfortran.

EDIT: implicit none изменил тип getS от реального (4) (путем неявного ввода) до неизвестного (тип объявлен, неявное типирование отключено). Если вы поместите процедуры в модуль, они будут «знать» типы друг друга: возвращаемые функции и типы аргументов. Это исправит эту ошибку. Это также помогает компилятору найти другие ошибки, но позволяет проверять согласованность аргументов между вызовом и аргументами процедуры. См. Примеры Correct use of modules, subroutines and functions in fortran и Computing the cross product of two vectors in Fortran 90.

+0

я сделал не использовать неявное ни на моей одной подпрограммой, но я добавил его ко всем подпрограммам и функциям, и теперь это дает мне ту же ошибку, но вместо REAL (4)/REAL (8) по ошибке это дает мне UNKNOWN/REAL (8) –

+0

Я ожидаю, что вы сейчас получаете вторая ошибка, что getS не объявлен в подпрограмме createS. Это ключ к проблеме. Его нужно вводить как двойную точность ..., которую вы автоматически получите, разместив свои подпрограммы в модуле. –

2

Вы не объявляете getS в качестве функции в подпрограмме createS. Вы должны добавить double precision, external :: getS в свои объявления переменных подпрограммы createS.

+3

Мое мнение: лучше не использовать 'external' в современном Fortran. Если функция находится в Фортране, и у вас есть исходный код, поместите его в модуль и «используйте» этот модуль. Если он находится на другом языке или находится в библиотеке, и у вас нет исходного кода, напишите для него инструкцию 'interface'. Оба интерфейса и модуль дают вам проверку согласованности аргументов. Для использования многих «расширенных» функций Fortran> = 90 требуется явный интерфейс. –

+1

Я согласен с этим для ** современного ** Fortran, но OP, похоже, использует F77, поэтому я побежал с тем, что является общим для этого. (Хотя, если OP отправлял F90 +, я, вероятно, рекомендовал бы простой 'contains' в подпрограмме' createS'). –

+0

Спасибо за эти комментарии. Почему не рекомендуется использовать внешние? –

-1

заменить двойной точности с:

REAL (Kind=8) 
INTEGER (Kind=4) 
COMPLEX (Kind=8) 
+1

Это не очень хороший ответ. –