2017-06-13 2 views
1

Ich habe versucht, ein Programm zu schreiben, das GPU verwendet, um ein Integral zu berechnen, das Gaussianquadratur numerische Integration verwendet. Ich habe versucht herauszufinden, warum dieses Programm nicht funktioniert. Ich denke, ich habe darauf hingewiesen, dass die Parameter, die im Funktionsaufruf d_one übergeben werden, nicht korrekt in den cuda c-Code kopiert werden. Ich bin mir nicht sicher, warum das passiert. Ich verbrachte so viel Zeit damit, es herauszufinden, aber ich konnte damit nicht weiterkommen.Variablen falsch kopiert von einem Fortran zu einem cuda c Programm

Hier sind die beiden Programme:

Das Fortran-Programm:

implicit real*8(a-h,o-z) 
    parameter (nlinx = 22) ! Total number of mesh regions 
    dimension sx(3*nlinx),swx(3*nlinx) 

    xa = 0.d0 
    xb = 5.d0 
    ! In the following "nptx" is the total number of integration 
    ! points. So, it is (nlinx * 3) 
    call meshwt1(xa,xb,nlinx,ntan,sx,swx,nptx) 

    ans0 = 0.d0 

    CAll d_one(sx, swx, nptx, ans0) 

    print *, ans0 

    stop 

    end 

SUBROUTINE MESHWT1(A,B,N,NT,X,W,NTOT) 
    implicit real*8(a-h,o-z) 
    !3*N LINEAR POINTS FOR A TO B 
    !NT=0 OR 1, 3*NT TAN PTS FOR B TO INFINITY 
    !NTOT= 3*(N+NT) 
    DIMENSION X(*),W(*),G(3),GW(3) 
    G(1) = -0.7745966 
    G(2) = 0.0000000 
    G(3) = -G(1) 
    GW(2) = 0.8888888 
    GW(1) = 0.5555555 
    GW(3) = GW(1) 
    Y = N 
    DX = (B - A)/Y 
    K = 0 
    XA = A - DX 
    XB = A 
    DO 2 I = 1, N 
    XA = XA + DX 
    XB = XB + DX 
    DO 2 J = 1, 3 
    K = K + 1 
    X(K) = 0.5 * (XA + XB) + 0.5 * (XB - XA) * G(J) 
2 W(K) = 0.5 * (XB - XA) * GW(J) 
    NTOT = K 
    IF(NT .EQ. 1) GO TO 3 
    GO TO 5 
3 NTOT = K + 3 
    DO 4 J = 1, 3 
    K = K + 1 
    Y = (1.0 + G(J)) * 3.14159 * 0.25 
    X(K) = XB + DTAN(Y) 
4 W(K) = GW(J) * 3.14159 * 0.25/(DCOS(Y)) ** 2 
5 CONTINUE 
    RETURN 
    END 

Das CUDA-Programm:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <cuda.h> 
#include <cuda_runtime.h> 
__global__ void loop_d(float *a, float *b, int N, float *ans) 
{ 
    __shared__ float temp[66]; 
    int idx = threadIdx.x; 
    if (idx < 66) 
    { 
       temp[idx] = a[idx] * b[idx]; 
    } 
    __syncthreads(); 
    if (0 == idx) 
    { 
      float sum = 0.0; 
      for (int i=0; i < 66; i++) 
      { 
        sum += temp[i]; 
      } 
      *ans = sum; 
    } 
} 
// The following function is called from the Fortran program 
extern "C" void d_one_(float *a, float *b, int *Np, float *ans) 
{ 
    float *a_d, *b_d, *ans_d; // Declaring GPU Copies of the parameters passed 
    int blocks = 1; // Number of blocks used 
    int N = *Np; // Number of threads is determined by the parameter nptx passed from the Fortran program 

    // Allocating GPU memory 
    cudaMalloc((void **)&a_d, sizeof(float) * N); 
    cudaMalloc((void **)&b_d, sizeof(float) * N); 
    cudaMalloc((void **)&ans_d, sizeof(float)); 
    // Copying information from CPU to GPU 
    cudaMemcpy(a_d, a, sizeof(float) * N, cudaMemcpyHostToDevice); 
    cudaMemcpy(b_d, b, sizeof(float) * N, cudaMemcpyHostToDevice); 
    cudaMemcpy(ans_d, ans, sizeof(float), cudaMemcpyHostToDevice); 
    // Calling the function on the GPU 
    loop_d<<< blocks, N >>>(a_d, b_d, N, ans_d); 
    cudaMemcpy(a, a_d, sizeof(float) * N, cudaMemcpyDeviceToHost); 
    cudaMemcpy(b, b_d, sizeof(float) * N, cudaMemcpyDeviceToHost); 
    cudaMemcpy(ans, ans_d, sizeof(float), cudaMemcpyDeviceToHost); 

    // Freeing GPU memory 
    cudaFree(a_d); 
    cudaFree(b_d); 
    cudaFree(ans_d); 
    return; 
} 

Die Ausgabe des Programms sollte 12,49999 sein. Ich bekomme eine Antwort in der Größenordnung von -314. Vielen Dank für Ihre Anregungen!

+5

Jeder, der im 21. Jahrhundert implizit tippt, verdient all den Schmerz, der sich auf dem Schlagbaum auf sie niederschlägt. Es ist wahrscheinlich nicht die Quelle der Fehler, die Sie melden, aber es ist eine Frage von Sekunden, das Programm zu ändern, um die Möglichkeit auszuschließen, dass es die Quelle der Fehler ist. –

+0

stimmen vollständig mit HPM überein. Der Grund, warum ich FORTRAN liebe, ist, dass jeder Code mit "IMPLICIT NONE" beginnen sollte. Imho das beste Motto überhaupt für die Codierung im Allgemeinen. – user463035818

+3

Zumindest verwendet er eine explizite "implizite" Anweisung, die es offensichtlich macht, dass er versucht, 'echte * 8'-Variablen in' Floats' zu überführen. – tera

Antwort

1

Entscheiden Sie, ob Sie Fließkomma-Variablen mit einfacher oder doppelter Genauigkeit verwenden möchten.

Im Moment verwenden Sie die doppelte Genauigkeit real*8 auf der Fortran-Seite und die einfache Genauigkeit float auf der C (++) -Seite.

Verwenden Sie entweder real*4 und float zusammen oder real*8 und double.

+0

Vielen Dank! Das hat mein Problem gelöst! Ich schätze deine Hilfe so sehr! – Bassa

Verwandte Themen