2012-01-11 3 views
11

CUDA 디바이스의 경우 ε (두 숫자 사이의 최소 간격), min (최소 크기) 및 max (최대 크기) 값을 찾고 있습니다.CUDA의 엡실론, 최소 및 최대 상수를 찾는 방법은 무엇입니까?

I.EE gcc 컴파일러에서 <float.h>에 정의 된 FLT_EPSILON (DBL_EPSILON), FLT_MIN (DBL_MIN) 및 FLT_MAX (DBL_MAX)에 해당하는 I.E입니다.

일부 CUDA 포함 파일에 상수가 있습니까? 설명서에 대한 설명이 있습니까? 커널을 작성하여 계산하는 방법은 없습니까?

미리 감사드립니다.

답변

13

네, 원한다면 확실하게 계산할 수 있습니다. A coupleexamples 기계 엡실론을 계산하는 방법은 위키피디아 페이지의 C에 나와 있습니다. 마찬가지로 당신은 아래/오버 플로우 될 때까지 2로 나누거나 곱함으로써 최소/최대를 찾을 수 있습니다. ("실제"최소/최대 값을 찾으려면 마지막 유효한 값과 다음 요소 2 사이를 검색해야하지만 이것은 좋은 출발점을 제공합니다).

컴퓨팅 성능이 2.0 이상인 장치를 사용하는 경우 수학은 대부분 약간의 편차가있는 IEEE 754이지만 (예 : 모든 반올림 모드가 지원되지는 않음) 이러한 편차는 기본 이 같은 수치 적 상수; 그래서 5.96e-08의 싱글과 1.11e-16의 두 배에 대한 표준 emach를 얻을 수 있습니다; FLT_MIN/MAX는 1.175494351e-38/3.402823466e + 38이고, DBL_MIN/MAX는 2.2250738585072014e-308/1.7976931348623158e + 308입니다.

컴퓨팅 성능이 1.3 인 컴퓨터에서 비정규 숫자는 단 정밀도로 지원되지 않으므로 FLT_MIN이 CPU보다 상당히 클 수 있습니다.

최소/최대에 대한 신속하고 더러운 계산과 계산 능력 2.0 컴퓨터의 빠른 테스트 :

#include <stdio.h> 
#include <stdlib.h> 
#include <getopt.h> 
#include <cuda.h> 
#include <sys/time.h> 
#include <math.h> 
#include <assert.h> 
#include <float.h> 

#define CHK_CUDA(e) {if (e != cudaSuccess) {fprintf(stderr,"Error: %s\n", cudaGetErrorString(e)); exit(-1);}} 

/* from wikipedia page, for machine epsilon calculation */ 
/* assumes mantissa in final bits */ 
__device__ double machine_eps_dbl() { 
    typedef union { 
     long long i64; 
     double d64; 
    } dbl_64; 

    dbl_64 s; 

    s.d64 = 1.; 
    s.i64++; 
    return (s.d64 - 1.); 
} 

__device__ float machine_eps_flt() { 
    typedef union { 
     int i32; 
     float f32; 
    } flt_32; 

    flt_32 s; 

    s.f32 = 1.; 
    s.i32++; 
    return (s.f32 - 1.); 
} 

#define EPS 0 
#define MIN 1 
#define MAX 2 

__global__ void calc_consts(float *fvals, double *dvals) { 

    int i = threadIdx.x + blockIdx.x*blockDim.x; 
    if (i==0) { 
     fvals[EPS] = machine_eps_flt(); 
     dvals[EPS]= machine_eps_dbl(); 

     float xf, oldxf; 
     double xd, oldxd; 

     xf = 2.; oldxf = 1.; 
     xd = 2.; oldxd = 1.; 

     /* double until overflow */ 
     /* Note that real fmax is somewhere between xf and oldxf */ 
     while (!isinf(xf)) { 
      oldxf *= 2.; 
      xf *= 2.; 
     } 

     while (!isinf(xd)) { 
      oldxd *= 2.; 
      xd *= 2.; 
     } 

     dvals[MAX] = oldxd; 
     fvals[MAX] = oldxf; 

     /* half until overflow */ 
     /* Note that real fmin is somewhere between xf and oldxf */ 
     xf = 1.; oldxf = 2.; 
     xd = 1.; oldxd = 2.; 

     while (xf != 0.) { 
      oldxf /= 2.; 
      xf /= 2.; 
     } 

     while (xd != 0.) { 
      oldxd /= 2.; 
      xd /= 2.; 
     } 

     dvals[MIN] = oldxd; 
     fvals[MIN] = oldxf; 

    } 
    return; 
} 

int main(int argc, char **argv) { 
    float fvals[3]; 
    double dvals[3]; 
    float *fvals_d; 
    double *dvals_d; 

    CHK_CUDA(cudaMalloc(&fvals_d, 3*sizeof(float))); 
    CHK_CUDA(cudaMalloc(&dvals_d, 3*sizeof(double))); 

    calc_consts<<<1,32>>>(fvals_d, dvals_d); 

    CHK_CUDA(cudaMemcpy(fvals, fvals_d, 3*sizeof(float), cudaMemcpyDeviceToHost)); 
    CHK_CUDA(cudaMemcpy(dvals, dvals_d, 3*sizeof(double), cudaMemcpyDeviceToHost)); 

    CHK_CUDA(cudaFree(fvals_d)); 
    CHK_CUDA(cudaFree(dvals_d)); 

    printf("Single machine epsilon:\n"); 
    printf("CUDA = %g, CPU = %g\n", fvals[EPS], FLT_EPSILON); 
    printf("Single min value (CUDA - approx):\n"); 
    printf("CUDA = %g, CPU = %g\n", fvals[MIN], FLT_MIN); 
    printf("Single max value (CUDA - approx):\n"); 
    printf("CUDA = %g, CPU = %g\n", fvals[MAX], FLT_MAX); 

    printf("\nDouble machine epsilon:\n"); 
    printf("CUDA = %lg, CPU = %lg\n", dvals[EPS], DBL_EPSILON); 
    printf("Double min value (CUDA - approx):\n"); 
    printf("CUDA = %lg, CPU = %lg\n", dvals[MIN], DBL_MIN); 
    printf("Double max value (CUDA - approx):\n"); 
    printf("CUDA = %lg, CPU = %lg\n", dvals[MAX], DBL_MAX); 

    return 0; 
} 

컴파일/실행이 답이 최소 값을 제외한 CPU 버전 (일관성이 있음을 보여줍니다; FLT_MIN이 CPU에서 비정상으로 표시되는 것이 아니라 최소 정상 값을 제공합니까?)

$ nvcc -o foo foo.cu -arch=sm_20 
$ ./foo 
Single machine epsilon: 
CUDA = 1.19209e-07, CPU = 1.19209e-07 
Single min value (CUDA - approx): 
CUDA = 1.4013e-45, CPU = 1.17549e-38 
Single max value (CUDA - approx): 
CUDA = 1.70141e+38, CPU = 3.40282e+38 

Double machine epsilon: 
CUDA = 2.22045e-16, CPU = 2.22045e-16 
Double min value (CUDA - approx): 
CUDA = 4.94066e-324, CPU = 2.22507e-308 
Double max value (CUDA - approx): 
CUDA = 8.98847e+307, CPU = 1.79769e+308 
+0

위대한 공헌입니다. 감사! – cibercitizen1

관련 문제