2016-05-11 8 views
1

Ich habe den folgenden MATLAB-Code, der Folgendes tut.Wie schreibt man das in Fortran?

Angenommen, ich habe 3 Investitionen von 10 Einheiten. Die Matrix exits hat den Wert 1, wenn die Investition beendet wird. Matrix pos sagt mir die Rendite jeder der drei Investitionen. Dann berechnet die letzte Zeile des Codes das gesamte Geld, das bei veräußerten Anlagen verdient wird.

Ich versuche, eine ähnliche Codezeilen in Fortran zu schreiben. Auch unter meinem Fortran-Versuch.

clear all 

X = 10; 
ret(1,1) = -0.05; 
ret(2,1) = 0.15; 

exits = [1 0 1]; 
pos = [1 1 2]; 
ret1 = (pos == 1) .* ret(1,1) + (pos == 2) .* ret(2,1); 

inv = sum(X * ones(1,3) .* (exits) .* exp(ret1)); 

Mein Fortran-Code:

PROGRAM Matlab_replication 
IMPLICIT NONE 

INTEGER, DIMENSION(1,1) :: X = 10 
REAL, DIMENSION(2,1) :: ret 
INTEGER, DIMENSION(1,3) :: exits 
INTEGER, DIMENSION(1,3) :: pos 
REAL, DIMENSION(1,3) :: ret1 
REAL, DIMENSION(1,3) :: ret2 
REAL, DIMENSION(1,3) :: ones = 1.0 
REAL, DIMENSION(1,3) :: X1 
REAL :: inv 

ret(1,1) = -0.05 
ret(2,1) = 0.15 

exits(1,1) = 1 
exits(1,2) = 0 
exits(1,3) = 1 

pos(1,1) = 1 
pos(1,2) = 1 
pos(1,3) = 2 

X1(1,:) = X(1,1) * ones(1,:) 

ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1) 
ret2(1,:) = exp(ret1(1,:)) 

inv = sum(X1(1,:) * exits(1,:)* ret2(1,:)) 



end program 

Irgendwie die Linie ret1 = (pos == 1) * ret(1,1) + (pos == 2) * ret(2,1) nicht liefern, was ich suche. Außerdem musste ich zwei zusätzliche Variablen gegen den MATLAB-Code X1 und ret2 erstellen. Kann ich das vermeiden?

+0

Was ist Ihre Ausgabe? Was macht es, wenn es nicht das liefert, wonach Sie suchen? Betrachten Sie einen aussagekräftigeren Titel. –

+0

Ich bin mir nicht sicher. Das Problem scheint auf der logischen Indizierung von ret1 zu liegen. Ich habe ein paar Korrekturen am Fortran-Code vorgenommen, damit es genau mit dem Matlab übereinstimmt. Aber die Ausgabe ist nicht die gleiche. – phdstudent

+0

Also zeigen Sie die Ausgabe, das ist was ich verlange! –

Antwort

0

pos == 1 in Matlab gibt ein Array bestehend aus 1 und 0 zurück, während es ein Array bestehend aus .true. und .false. in Fortran zurückgibt (wie von @HighPerformanceMark vorgeschlagen). Also, du musst dich irgendwie um diesen Unterschied kümmern. Es gibt verschiedene Möglichkeiten für diese, und ein solches Beispiel ist wie folgt:

real :: ret(2), vtmp(3), inv, x 
integer :: exits(3), pos(3) 

x = 10.0 
ret = [ -0.05, 0.15 ] 

exits = [ 1, 0, 1 ] 
pos = [ 1, 1, 2 ] 

vtmp = abs([ integer:: pos == 1 ]) * ret(1) + abs([ integer:: pos == 2 ]) * ret(2) 

inv = sum(x * exits * exp(vtmp)) 

wo ich angenommen habe gfortran oder Intel Fortran und änderte alle 2-D-Arrays im ursprünglichen Code zu 1-D-Arrays für die Einfachheit.


Für andere Compiler ist der obige Code syntaktisch nicht erlaubt; in diesem Fall kann es sinnvoll sein, einige Utility-Funktionen wie

module filter_mod 
    implicit none 
    interface filter 
     module procedure filter1D, filter2D 
    end interface 
contains 
    function filter1D(mask) result(ints) 
     logical :: mask(:) 
     integer :: ints(size(mask)) 
     ints = 0 ; where(mask) ints = 1 
    end function 

    function filter2D(mask) result(ints) 
     logical :: mask(:,:) 
     integer :: ints(size(mask, 1), size(mask, 2)) 
     ints = 0 ; where(mask) ints = 1 
    end function 
end module 

und ändern Sie den ursprünglichen Code als

PROGRAM Matlab_replication 
use filter_mod 
IMPLICIT NONE 
... 
ret1 = filter(pos == 1) * ret(1,1) + filter(pos == 2) * ret(2,1) 
inv = sum(X(1,1) * exits * exp(ret1)) 

zu definieren, die hoffentlich die Übersetzung von Matlab straight-forward macht.


EDIT: Eigentlich Verwendung von merge() Funktion scheint die einfachste Lösung zu sein (dank @francescalus). Mit dieser Funktion kann der erste und zweiten Codes neu geschrieben werden als

vtmp = merge(ret(1), 0.0, pos == 1) + merge(ret(2), 0.0, pos == 2) 

und

ret1 = merge(ret(1,1), 0.0, pos == 1) + merge(ret(2,1), 0.0, pos == 2) 

Da merge() kehrt ein Array mit der gleichen Form wie pos, es ist sehr geradlinig ist auch für Multi zu verwenden -dimensionale Arrays.

+0

Der Grund für das Hinzufügen von 'abs()' ist, dass gfortran '1' für' .true' Elemente gibt, während Intel fortran '-1' für sie gibt (hmm ...). Aus diesem Grund gibt ifort, wenn ich "abs()" weglasse, inv = 19.11979 statt 21.13064. – roygvib

+3

Es gibt auch 'merge (ret (1), 0, pos == 1)', um die Abscheulichkeit von 'abs ([integer :: pos == 1]) * ret (1) 'zu vermeiden. – francescalus

+0

Oh ich kannte diese merge() - Funktion nicht ... Ich werde die Verwendung später überprüfen. Vielen Dank :) – roygvib

2

Dies kann ein erweiterter Kommentar eher als eine Antwort sein ...

Der Ausdruck

(pos == 1) * ret(1,1) + (pos == 2) * ret(2,1) 

mischt Typen in einer Art und Weise nicht akzeptabel Fortran. Der erste Term (pos == 1) ist vom Typ logical und ergibt entweder .true. oder .false.. Das ist nicht etwas, was dann mit einer Zahl multipliziert werden kann, oder mit irgendetwas anderem.

Eigentlich sind die Dinge etwas schlechter als ich zuerst realisiert, da pos ein Array ist. Erwarten Sie eine Reihe von Ergebnissen oder ein einzelnes Ergebnis aus diesem Begriff?

Ich bin mir nicht sicher, was Sie versuchen, aber Sie müssen (pos == 1) in eine Zahl irgendwie umwandeln, wenn Sie es multiplizieren möchten. Es ist ziemlich einfach, eine Fortran-Funktion zu schreiben, um 1 (oder was auch immer Sie wollen) für einen .true. Eingang und eine andere Zahl für einen .false. Eingang zurückzugeben.

Endlich bin ich überrascht, dass Ihr Fortran-Code irgendetwas zurückgibt, wie Sie in Ihrem Kommentar behaupten. Ich bin überrascht, dass es kompiliert.

+0

Wenn er GCC verwendet, ist es wahrscheinlich [implizit konvertieren] (https://gcc.gnu.org/onlinedocs/gcc-4.0.3/gfortran/Implicitly-interconvert-LOGICAL-and-INTEGER.html) den Typ in eine ganze Zahl und könnte somit den Code kompilieren. Es sollte jedoch eine Warnung während der Kompilierung geben ... – Gabe

+0

Ja, jetzt, wo ich die Möglichkeit hatte, den Code selbst zu kompilieren, löst meine Installation von gfortran eine Warnung aus, kein Fehler. –