2012-01-11 14 views
11

मैं ईपीएसलॉन (दो संख्याओं के बीच सबसे छोटा कदम), न्यूनतम (न्यूनतम परिमाण) और सीयूडीए उपकरणों के लिए अधिकतम (सबसे बड़ा परिमाण) के मूल्यों की तलाश में हूं।सीयूडीए के लिए ईपीएसलॉन, न्यूनतम और अधिकतम स्थिरांक कैसे खोजें?

आईईई जीसीसी कंपाइलर्स में <float.h> में परिभाषित FLT_EPSILON (DBL_EPSILON), FLT_MIN (DBL_MIN) और FLT_MAX (DBL_MAX) के समकक्ष।

क्या कुछ सीयूडीए में स्थिरांक फ़ाइल शामिल हैं? कोई भी मैनुअल उन्हें समझाता है? उन्हें गणना करने के लिए कर्नेल लिखने का कोई तरीका?

अग्रिम धन्यवाद।

उत्तर

13

हां, यदि आप चाहें तो निश्चित रूप से इनकी गणना कर सकते हैं। मशीन epsilon की गणना कैसे करें के लिए coupleexamples विकिपीडिया पृष्ठ पर सी में दिया गया है; इसी तरह आप नीचे/ओवरफ्लो तक दो तक विभाजित/गुणा करके न्यूनतम/अधिकतम पा सकते हैं। (फिर आपको "सत्य" न्यूनतम/अधिकतम मान खोजने के लिए अंतिम वैध मान और दो के अगले कारक के बीच खोज करना चाहिए, लेकिन यह आपको एक अच्छा प्रारंभिक बिंदु देता है)।

यदि आपके पास 2.0 या उससे अधिक की गणना क्षमता वाला डिवाइस है, तो गणित ज्यादातर आईईईई 754 है, जिसमें कुछ छोटे विचलन होते हैं (उदाहरण के लिए, सभी राउंडिंग मोड समर्थित नहीं हैं) लेकिन वे विचलन मौलिक को प्रभावित करने के लिए पर्याप्त नहीं हैं इन तरह संख्यात्मक स्थिरांक; तो आपको 5.9 6e-08 के एकल और 1.11e-16 के डबल के लिए मानक एमाच मिलेगा; FLT_MIN/MAX का 1.175494351e-38/3.402823466e + 38, और डीबीएल_MIN/अधिकतम 2.2250738585072014-308/1.7976931348623158e + 308 का MAX।

गणना क्षमता 1.3 मशीनों पर, denormalized संख्या एकल परिशुद्धता में समर्थित नहीं थे, इसलिए आपका 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; 
} 

संकलन/चल रहा है पता चलता है कि उत्तर सीपीयू संस्करण (न्यूनतम मूल्यों को छोड़कर के साथ संगत कर रहे हैं; क्या FLT_MIN सीपीयू पर उल्लिखित के बजाय न्यूनतम सामान्य मूल्य दे रहा है?)

$ 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

संबंधित मुद्दे