2016-12-09 6 views
0

Ich bin neu in Fortran, mit einer Funktion einige Übung Schreiben von Code, Farenheit von Celsius zurückFunktionstyp entspricht nicht der Funktionsdefinition

program Console1 

implicit none 
real, parameter :: ikind = selected_real_kind(p=15) 
real (kind = ikind):: c,f,o,faren 
print *, "enter a temperature in degrees celsius" 
read *, c 
write(*,10) "farenheit =", faren(c) 
10 format(a,f10.8) 

end program Console1 



function faren(c) 

real, parameter :: ikind = selected_real_kind(p=15) 
real (kind = ikind):: c,f 
faren = (9/5)*c + 32 

end function faren 

Ich erhalte eine Fehlermeldung # 7977: Der Typ der Funktionsreferenz tut stimmt nicht mit dem Typ der Funktionsdefinition überein.

Also, wenn ich function faren(c) zu real function faren(c) ändern, bekomme ich den gleichen Fehler, aber die Typen sind die gleichen?

Fehle ich etwas? Muss ich die Funktion im Hauptprogramm definieren?

+3

Wenn Sie dem Körper der Funktion 'implizite none' hinzufügen, erhalten Sie einen guten Hinweis, den Sie teilweise mit' real function faren' aufgreifen. Dein Compiler sagt, dass 'real' und' real (kind = ikind) 'nicht gleich sind. Haben Sie die Definitionen konsistent und die Dinge sind in Ordnung. [Eine explizite Schnittstelle verfügbar zu haben, hilft hier: siehe Module und interne Funktionen.] – francescalus

Antwort

2

Es gibt mehrere Probleme zusätzlich zu der strukturellen/code Anordnung diejenigen bereits zur Kenntnis genommen.

Zuerst KIND eine ganze Zahl ist, so dass Sie wollen

real, parameter :: ikind = selected_real_kind(p=15) 

zu

integer, parameter :: ikind = selected_real_kind(p=15) 

Idealerweise möchte man, dass (in einem Modul also) nur an einer Stelle definieren, ändern, und die Bezugs es aus Ihrem Hauptprogramm und der Funktion, aber der Code sollte gut sein, wie es für Testzwecke ist. Ein zweites Problem, das Neuankömmlinge oft auf Fortran (und Python2) stürzt, ist, dass reelle Zahlen und ganze Zahlen unterschiedliche Typen sind und nicht allgemein austauschbar sind.

faren = (9/5)*c + 32 

vereinfacht zu

faren = (1)*c + 32 

weil ganzzahlige Teilung ein ganzzahliges Ergebnis hat; 9/5 = 1

Fortran ist pingelig numerische Werte (das ist sozusagen der ganze Sinn der Sprache) so, was Sie wollen wahrscheinlich ist:

faren = (9.0/5.0) * c + 32.0 

Oder genauer gesagt, wenn faren mit einem definierten spezifische Präzision ikind,

faren = (real(9.0,ikind)/real_(5.0,ikind)) * c + real(32.0,ikind) 

oder

faren = (9.0_ikind/5.0_ikind) * c + 32.0_ikind 

Diese Syntax lässt die Köpfe der Leute explodieren. Willkommen in modernen Fortran;)

Die letzte Ausgabe befasst sich mit den Schrecken von Fortran I/O. Aus der Sicht des Designs müssen Sie wissen, welche Ergebnisse der Benutzer erwartet, und sicherstellen, dass das Ausgabeformat diese anzeigen kann. Der zulässige Bereich der Eingabewerte für c ist -273.15 (Geben oder Nehmen) zu einer oberen Grenze, die auf dem Anwendungsfall für den Code beruht. Wenn Sie mit Kochtemperaturen zu tun haben, werden Sie wahrscheinlich 400,0 nicht überschreiten; Wenn Sie Fusionsforschung betreiben, könnten Sie viel höher gehen. Sind 8 Zahlen hinter dem Komma nützlich oder glaubwürdig? In diesem Fall testen wir nur den Code, so dass wir nicht viel Präzision in der Ausgabe benötigen.

10 format(a,es10.2) 

oder

10 format(a,g16.8) 

Sie müssen die gesamte Feldbreite (die Zahl vor dem Punkt), um sicherzustellen, können die Dezimalstellen enthalten (das: Sie werden das Ausgabeformat zu so etwas wie ändern möchten Zahl nach dem Punkt) zusammen mit dem ganzzahligen Teil der Zahl plus dem Platz, der benötigt wird, um Vorzeichen und Exponent anzuzeigen. Für wissenschaftliche Notation werden vier Zeichen von Mantissenzeichen, Dezimalpunkt, 'E' und Exponentenzeichen gegessen. Es ist möglicherweise sicherer, wenn Sie nur ein Ausgabeformat von * verwenden; Es ist frustrierend, gleichzeitig mit Zahlen und Formatierungen zu kämpfen.

1

Das ist ein guter Aufwand und einfacher Start durch die Nuance, so eine gute Frage.

Persönlich würde ich reals für die Mathematik, eher die 9/5, verwenden und ein Modul verwenden. In diesem Beispiel könnten Sie einen echten oder einen doppelten Code an C2Faren übergeben und die Schnittstelle/Prozedur wird aussortieren, ob Sie die echte oder die doppelte Version verwenden möchten. Dann haben Sie ein paar Optionen, falls Sie andere Präzision wünschen.

Sie auch die ISO_C_BINDING verwenden können, wenn Sie gemischte Sprache tun ...

MODULE MyTEMPS 
PRIVATE 
DOUBLE PRECISION, PARAMETER :: C2F_ScaleFact = 1.8D0 
DOUBLE PRECISION, PARAMETER :: F2C_ScaleFact = /(1.0D0/1.8D0)/ 
DOUBLE PRECISION, PARAMETER :: F2C_Offset = 32.0D0 
PUBLIC Faren2C 

INTERFACE C2Faren 
    MODULE PROCEDURE C2Faren_Real, C2Faren_DBL 
END INTERFACE 

CONTAINS 

!========= REAL VERISON ========= 
REAL FUNCTION C2Faren_Real(c) 
IMPLICIT NONE 
real, INTENT(IN ) :: c 

C2Faren_Real = (C*F2C_ScaleFact) + F2C_Offset 

RETURN 
END FUNCTION C2Faren_Real 

!========= DOUBLE VERSION ========= 
DOUBLE PRECISION FUNCTION C2Faren_DBL(c) 
IMPLICIT NONE 
DOUBLE PRECISION , INTENT(IN ) :: c 

C2Faren_DBL = (C*F2C_ScaleFact) + F2C_Offset 

RETURN 
END FUNCTION C2Faren_DBL 

!========= REAL VERSION (Faren to Centigrade) ========= 
REAL FUNCTION faren2C(Faren) 
IMPLICIT NONE 
REAL, INTENT(IN ) :: Faren 

faren2C = (faren - F2C_Offset)/F2C_ScaleFact 

RETURN 
END FUNCTION faren2C 

END MODULE MyTEMPS 

Dann wird Ihr Programm das Modul über USE nutzt n der zweiten Zeile ...

program Console1 
USE MyTEMPS   !<== Here 
implicit none 
real :: c, f 
DOUBLE PRECISION :: Dc, Df ! No way to get Df to C or DC in the module (yet)! 
print *, "enter a temperature in degrees celsius" 
read *, c 
write(*,10) "farenheit =", C2faren(c) 
10 format(a,f10.6) 

Dc = C 
write(*,12) "farenheit =", C2faren(Dc) 
12 format("DBL:",A,f10.6) 

F = Dc 
write(*,14) "Centigrade =", faren2C(F) 
14 format("DBL:",A,f10.6) 

end program Console1 

So/und Der Hauptvorteil des Moduls besteht darin, dass Sie dieses Zeug in einer Vielzahl von Programmen verwenden und das Modul einmal testen und aussortieren wollen ... Üblicherweise legen Leute solche Sachen (viele Module) in eine Bibliothek, wenn die Modul (e) haben viele Funktionen.

Sie könnten auch nur das reale, Parameter :: ikind = selected_real_kind (p = 15) in ein Modul einfügen und das sowohl im Programm als auch in der Funktion verwenden und Sie wären da. Du warst wirklich nah dran, und es war hauptsächlich eine Frage von Stil und Nützlichkeit.

Für Intel Fortran können Sie REAL (KIND = 4) und REAL (KIND = 8) ... Was ich tun, aber das ist nicht portierbar nach gfortran, so ist es wahrscheinlich eine bessere Gewohnheit, die ISO_C_BINDING oder verwenden benutze einfach REAL und DOUBLE PRECISION.

+1

* es ist wahrscheinlich eine bessere Angewohnheit, das ISO_C_BINDING zu verwenden * Nun, vielleicht für die Programmierung gemischter Sprachen.Vielleicht ist es besser, einem Anfänger zu empfehlen, das intrinsische Modul 'iso_fortran_env' und die darin enthaltenen Typen zu verwenden, wie' real64' und 'int32'. –

+0

Guter Punkt @HighPerformanceMark Ich muss eine Menge von iFORT Code ändern, um gfortran Kompilierung zu erlauben, so ist es eine gute Erinnerung für mich auch. – Holmz

1

Module sind großartig, aber wenn Sie einen sehr einfachen Code haben, können Sie die Unterprogramme und Funktionen in Ihr Hauptprogramm einfügen. Der Trick ist, sie zu setzen, nachdem das Wort enthält:

program xxx 
stuff 

contains 

subroutine yyy 
function zzz 

end program xxx 

Auf diese Weise werden die Funktionen in den Inhalt des Hauptprogramms sehen können, so müssen Sie Ihre Parameter nicht erneut erklären, und Sie werden wahrscheinlich bekommen aussagekräftigere Fehlermeldungen

Da Sie neu habe ich eine große Ressource, die ich von zu teilen viel gelernt: http://www.uv.es/dogarcar/man/IntrFortran90.pdf