2017-06-13 10 views
1

GPUを使用してガウスの直交数値積分を使用して積分を計算するプログラムを作成しようとしました。私はこのプログラムがなぜ機能していないのか理解しようとしています。私は関数呼び出しd_oneで渡されたパラメータがcudaのcコードに正しくコピーされていないという事実に固定していると思います。なぜこれが起こっているのか分かりません。私はそれを理解しようと多くの時間を費やしましたが、どこでもそれを得ることができませんでした。プログラムの出力は12.49999でなければなりません変数が誤ってFortranからcuda cプログラムにコピーされました

#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; 
} 

のFortranプログラム:

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 

CUDAプログラムここで

2つのプログラムです。私は-314の順番で答えを得ています。あなたが提供していただきありがとうございます!

+5

21世紀の暗黙のタイピングを使っている人は誰でも、ターンパイクを下ろしてくる苦痛に遭遇するでしょう。おそらくあなたが報告したエラーの原因ではありませんが、それがエラーの原因である可能性を排除するためにプログラムを修正するのは数秒です。 –

+0

はHPMと完全に同意します。 FORTRANが好きなのは、どのコードも 'IMPLICIT NONE'で始まるからです。 Imhoは一般的にコーディングのための最高のモットーです。 – user463035818

+3

少なくとも、明示的な 'implicit'ステートメントを使っています。これは、' real * 8'変数を 'float'に渡そうとしていることを明らかにしていません。 – tera

答えて

1

単精度浮動小数点または倍精度浮動小数点変数を使用するかどうかを決定します。

現時点では、Fortran側で倍精度real*8、C(++)側で単精度floatを使用しています。

real*4floatのいずれか、またはreal*8doubleのいずれかを使用してください。

+0

ありがとうございます!これは私の問題を解決しました!私はあなたの助けにあまり感謝します! – Bassa

関連する問題