【发布时间】:2015-11-18 05:38:15
【问题描述】:
我正在使用 .RAW 文件中的 RGB 数据对 10+ 百万个 uint64_ts 进行排序,并且我 79% 的 C 程序时间都花在了 qsort 上。我正在为这种特定的数据类型寻找一种更快的排序方式。
作为 RAW 图形数据,这些数字非常随机,大约 80% 是唯一的。预计不会对已排序的数据进行部分排序或运行。 uint64_t 中的 4 个 uint16_ts 是 R、G、B 和零(可能是一个小计数
我有我能想到的最简单的比较函数,使用unsigned long longs(你不能只减去它们):
qsort(hpidx, num_pix, sizeof(uint64_t), comp_uint64);
...
int comp_uint64(const void *a, const void *b) {
if(*((uint64_t *)a) > *((uint64_t *)b)) return(+1);
if(*((uint64_t *)a) < *((uint64_t *)b)) return(-1);
return(0);
} // End Comp_uint64().
StackExchange 上有一个非常有趣的“Programming Puzzles & Code Golf”,但他们使用了floats。然后是QSort、RecQuick、heap、stooge、tree、radix...
swenson/sort 看起来很有趣,但对我的数据类型uint64_t 没有(明显的)支持。 “快速排序”时间是最好的。一些消息来源说系统qsort 可以是任何东西,不一定是“快速排序”。
C++ 排序绕过了 void 指针的通用转换,并实现了相对于 C 的性能的巨大改进。必须有一种优化的方法来通过 64 位处理器以扭曲速度猛击 U8。
系统/编译器信息:
我目前正在将 GCC 与 Strawberry Perl 一起使用
gcc version 4.9.2 (x86_64-posix-sjlj, built by strawberryperl.com
Intel 2700K Sandy Bridge CPU, 32GB DDR3
windows 7/64 pro
gcc -D__USE_MINGW_ANSI_STDIO -O4 -ffast-math -m64 -Ofast -march=corei7-avx -mtune=corei7 -Ic:/bin/xxHash-master -Lc:/bin/xxHash-master c:/bin/stddev.c -o c:/bin/stddev.g6.exe
第一次尝试更好的qsort,QSORT()!
尝试使用 Michael Tokarev 的内联 qsort。
“准备使用”?来自qsort.h 文档
-----------------------------
* Several ready-to-use examples:
*
* Sorting array of integers:
* void int_qsort(int *arr, unsigned n) {
* #define int_lt(a,b) ((*a)<(*b))
* QSORT(int, arr, n, int_lt);
--------------------------------
Change from type "int" to "uint64_t"
compile error on TYPE???
c:/bin/bpbfct.c:586:8: error: expected expression before 'uint64_t'
QSORT(uint64_t, hpidx, num_pix, islt);
我找不到一个真正的、编译的、工作的示例程序,只是带有“一般概念”的 cmets
#define QSORT_TYPE uint64_t
#define islt(a,b) ((*a)<(*b))
uint64_t *QSORT_BASE;
int QSORT_NELT;
hpidx=(uint64_t *) calloc(num_pix+2, sizeof(uint64_t)); // Hash . PIDX
QSORT_BASE = hpidx;
QSORT_NELT = num_pix; // QSORT_LT is function QSORT_LT()
QSORT(uint64_t, hpidx, num_pix, islt);
//QSORT(uint64_t *, hpidx, num_pix, QSORT_LT); // QSORT_LT mal-defined?
//qsort(hpidx, num_pix, sizeof(uint64_t), comp_uint64); // << WORKS
“即用型”示例使用 int、char * 和 struct elt 类型。 uint64_t 不是类型吗?试试long long
QSORT(long long, hpidx, num_pix, islt);
c:/bin/bpbfct.c:586:8: error: expected expression before 'long'
QSORT(long long, hpidx, num_pix, islt);
下一次尝试:RADIXSORT:
结果:RADIX_SORT 是 RADICAL!
I:\br3\pf.249465>grep "Event" bb12.log | grep -i Sort
<< 1.40 sec average
4) Time=1.411 sec = 49.61%, Event RADIX_SORT , hits=1
4) Time=1.396 sec = 49.13%, Event RADIX_SORT , hits=1
4) Time=1.392 sec = 49.15%, Event RADIX_SORT , hits=1
16) Time=1.414 sec = 49.12%, Event RADIX_SORT , hits=1
I:\br3\pf.249465>grep "Event" bb11.log | grep -i Sort
<< 5.525 sec average = 3.95 time slower
4) Time=5.538 sec = 86.34%, Event QSort , hits=1
4) Time=5.519 sec = 79.41%, Event QSort , hits=1
4) Time=5.519 sec = 79.02%, Event QSort , hits=1
4) Time=5.563 sec = 79.49%, Event QSort , hits=1
4) Time=5.684 sec = 79.83%, Event QSort , hits=1
4) Time=5.509 sec = 79.30%, Event QSort , hits=1
比开箱即用的 qsort 快 3.94 倍!
而且,更重要的是,有实际的、有效的代码,而不仅仅是某些大师提供的 80% 的代码,他们假设你知道他们所知道的一切,并且可以填写其他 20%。
绝妙的解决方案!谢谢路易斯·里奇!
【问题讨论】:
-
如果您的数据像您描述的那样随机,那么我会说 qsort 将是性能最稳定的实现之一。
-
你能简单地使用 C++ 排序吗?您可以将其放入带有
extern "C"的单独 .cpp 文件中,以便您的其余代码可以保留在 C 中。 -
@user3386109 您正在考虑 RGBA。我认为 Z 指的是深度信息。无论哪种方式,它都与问题无关。
-
RGBZ 用于 RGB_ZERO_ 我将 3 个 UINT16 粉碎成 UINT64,因为 UINT32 太小,而且 K 和 R 都没有 16 位量子的数码相机,没有 UINT48。多么严重的疏忽!在加载 RGB 之前,我清除了所有 8 个字节。我还在最后 2 个字节中添加了计数和其他内容。
标签: c algorithm performance sorting