Radix Sort for Floats

China☆狼群 提交于 2020-12-15 03:52:25

问题


I want to sort floats in C with radix. Below is the code I have. However, my output is not correct. For example, if I run the code with 3.1, -5, and 1 my sorted values are printed as 3.000000, -5.000000, and 1.000000.

I know to cast correctly from a float to an int back to a float, I need to apply the following logic but I am not sure how to integrate this into rfloat() because I tried and am getting many errors.

How would I be able to correctly apply a bitwise radix sort to floats?

float x = 3.1, *y; 
    int *a; 
    
    a = (int *)&x; 
    y = (float *)a; 

    printf("%f",*y); 
#include <stdio.h>
#include <stdlib.h>

void rs(unsigned int *a, int c) {
    int i;
    int m = a[0];
    int bt = 0;
    unsigned int *b = malloc(0 * sizeof(int));

    for (i = 0; i < c; i++) {
        if (a[i] > m)
            m = a[i]; 
    }

    while((m>>bt) > 0){ 
        int buck[2] = { 0 };

        for (i = 0; i < c; i++) { 
            buck[(a[i]>>bt)&1]++;
        }

        for (i = 1; i < 2; i++) { 
            buck[i] += buck[i-1];
        }

        for (i = c-1; i >= 0; i--) { 
            b[--buck[(a[i]>>bt)&1]] = a[i]; 
        }

        for (i = 0; i < c; i++) {
            a[i] = b[i]; 
        }
        bt++;
    }
    free(b); 
}

void rfloat(float *arr, int c) {
    int d[c]; 
    int i; 
    
    for(i = 0; i < c; i++){
        d[i] = (int)arr[i];
    }
    
    rs(d, c);
    
    for(i = 0; i < c; i++){
        arr[i] = (float)d[i]; 
    }
    
}

int main() {
    int size;  
    int i; 
    float* arr = malloc(0* sizeof(float)); 
    
    printf("Size: "); 
    scanf("%d", &size); 
    
    for (int i = 0; i < size; i++){
        printf("Values: ");
        scanf("%f", &arr[i]); 
    }
    
    rfloat(arr, size); 
    
    printf("Sorted: ");
    for (i = 0; i < size; i++){
        printf("%f ", arr[i]);
    }
    free(arr); 
}

回答1:


Positive floats sort in the same order as they would if you would sort their bit pattern as unsigned integers. Negative floats do not, they sort in the reverse order than if you would sort their bit pattern. Furthermore, negative floats sort after the positive ones if you would sort on their bit pattern, because their top bit is set.

So what do we do? We do a transform. We flip all the other bits if the top bit is set (making negative numbers sort correctly between themselves), and we always flip the top bit (to make negative and positive numbers sort correctly). Then after sorting we reverse the transformation.

No rounding needed!

void rfloat(float* arr, size_t size) {
    assert(sizeof(unsigned) == sizeof(float) && sizeof(float) == 4);
    unsigned* d = malloc(size * sizeof(unsigned));
    
    for (size_t i = 0; i < size; i++) {
        // Interpret float as 32-bit unsigned.
        d[i] = *(unsigned*) &(arr[i]);

        // Flip all except top if top bit is set.
        d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);

        // Flip top bit.
        d[i] ^= (1u << 31);
    }
    
    rs(d, size);
    
    // Inverse transform.
    for (size_t i = 0; i < size; i++) {
        d[i] ^= (1u << 31);
        d[i] ^= (((unsigned) (((int) d[i]) >> 31)) >> 1);
        arr[i] = *(float*) &(d[i]);
    }
    
    free(d);
}

Note that your code still doesn't work after this. Your radix sort routine has issues. But that is for another question, if you can't figure it out yourself.



来源:https://stackoverflow.com/questions/64744678/radix-sort-for-floats

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!