#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
#include <cuda_runtime.h>
#include <cutil.h>
#if __DEVICE_EMULATION__
bool InitCUDA(void){
   fprintf(stderr, "Режим эмуляции\n");  
   return true;
}
#else
bool InitCUDA(void) {
   int deviceCount;
   cudaGetDeviceCount(&deviceCount);
   if (deviceCount == 0) {
      printf("Устройства CUDA не обнаружены\n");
      return false;
   }
   for (int dev = 0; dev < deviceCount; dev++) {
      cudaDeviceProp deviceProp;
      cudaGetDeviceProperties(&deviceProp, dev);
      if (dev == 0) {
         if (deviceProp.major == 9999 && deviceProp.minor == 9999) {
            printf("Устройства CUDA не обнаружены\n");
            return false;
         } else if (deviceCount == 1) {
            printf("Найдено 1 CUDA устройство\n");
         } else {
            printf("Найдено %d CUDA устройств \n", deviceCount);
         }
      }
   }
   return true;
}
#endif
__global__ void calc(double *a, int n) {
   int idx = blockIdx.x * blockDim.x + threadIdx.x;
   double val = a[idx];
   if (idx < n){
     a[idx] = 4.0 /(1.0 + val*val);
   }
}
int main(int argc, char* argv[]) {
   setlocale(LC_ALL, "Russian");
   if(!InitCUDA()) {
      system("pause");
      return 0;
   }  
   double *a_h; // указатель на область памяти хоста
   double *a_d; // указатель на область памяти устройства
   const int numSteps = 10000; // количество разбиений
   a_h = (double *)malloc(sizeof(double)*numSteps); // выделяем память на  хосте обычным способом
   cudaMalloc((void **) &a_d, sizeof(double)*numSteps); // выделяем память на устройстве
   int blockSize = 4;
   int blocks = numSteps / blockSize + (numSteps % blockSize == 0 ? 0:1);
   double left = 0.0;
   double right = 1.0;
   double step = (right-left)/numSteps;
   int i = 0;
   for (double x = left + 0.5*step; x < right; x += step) {
      a_h[i] = x;
      i++;
   }
   cudaMemcpy(a_d, a_h, sizeof(double)*numSteps, cudaMemcpyHostToDevice);
   calc<<< blocks, blockSize >>> (a_d, numSteps);
   cudaMemcpy(a_h, a_d, sizeof(double)*numSteps, cudaMemcpyDeviceToHost); // передаем данные обратно на хост
   double sum = 0.0; 
   for(int i = 0; i < numSteps; i++) {
      sum += a_h[i];
   }
   printf("Значение интеграла %0.7f\n", sum / numSteps);
   system("pause");
   
   free(a_h);
   cudaFree(a_d);
   return EXIT_SUCCESS;
}