Make bitonic work for non powers of 2 (#24)

This commit is contained in:
Chris Cromer 2018-11-17 15:12:24 -03:00 committed by Gitea
parent ca5946b92a
commit 03c1305f57
2 changed files with 145 additions and 33 deletions

View File

@ -15,6 +15,39 @@
#include "swap.h" #include "swap.h"
/**
* Verificar si x es de 2^n
* @param x El valor a verificar
* @return Retorna 1 si es de 2^n ó 0 al contrario;
*/
int power_of_two(int n) {
if (n == 0) {
return 0;
}
while (n != 1) {
if (n % 2 != 0) {
return 0;
}
n = n / 2;
}
return 1;
}
/**
* Buscar un valor que es de potencia de 2 pero menor que n
* @param n El valor de n
* @return Un potencia de 2 que es menor que n
*/
int greatest_power_of_two_less_than(int n) {
int k = 1;
while (k > 0 && k < n) {
k = (int) ((unsigned int) k << 1);
}
k = (int) ((unsigned int) k >> 1);
return (int) k;
}
/** /**
* Comparar y intercambiar los valores para darle orden * Comparar y intercambiar los valores para darle orden
* @param i El primer indice a comparar * @param i El primer indice a comparar
@ -31,16 +64,16 @@ void compare(int i, int j, int dir, int *array) { //
/** /**
* Unir la secuencia * Unir la secuencia
* @param low El parte inferior * @param low El parte inferior
* @param c El parte superior * @param c El parte superior n
* @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
* @param array El array a ordenar * @param array El array a ordenar
*/ */
void bitonicmerge(int low, int c, int dir, int *array) { void bitonicmerge(int low, int n, int dir, int *array) {
int i; int i;
int k; int k;
if (c > 1){ if (n > 1) {
k = c / 2; k = n / 2;
for (i = low; i < low + k; i++){ for (i = low; i < low + k; i++){
compare(i, i + k, dir, array); compare(i, i + k, dir, array);
} }
@ -50,20 +83,59 @@ void bitonicmerge(int low, int c, int dir, int *array) {
} }
/** /**
* Generar la secuencia bitonica en forma de piramide * Unir la secuencia cuando n no es de potencia 2
* @param low El parte inferior * @param low El parte inferior
* @param c El parte superior * @param c El parte superior n
* @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
* @param array El array a ordenar * @param array El array a ordenar
*/ */
void recbitonic(int low, int c, int dir, int *array) { void bitonicmerge_no2(int low, int n, int dir, int *array) {
int i;
int k; int k;
if (c > 1){ if (n > 1) {
k = c / 2; k = greatest_power_of_two_less_than(n);
for (i = low; i < low + n-k; i++){
compare(i, i + k, dir, array);
}
bitonicmerge_no2(low, k, dir, array);
bitonicmerge_no2(low + k, n - k, dir, array);
}
}
/**
* Generar la secuencia bitonica en forma de piramide
* @param low El parte inferior
* @param c El parte superior n
* @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
* @param array El array a ordenar
*/
void recbitonic(int low, int n, int dir, int *array) {
int k;
if (n > 1){
k = n / 2;
recbitonic(low, k, 1, array); recbitonic(low, k, 1, array);
recbitonic(low + k, k, 0, array); recbitonic(low + k, k, 0, array);
bitonicmerge(low, c, dir, array); bitonicmerge(low, n, dir, array);
}
}
/**
* Generar la secuencia bitonica en forma de piramide cuando n no es de potencia 2
* @param low El parte inferior
* @param c El parte superior n
* @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
* @param array El array a ordenar
*/
void recbitonic_no2(int low, int n, int dir, int *array) {
int k;
if (n > 1){
k = n / 2;
recbitonic_no2(low, k, !dir, array);
recbitonic_no2(low + k, n - k, dir, array);
bitonicmerge_no2(low, n, dir, array);
} }
} }
@ -74,7 +146,12 @@ void recbitonic(int low, int c, int dir, int *array) {
* @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
*/ */
void sort(int *array, int n, int dir) { void sort(int *array, int n, int dir) {
recbitonic(0, n, dir, array); if (power_of_two(n)) {
recbitonic(0, n, dir, array);
}
else {
recbitonic_no2(0, n, dir, array);
}
} }
/** /**
@ -83,5 +160,5 @@ void sort(int *array, int n, int dir) {
* @param n El tamaño del array * @param n El tamaño del array
*/ */
void bitonic_sort(int *array, int n) { void bitonic_sort(int *array, int n) {
sort(array, n, 1); sort(array, n, 1);
} }

View File

@ -52,7 +52,8 @@ void cleanup() {
* El programa de test * El programa de test
*/ */
int main(int argc, char **argv) { int main(int argc, char **argv) {
int n = 32768; int n = 50000;
int n2 = 32768;
int i; int i;
int gen; int gen;
int pass; int pass;
@ -99,7 +100,7 @@ int main(int argc, char **argv) {
// Prepare for sort tests // Prepare for sort tests
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
test_case[i] = gen_rand(-100, 100); test_case[i] = gen_rand(-1000000, 1000000);
} }
memcpy(qarray, test_case, sizeof(int) * n); memcpy(qarray, test_case, sizeof(int) * n);
qsort(qarray, n, sizeof(int), compar); qsort(qarray, n, sizeof(int), compar);
@ -156,25 +157,6 @@ int main(int argc, char **argv) {
break; break;
} }
} }
if (pass) {
fprintf(stdout, "pass\n");
passed++;
}
// Test bitonic sort
pass = 1;
memcpy(test_array, test_case, sizeof(int) * n);
fprintf(stdout, "\tbitonic sort: ");
fflush(stdout);
bitonic_sort(test_array, n);
for (i = 0; i < n; i++) {
if (test_array[i] != qarray[i]) {
fprintf(stdout, "fail\n");
failed++;
pass = 0;
break;
}
}
if (pass) { if (pass) {
fprintf(stdout, "pass\n"); fprintf(stdout, "pass\n");
passed++; passed++;
@ -218,6 +200,59 @@ int main(int argc, char **argv) {
passed++; passed++;
} }
// Test bitonic sort without 2^n
pass = 1;
memcpy(test_array, test_case, sizeof(int) * n);
fprintf(stdout, "\tbitonic sort: ");
fflush(stdout);
bitonic_sort(test_array, n);
for (i = 0; i < n; i++) {
if (test_array[i] != qarray[i]) {
fprintf(stdout, "fail\n");
failed++;
pass = 0;
break;
}
}
if (pass) {
fprintf(stdout, "pass\n");
passed++;
}
// Test bitonic sort with 2^n
pass = 1;
int *bitonic_test_case = malloc(sizeof(int) * n2);
if (bitonic_test_case == NULL) {
fprintf(stderr, "Error: Out of heap space!\n");
exit(1);
}
int *bitonic_test_array = malloc(sizeof(int) * n2);
if (bitonic_test_array == NULL) {
fprintf(stderr, "Error: Out of heap space!\n");
exit(1);
}
for (i = 0; i < n; i++) {
bitonic_test_case[i] = gen_rand(-1000000, 1000000);
}
memcpy(qarray, bitonic_test_case, sizeof(int) * n2);
qsort(qarray, n2, sizeof(int), compar);
memcpy(bitonic_test_array, bitonic_test_case, sizeof(int) * n2);
fprintf(stdout, "\tbitonic sort 2^n: ");
fflush(stdout);
bitonic_sort(bitonic_test_array, n2);
for (i = 0; i < n2; i++) {
if (bitonic_test_array[i] != qarray[i]) {
fprintf(stdout, "fail\n");
failed++;
pass = 0;
break;
}
}
if (pass) {
fprintf(stdout, "pass\n");
passed++;
}
fprintf(stdout, "%d tests passed\n", passed); fprintf(stdout, "%d tests passed\n", passed);
fprintf(stdout, "%d tests failed\n", failed); fprintf(stdout, "%d tests failed\n", failed);