Last active
September 9, 2024 14:09
-
-
Save coderodde/dbf04dcad706b6793b39578ee1b20f07 to your computer and use it in GitHub Desktop.
PPC sorting algorithm research attempt.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <chrono> | |
#include <cstring> | |
#include <iostream> | |
#include <limits.h> | |
#include <math.h> | |
#include <random> | |
#include <time.h> | |
#include <limits> | |
#include <string.h> | |
#define N (100 * 1000 * 1000) | |
#define INSERTION_SORT_THRESHOLD 64 | |
#define RADIX 256 | |
using std::cout; | |
using std::memcpy; | |
typedef unsigned long long data_t; | |
static data_t* create_data() { | |
data_t* data = new data_t[N]; | |
std::random_device dev; | |
std::mt19937 rng(13); | |
std::uniform_int_distribution<int> dist(0, 100000000); | |
for (size_t i = 0; i < N; i++) { | |
data[i] = dist(rng); | |
} | |
return data; | |
} | |
static void merge_impl(data_t* source, | |
data_t* target, | |
const size_t offset, | |
const size_t left_run_length, | |
const size_t right_run_length) | |
{ | |
data_t* left_subarray_pointer = source + offset; | |
data_t* right_subarray_pointer = left_subarray_pointer | |
+ left_run_length; | |
data_t* left_bound = right_subarray_pointer; | |
data_t* right_bound = right_subarray_pointer | |
+ right_run_length; | |
data_t* target_subarray_pointer = target + offset; | |
while (left_subarray_pointer != left_bound && | |
right_subarray_pointer != right_bound) { | |
if (*right_subarray_pointer < *left_subarray_pointer) { | |
*target_subarray_pointer = *right_subarray_pointer; | |
right_subarray_pointer++; | |
} else { | |
*target_subarray_pointer = *left_subarray_pointer; | |
left_subarray_pointer++; | |
} | |
target_subarray_pointer++; | |
} | |
memcpy(target_subarray_pointer, | |
left_subarray_pointer, | |
(left_bound - left_subarray_pointer) * sizeof(data_t)); | |
memcpy(target_subarray_pointer, | |
right_subarray_pointer, | |
(right_bound - right_subarray_pointer) * sizeof(data_t)); | |
} | |
static void insertion_sort(data_t* source, | |
const size_t range_length) { | |
for (size_t i = 1; i < range_length;) { | |
const data_t x = source[i]; | |
size_t j = i; | |
while (j > 0 && source[j - 1] > x) { | |
source[j] = source[j - 1]; | |
j--; | |
} | |
source[j] = x; | |
i++; | |
} | |
} | |
static void mergesort_impl(data_t* source, | |
data_t* target, | |
const size_t offset, | |
const size_t range_length) { | |
if (range_length < 2) { | |
return; | |
} | |
const size_t half_range_length = range_length / 2; | |
mergesort_impl(target, | |
source, | |
offset, | |
half_range_length); | |
mergesort_impl(target, | |
source, | |
offset + half_range_length, | |
range_length - half_range_length); | |
merge_impl(source, | |
target, | |
offset, | |
half_range_length, | |
range_length - half_range_length); | |
} | |
void my_mergesort(data_t* base, size_t num) | |
{ | |
auto aux = new data_t[num]; | |
memcpy(aux, base, num * sizeof(data_t)); | |
mergesort_impl( | |
aux, | |
base, | |
0, | |
num); | |
delete[] aux; | |
} | |
static unsigned long long get_millis() { | |
long ms; | |
time_t s; | |
struct timespec spec; | |
clock_gettime(CLOCK_REALTIME, &spec); | |
s = spec.tv_sec; | |
ms = round(spec.tv_nsec / 1e6); | |
if (ms > 999) { | |
s++; | |
ms -= 1000; | |
} | |
return s * 1000 + ms; | |
} | |
static size_t get_bucket_index(const data_t key, | |
const size_t byte_index) { | |
return static_cast<size_t>(key >> (byte_index * CHAR_BIT)) & | |
static_cast<size_t>(0xff); | |
} | |
static void radix_sort_impl(data_t* source, | |
data_t* target, | |
const size_t num, | |
const size_t byte_index) { | |
if (num < INSERTION_SORT_THRESHOLD) { | |
insertion_sort(source, num); | |
if ((byte_index & 1) == 0) { | |
memcpy(target, | |
source, | |
num * sizeof(data_t)); | |
} | |
return; | |
} | |
size_t bucket_size_map[RADIX]; | |
size_t start_index_map[RADIX]; | |
size_t processed_map [RADIX]; | |
memset(bucket_size_map, 0, sizeof(size_t) * RADIX); | |
memset(processed_map, 0, sizeof(size_t) * RADIX); | |
for (data_t* pd = source; pd != source + num; pd++) { | |
const data_t current_key = *pd; | |
bucket_size_map[get_bucket_index(current_key, byte_index)]++; | |
} | |
start_index_map[0] = 0; | |
for (size_t i = 1; i < RADIX; i++) { | |
start_index_map[i] = start_index_map[i - 1] | |
+ bucket_size_map[i - 1]; | |
} | |
for (data_t* pd = source; pd != source + num; pd++) { | |
const data_t current_key = *pd; | |
const size_t bucket_index = get_bucket_index(current_key, | |
byte_index); | |
*(target + (start_index_map[bucket_index] | |
+ processed_map[bucket_index]++)) = current_key; | |
} | |
if (byte_index) { | |
for (size_t i = 0; i != RADIX; i++) { | |
if (bucket_size_map[i]) { | |
radix_sort_impl( | |
target, | |
source, | |
bucket_size_map[i], | |
byte_index - 1); | |
} | |
} | |
} | |
} | |
void radix_sort(data_t* source, size_t num) { | |
if (num < 2) { | |
return; | |
} | |
auto aux = new data_t[num]; | |
memcpy(aux, source, num * sizeof(data_t)); | |
radix_sort_impl(aux, | |
source, | |
num, | |
3); | |
delete[] aux; | |
} | |
int main() { | |
data_t* data = create_data(); | |
data_t* copy = new data_t[N]; | |
data_t* cpy2 = new data_t[N]; | |
memcpy(copy, data, N * sizeof(data_t)); | |
memcpy(cpy2, data, N * sizeof(data_t)); | |
auto st = get_millis(); | |
std::sort(copy, copy + N); | |
auto et = get_millis(); | |
std::cout << "std::sort in " << et - st << " milliseconds.\n"; | |
st = get_millis(); | |
my_mergesort(data, N); | |
et = get_millis(); | |
cout << "my_mergesort in " << et - st << " milliseconds.\n"; | |
st = get_millis(); | |
radix_sort(cpy2, N); | |
et = get_millis(); | |
cout << "radix_sort in " << et - st << " milliseconds.\n"; | |
cout << "Algorithms agree: " | |
<< std::boolalpha | |
<< (std::equal(copy, copy + N, data) && | |
std::equal(cpy2, cpy2 + N, data)) | |
<< ".\n"; | |
delete[] data; | |
delete[] copy; | |
delete[] cpy2; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment