IEEE 754浮点数的机器表示如下:
符号 | 指数 | 尾数 |
比较大小时先比较符号位,再比较指数,最后比较尾数。
反码整数的机器表示如下:
符号 | 尾数 |
比较大小时先比较符号位,再比较尾数。
可以看出,要比较两个浮点数的大小,等价于比较相同机器表示的反码整数的大小。因此,可以把浮点数当成反码整数来进行计数排序或基数排序。需要注意的是,计算机的整数是用补码表示的,还需要一些额外的处理。
代码如下:
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "fsort.h"
typedef unsigned long long uint64;
typedef long long int64;
typedef unsigned short uint16;
static void sort_word(double *array, size_t n, int word, double *buf)
{
int cnt[65536];
memset(cnt, 0, sizeof(cnt));
for (size_t i = 0; i < n; i++)
{
uint16 tmp = ((uint16 *)(array+i))[word];
cnt[tmp]++;
}
for (size_t i = 1; i < 65536; i++)
{
cnt[i] += cnt[i-1];
}
memcpy(buf, array, sizeof(double)*n);
for (int i = (int)n-1; i >= 0; i--)
{
uint16 tmp = ((uint16 *)(buf+i))[word];
array[cnt[tmp]-1] = buf[i];
cnt[tmp]--;
}
}
void fsort(double *array, size_t n)
{
double *buf = (double *)malloc(sizeof(double)*n);
sort_word(array, n, 0, buf);
sort_word(array, n, 1, buf);
sort_word(array, n, 2, buf);
sort_word(array, n, 3, buf);
memcpy(buf, array, sizeof(double)*n);
for (int i = (int)n-1; i >= 0; i--)
{
if (((int64 *)buf)[i] < 0)
{
array[n-i-1] = buf[i];
}
else
{
memcpy(array+n-i-1, buf, sizeof(double)*(i+1));
break;
}
}
free(buf);
}