Использование << для возведения в степень в C или CUDA - PullRequest
3 голосов
/ 04 ноября 2011

Что означает утверждение

// create arrays of 1M elements
const int num_elements = 1<<20;

в коде ниже? Это специфично для CUDA или это можно использовать и в стандарте C?

Когда я printf ed num_elements, я получил num_elements == 1048576

Который оказывается 2 ^ 20. Так является ли оператор << сокращением для возведения в степень в C? </p>

// This example demonstrates parallel floating point vector
// addition with a simple __global__ function.

#include <stdlib.h>
#include <stdio.h>


// this kernel computes the vector sum c = a + b
// each thread performs one pair-wise addition
__global__ void vector_add(const float *a,
                           const float *b,
                           float *c,
                           const size_t n)
{
  // compute the global element index this thread should process
  unsigned int i = threadIdx.x + blockDim.x * blockIdx.x;

  // avoid accessing out of bounds elements
  if(i < n)
  {
    // sum elements
    c[i] = a[i] + b[i];
  }
}


int main(void)
{
  // create arrays of 1M elements
  const int num_elements = 1<<20;

  // compute the size of the arrays in bytes
  const int num_bytes = num_elements * sizeof(float);

  // points to host & device arrays
  float *device_array_a = 0;
  float *device_array_b = 0;
  float *device_array_c = 0;
  float *host_array_a   = 0;
  float *host_array_b   = 0;
  float *host_array_c   = 0;

  // malloc the host arrays
  host_array_a = (float*)malloc(num_bytes);
  host_array_b = (float*)malloc(num_bytes);
  host_array_c = (float*)malloc(num_bytes);

  // cudaMalloc the device arrays
  cudaMalloc((void**)&device_array_a, num_bytes);
  cudaMalloc((void**)&device_array_b, num_bytes);
  cudaMalloc((void**)&device_array_c, num_bytes);

  // if any memory allocation failed, report an error message
  if(host_array_a == 0 || host_array_b == 0 || host_array_c == 0 ||
     device_array_a == 0 || device_array_b == 0 || device_array_c == 0)
  {
    printf("couldn't allocate memory\n");
    return 1;
  }

  // initialize host_array_a & host_array_b
  for(int i = 0; i < num_elements; ++i)
  {
    // make array a a linear ramp
    host_array_a[i] = (float)i;

    // make array b random
    host_array_b[i] = (float)rand() / RAND_MAX;
  }

  // copy arrays a & b to the device memory space
  cudaMemcpy(device_array_a, host_array_a, num_bytes, cudaMemcpyHostToDevice);
  cudaMemcpy(device_array_b, host_array_b, num_bytes, cudaMemcpyHostToDevice);

  // compute c = a + b on the device
  const size_t block_size = 256;
  size_t grid_size = num_elements / block_size;

  // deal with a possible partial final block
  if(num_elements % block_size) ++grid_size;

  // launch the kernel
  vector_add<<<grid_size, block_size>>>(device_array_a, device_array_b, device_array_c, num_elements);

  // copy the result back to the host memory space
  cudaMemcpy(host_array_c, device_array_c, num_bytes, cudaMemcpyDeviceToHost);

  // print out the first 10 results
  for(int i = 0; i < 10; ++i)
  {
    printf("result %d: %1.1f + %7.1f = %7.1f\n", i, host_array_a[i], host_array_b[i], host_array_c[i]);
  }


    // deallocate memory
  free(host_array_a);
  free(host_array_b);
  free(host_array_c);

  cudaFree(device_array_a);
  cudaFree(device_array_b);
  cudaFree(device_array_c);
}

Ответы [ 3 ]

4 голосов
/ 04 ноября 2011

Нет, оператор << является оператором сдвига битов.Он берет биты числа, такие как 00101, и сдвигает их влево n мест, что приводит к умножению числа на степень два.Так что x << y это x * 2^y.Это результат того, как числа хранятся внутри компьютера на компьютерах, которые являются двоичными.

Например, число 1, когда оно хранится как 32-разрядное целое число в дополнении 2 (что это такое):

00000000000000000000000000000001

Когда вы делаете

1 << 20

Вы берете все 1 в этом двоичном представлении и перемещаете их по 20 местам:

00000000000100000000000000000000

Что составляет 2 ^ 20.Это также работает для представления величины знака, дополнения 1 и т. Д.

Другой пример, если вы возьмете представление 5:

00000000000000000000000000000101

И выполните 5 << 1, вы получите

00000000000000000000000000001010

То есть 10 или 5 * 2^1.

И наоборот, >> будет делить на степень 2, перемещая биты надна вправо n мест.

2 голосов
/ 04 ноября 2011

Это немного сдвиг. В двоичном виде возьмите 1, переместите его на 20 мест влево, что эквивалентно умножению на 2 ^ 20

edit: Да, это стандартный C и очень хороший способ прояснить пользователю, что это одна единица в 20-битной позиции, больше, чем запись int a = 1048576;

1 голос
/ 04 ноября 2011

(Стандартный) оператор левого сдвига C << работает, перемещая биты (двоичные цифры) значения с левой стороны влево на столько «пробелов», сколько указано значением с правой стороны (заполнениев нулях справа), то есть 1 << 20 приводит к двоичному числу с 1, за которым следуют 20 нулей.Поскольку двоичное является основанием 2, каждое смещение влево удваивает значение (умножается на основание), то есть оно равнозначно умножению на степени 2. </p>

Это свойство двоичных чисел можно использовать для умножения и делениянатуральные числа на степени 2 быстрее, чем с более общими математическими функциями.(Аналогично в математике начальной школы можно использовать аналогичное свойство десятичных чисел при работе со степенями 10… =)

...