네, 원한다면 확실하게 계산할 수 있습니다. 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
위대한 공헌입니다. 감사! – cibercitizen1