C++ cuda中的双音排序对某些值排序错误

C++ cuda中的双音排序对某些值排序错误,c++,arrays,sorting,cuda,C++,Arrays,Sorting,Cuda,我正在为一个更大的项目在CUDA上做一个排序算法,我决定实现一个双音排序。我将要排序的元素数始终是2的幂,实际上是512。我需要一个具有最终位置的数组,因为此方法将用于排序表示另一个解决方案的质量矩阵的数组 fitness是我要排序的数组,numElements是元素的数量,orden最初是一个空数组,包含numElements位置,这些位置将在一开始以这种方式填充:orden[i]=i。实际上orden与这个问题无关,但我保留了它 我的问题是,一些值没有正确排序,直到现在我还无法找出我有什么问

我正在为一个更大的项目在CUDA上做一个排序算法,我决定实现一个双音排序。我将要排序的元素数始终是2的幂,实际上是512。我需要一个具有最终位置的数组,因为此方法将用于排序表示另一个解决方案的质量矩阵的数组

fitness是我要排序的数组,numElements是元素的数量,orden最初是一个空数组,包含numElements位置,这些位置将在一开始以这种方式填充:
orden[i]=i
。实际上orden与这个问题无关,但我保留了它

我的问题是,一些值没有正确排序,直到现在我还无法找出我有什么问题

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <ctime>
#include <cuda.h>
#include <curand.h>
#include <curand_kernel.h>
#include <device_functions.h>
#include "float.h"


__global__ void sorting(int * orden, float * fitness, int numElements);

// Populating array with random values for testing purposes
__global__ void populate( curandState * state, float * fitness{

    curandState localState = state[threadIdx.x];
    int a = curand(&localState) % 500;
    fitness[threadIdx.x] = a;
}

//Curand setup for the populate method 
__global__ void setup_cuRand(curandState * state, unsigned long seed)
{
    int id = threadIdx.x;
    curand_init(seed, id, 0, &state[id]);
}

int main()
{
    float * arrayx;
    int numelements = 512;
    int * orden;
    float arrayCPU[512] = { 0 };
    curandState * state;

    cudaDeviceReset();
    cudaSetDevice(0);
    cudaMalloc(&state, numelements * sizeof(curandState));
    cudaMalloc((void **)&arrayx, numelements*sizeof(float));
    cudaMalloc((void **)&orden, numelements*sizeof(int));






    setup_cuRand << <1, numelements >> >(state, unsigned(time(NULL)));

    populate << <1, numelements >> > (state, arrayx);
    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    for (int i = 0; i < numelements; i++)
        printf("fitness[%i] = %f\n", i, arrayCPU[i]);

    sorting << <1, numelements >> >(orden, arrayx, numelements);
    printf("\n\n");

    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    for (int i = 0; i < numelements; i++)
        printf("fitness[%i] = %f\n", i, arrayCPU[i]);



    cudaDeviceReset();


    return 0;
}
__device__ bool isValid(float n){
    return !(isnan(n) || isinf(n) || n != n || n <= FLT_MIN || n >= FLT_MAX);

}

__global__ void sorting(int * orden, float * fitness, int numElements){
    int i = 0;
    int j = 0;
    float f = 0.0;
    int aux = 0;

    //initial orden registered (1, 2, 3...)
    orden[threadIdx.x] = threadIdx.x;
    //Logarithm on base 2 of numElements
    for (i = 2; i <= numElements; i = i * 2){
        // descending from i reducing to half each iteration
        for (j = i; j >= 2; j = j / 2){

            if (threadIdx.x % j  < j / 2){
                __syncthreads();
                // ascending or descending consideration using (threadIdx.x % (i*2) < i) 
                if ((threadIdx.x % (i * 2) < i) && (fitness[threadIdx.x] >  fitness[threadIdx.x + j / 2] || !isValid(fitness[threadIdx.x])) ||
                    ((threadIdx.x % (i * 2) >= i) && (fitness[threadIdx.x] <= fitness[threadIdx.x + j / 2] || !isValid(fitness[threadIdx.x + j / 2])))){

                    aux = orden[threadIdx.x];
                    orden[threadIdx.x] = orden[threadIdx.x + j / 2];
                    orden[threadIdx.x + j / 2] = aux;
                    //Se reubican los fitness
                    f = fitness[threadIdx.x];
                    fitness[threadIdx.x] = fitness[threadIdx.x + j / 2];
                    fitness[threadIdx.x + j / 2] = f;
                }
            }
        }
    }
}
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括“float.h”
__全局无效排序(int*orden、float*fitness、int numElements);
//为测试目的用随机值填充数组
__全局无效填充(curandState*状态,浮点*适合度{
curandState localState=state[threadIdx.x];
int a=curand(&localState)%500;
适合度[threadIdx.x]=a;
}
//用于填充方法的Curand设置
__全局\uuuuu无效设置\u cuRand(curandState*状态,无符号长种子)
{
int id=threadIdx.x;
curand_init(seed、id、0和state[id]);
}
int main()
{
浮动*阵列;
整数=512;
int*orden;
浮点数组CPU[512]={0};
库兰州*州;
cudaDeviceReset();
cudaSetDevice(0);
cudaMalloc(和州,numelements*sizeof(curandState));
Cudamaloc((无效**)和arrayx,numelements*sizeof(浮动));
Cudamaloc((void**)和orden,numelements*sizeof(int));
设置和>(状态,未签名(时间(空));
填充>(状态,arrayx);
cudaMemcpy(&arrayCPU、arrayx、numelements*sizeof(float)、cudamemcpydevicetoost);
对于(int i=0;i(orden、arrayx、Numements);
printf(“\n\n”);
cudaMemcpy(&arrayCPU、arrayx、numelements*sizeof(float)、cudamemcpydevicetoost);
对于(int i=0;ifitness[threadIdx.x+j/2]| |!有效(fitness[threadIdx.x]))||

((threadIdx.x%(i*2)>=i)和(fitness[threadIdx.x]以下是我发现的问题:

  • 在您发布的代码中,这不会编译:

    __global__ void populate( curandState * state, float * fitness{
                                                                  ^
                                                       missing close parenthesis
    
    我在那里加了一个右括号

  • 无需在这些
    cudaMemcpy
    语句中获取数组地址:

    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    ....
    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    
    数组名已经是数组的地址,所以我删除了符号。如果使用动态分配的数组,这种用法将被破坏

  • 您在此处使用的
    \uu syncthreads()
    已中断:

    for (j = i; j >= 2; j = j / 2){
    
        if (threadIdx.x % j  < j / 2){
            __syncthreads();
    

  • 通过以上更改,在大多数情况下,您的代码对我来说似乎运行正常。如果您打算为0(或任何负值),您在有效性检查中使用的
    FLT\u MIN
    也有问题要正确排序。一般来说,
    FLT_MIN
    是一个数字,也就是说。如果您认为这是一个大的负数,它不是。因此,零可能是随机数生成器的一个输出,它将无法正确排序。我将把这个问题留给您来解决,它应该是简单的,但它将是d请说明您最终想要实现的目标。(如果您只想对正非零浮点值进行排序,测试可能还可以,但在这种情况下,您的随机数生成器可以返回0。)

    以下是我发现的问题:

  • 在您发布的代码中,这不会编译:

    __global__ void populate( curandState * state, float * fitness{
                                                                  ^
                                                       missing close parenthesis
    
    我在那里加了一个右括号

  • 无需在这些
    cudaMemcpy
    语句中获取数组地址:

    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    ....
    cudaMemcpy(&arrayCPU, arrayx, numelements * sizeof(float), cudaMemcpyDeviceToHost);
    
    数组名已经是数组的地址,所以我删除了符号。如果使用动态分配的数组,这种用法将被破坏

  • 您在此处使用的
    \uu syncthreads()
    已中断:

    for (j = i; j >= 2; j = j / 2){
    
        if (threadIdx.x % j  < j / 2){
            __syncthreads();
    

  • 通过以上更改,在大多数情况下,您的代码对我来说似乎运行正常。如果您打算为0(或任何负值),您在有效性检查中使用的
    FLT\u MIN
    也有问题要正确排序。一般来说,
    FLT_MIN
    是一个数字,也就是说。如果您认为这是一个大的负数,它不是。因此,零可能是随机数生成器的一个输出,它将无法正确排序。我将把这个问题留给您来解决,它应该是简单的,但它将是depend取决于您最终想要实现的目标。(如果您只想对正非零浮点值进行排序,测试可能还可以,但在这种情况下,您的随机数生成器可以返回0。)

    您发布的代码将无法编译。我建议您通过更改此处的循环结束条件来检查排序的每个步骤是否按预期工作(i=2;i)您发布的代码将无法编译。我建议您通过更改(i=2;