2016-10-17 3 views
2

Я хочу написать код, действительный как для float, так и для двойной точности. я делаю что-то вроде этого:float (0.0) vs 0.0f в CUDA

typedef real float; 
//typedef real double; 

__global__ void foo(real a, real *b){ 
    b[0] = real(0.5)*a; 
} 

int main(){ 
    real a = 1.0f; 
    real *b; 
    cudaMalloc(&f, sizeof(real)); 
    foo<<<1,1>>>(a,b); 
    return 0; 
} 

Это заставило меня думать, я не хочу потерять точность в постоянной, как 0.5f при выполнении двойной точности, но я не хочу, чтобы способствовать 0,5 удвоить делая одиночная точность!

Итак, я использовал оператор real(), как в примере. В режиме одиночной точности, если я разобрал функцию «foo» с помощью real (0.5), я понял, что нет поощрения удвоения, в отличие от использования всего 0,5, когда продвижение происходит.

Вы можете проверить с помощью:

$nvcc test.cu -arch=sm_52 -lineinfo --source-in-ptx -g -G -O0 ; cuobjdump -sass a.out | grep "foo" -A 35 

Я вижу

/*0078*/     FMUL R0, R0, 0.5;    /* 0x3868004000070000 */ 

При использовании реальной (0.5) или 0.5f И:

/*0078*/     F2F.F64.F32 R4, R0;   /* 0x5ca8000000070b04 */ 
/*0088*/     DMUL R4, R4, 0.5;    /* 0x3880004000070404 */ 
/*0090*/     F2F.F32.F64 R0, R4;   /* 0x5ca8000000470e00 */ 

При написании всего 0,5.

Это может показаться чересчур очевидным. Но поскольку я не знаю, что такое «реальный (0,5)», я не знаю, является ли это только компилятором, играющим в этом конкретном случае. Разборный код кажется идентичным как в реальных (0,5), так и в 0,5f!

Так что вопрос остается:

Что реально (0,5) (AKA поплавок (0,5)) на самом деле?

Есть ли разница между поплавком (0,5) и 0,5f? (OR double (0,5) и 0,5)

Это также относится к C/C++, я полагаю.

ответ

4

Что такое real (0.5) (AKA float (0.5)), что именно происходит?

real(0.5)function-style cast, и в этом случае снижается до static_cast

real(0.5) 
static_cast<real>(0.5) //exactly the same thing 

Это означает, что a умножается на real переменной (в данном случае float), что означает, что нет необходимости выполнять продвижение на double, а будет иметь место для умножения double * float.

Есть ли разница между поплавком (0,5) и 0,5f? (OR double (0,5) и 0,5)

Можно утверждать, что инициализация float с 0.5 может произойти во время выполнения, но это нереально для любого современного компилятора. Это должно быть no-op, это уже для OP.

Кроме этого, с помощью float(0.5f) это не делает никакой разницы от только с помощью 0.5f, и то же самое для double(0.5) и 0.5.

+0

От ссылки: 1) Если есть неявная последовательность преобразований из выражения в new_type или если разрешение перегрузки для прямой инициализации объекта или ссылки типа new_type из выражения найдет хотя бы одну жизнеспособную функцию, тогда static_cast (выражение) возвращает мнимую переменную Temp, инициализированную так, как если бы она была создана с помощью new_type Temp (expression) ;, которая может включать неявные преобразования, вызов конструктора new_type или вызов пользовательского оператора преобразования. – Apo

+0

Разве это не означает, что static_cast (0.5) вызывает real (0.5)? Кроме того, [static_cast] может включать неявные преобразования, вызов конструктора new_type или вызов пользовательского оператора преобразования. ". Итак, это что-то делает во время выполнения, а не в 0,5f? – Apo

+0

Если у вас были более сложные типы (с конструктором), то это могло бы быть. В вашем случае, однако, вы можете легко увидеть, что ничего подобного не происходит. Вы инициализируете 'real' со значением' 0,5'. Компилятор знает, как это сделать во время компиляции, а затем он не вынужден генерировать продвижение в два раза для выполнения умножения. – krzaq

Смежные вопросы