Content

C und Fortran Funktionen

Wir beginnen mit

Das Fortran Hauptprogramm ruft die Subroutine auf und gibt ein davon abhängiges Ergebnis aus.

Dann ersetzen die Fortran Routine mit einer C Funktion. Das Fortran Programm wird das gar nicht merken.

Reines Fortran Beispiel

Hauptprogramm

      PROGRAM SUMTEST

*  Externe Funktionen, die aufgerufen werden
      DOUBLE PRECISION DSUM

*  Wo wird I und X im Speicher abgelegt?
      INTEGER          I
      DOUBLE PRECISION X(10), ALPHA

*  Vektor X mit etwas pseudo wichtigem initialisieren
      DO 10 I = 110
          X(I) = I ** 2
   10 CONTINUE

      WRITE (*,*'X =', X

      ALPHA = DSUM(10, X, 1)
      WRITE (*,*'ALPHA = DSUM(10, X, 1) =', ALPHA

      ALPHA = DSUM(5, X, 2)
      WRITE (*,*'ALPHA = DSUM(5, X, 2) =', ALPHA

      ALPHA = DSUM(5, X(2), 2)
      WRITE (*,*'ALPHA = DSUM(5, X(2), 2) =', ALPHA

      END

Subroutine

      DOUBLE PRECISION FUNCTION DSUM( N, X, INCX)

*  Definition der Argumente
*  .. Skalare Argumente
      INTEGER            N, INCX

*  .. Array Argument
      DOUBLE PRECISION   X(*)

*  Lokale Variablen (Werden auf dem Stack angelegt)
      INTEGER I, NINC

*  Parameter (Wo werden die angelegt?)
      DOUBLE PRECISION   Zero
      PARAMETER          ( ZERO = 0.0D+0 )

*  Wir beginnt die eigentliche Arbeit

      DSUM = Zero

      NINC = N*INCX

      DO 10 I = 1, NINC, INCX
          DSUM = DSUM + X(I)
  10  CONTINUE

      RETURN
      END

Übersetzen, Linken und ausführen

Wir übersetzten die Fortran Source Dateien einzeln und erzeugen zunächst nur Object Files. Bei diesen kann man dann auch mit otool prüfen, wo genau Variablen angelegt wurden.

$shell> gfortran -Wall -fimplicit-none -c dsum.f                               
$shell> gfortran -Wall -fimplicit-none -c sumtest.f                            

Dann Linken wir diese zu einer ausführbaren Datei (hier werden heimlich noch System Bibliotheken zu den Object Files dazugelinkt):

$shell> gfortran dsum.o sumtest.o                                              

Jetzt kann man testen was das Ganze tut:

$shell> ./a.out                                                                
 X =   1.0000000000000000        4.0000000000000000        9.0000000000000000        16.000000000000000        25.000000000000000        36.000000000000000        49.000000000000000        64.000000000000000        81.000000000000000        100.00000000000000     
 ALPHA = DSUM(10, X, 1) =   385.00000000000000     
 ALPHA = DSUM(5, X, 2) =   165.00000000000000     
 ALPHA = DSUM(5, X(2), 2) =   220.00000000000000     

Aufgabe:

Fortran Funktion mit C-Funktion ersetzen

Mit folgender C-Funktion kann man die Fortran Routine ersetzen:

double
dsum_(int *n, double *x, int *incX)
{
    double result = 0.0;
    int    i, nInc;

    nInc = (*n) * (*incX);

    for (i=0; i<nInc; i+=(*incX)) {
        result += x[i];
    }

    return result;
}

Wir erzeugen für die C-Funktion das Object File

$shell> gcc-4.8 -Wall -c new_dsum.c                                            

Und linken mit dem Object File des Hauptporgramms

$shell> gfortran new_dsum.o sumtest.o                                          

Jetzt kann man wieder testen ob das Ganze tut:

$shell> ./a.out                                                                
 X =   1.0000000000000000        4.0000000000000000        9.0000000000000000        16.000000000000000        25.000000000000000        36.000000000000000        49.000000000000000        64.000000000000000        81.000000000000000        100.00000000000000     
 ALPHA = DSUM(10, X, 1) =   385.00000000000000     
 ALPHA = DSUM(5, X, 2) =   165.00000000000000     
 ALPHA = DSUM(5, X(2), 2) =   220.00000000000000     

Makefile

Schaut euch folgendes (viel zu primitives) Makefile an:

all: sum_f77 sum_c

sum_f77: dsum.o sumtest.o
    gfortran -Wall -fimplicit-none -o sum_f77 dsum.o sumtest.o

sum_c: new_dsum.o sumtest.o
    gfortran -Wall -fimplicit-none -o sum_c new_dsum.o sumtest.o

new_dsum.o: new_dsum.c
    gcc-4.8 -Wall -c new_dsum.c

dsum.o: dsum.f
    gfortran -Wall -fimplicit-none -c dsum.f

sumtest.o: sumtest.f
    gfortran -Wall -fimplicit-none -c sumtest.f

clean:
    rm -f *.o sum_f77 sum_c

Aufgabe: Verbessert es