Count inversion using MergSort C++ - arrays

I am trying to solve the below question, it works for all other cases except one mentioned below. Can someone please explain what is wrong with the code?
Question Inversion Count: For an array, inversion count indicates how far (or close) the array is from being sorted. If array is already sorted then the inversion count is 0. If an array is sorted in the reverse order then the inversion count is the maximum.
Formally, two elements a[i] and a[j] form an inversion if a[i] > a[j] and i < j.
int merge(long long int arr[], int low, int mid, int high)
{
int count = 0;
int n = mid-low+1;
int m = high-mid;
int a[n];
int b[m];
for(int i=0; i<n; i++)
{
a[i] = arr[low+i];
}
for(int i=0; i<m; i++)
{
b[i] = arr[mid+1+i];
}
int i=0;
int j=0;
int k=low;
while(i<n && j<m)
{
if(a[i]<=b[j])
{
arr[k]=a[i];
i++;
k++;
}
else if(b[j]<a[i])
{
arr[k]=b[j];
j++;
k++;
count += mid-i+1;
// cout<<"count:"<<count<<endl;
}
}
while(i<n)
{
arr[k]=a[i];
i++;
k++;
}
while(j<m)
{
arr[k]=b[j];
j++;
k++;
}
return count;
}
int mergeSort(long long int arr[], int low, int high)
{
int count = 0;
if(low<high)
{
int mid = (high+low)/2;
count += mergeSort(arr, low, mid);
count += mergeSort(arr, mid+1, high);
count += merge(arr, low, mid, high);
}
return count;
}
long long int inversionCount(long long arr[], long long n)
{
// Your Code Here 2 4 1 3 5
int count = mergeSort(arr, 0, n-1);
return count;
}
42-->no. of elements in array
468 335 1 170 225 479 359 463 465 206 146 282 328 462 492 496 443 328 437 392 105 403 154 293 383 422 217 219 396 448 227 272 39 370 413 168 300 36 395 204 312 323
desired result:
494
My Output:
1444

Related

generate a number sequence, and then sort the sequence

I am supposed to write a program that processes a sequence of 100 positive numbers. The program should have 3 different functions, which could be chosen from a menu.
Generate a number sequence with a random generator and print the numbers on the screen. The numbers generated should be in the range 0 ≤ n ≤ 900
I have to sort the sequence with bubble sort and then the numbers must be printed and I cannot use built-in sorting functions, such as qsort.
Quit program.
The 1 and 2 must be in own functions.
Lasly every time the program prints out the number, it should be printed as a table with ten rows and ten columns. Choice two can not be made unless choice one has been chosen.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 100
#define N 10
#define INVALID 0
#define VALID 1
void randomNum() {
//random number gen
int num[SIZE] = {0};
int i = 0;
srand(time(NULL));
for(i = 0; i < SIZE; i++) {
num[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", num[i]);
if(i % 10 == 9)
printf("\n");
}
}
void sort() {
//sort of the generated number sequence
int num[SIZE] = {0};
int i = 0;
int j = 0;
int temp = 0;
for (int i = 0 ; i < SIZE; i++)
{
for (int j = 0; j < SIZE - 1; j++)
{
if (num[j] > num[j+1])
{
temp = num[j];
num[j] = num[j+1];
num[j+1] = temp;
}
}
}
for(i = 0; i < SIZE; i++) {
printf("%4d", num[i]);
if(i % 10 == 9)
printf("\n");
}
}
int main() {
randomNum();
printf("\n");
sort();
return 0;
}
I have figured out the solutions for how to generate a sequene and sort it and it works correct when all the code are in main() , however, when I put in in own functions above the main() it does not work. I'm stuck and don't know how to move forward. When i run the program it generates a random sequence but then the sorting function just prints out 100 zeros.
I fixed up your code, to try to do mostly the same thing in a very straight forward fashion.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 100
void fill_random_array( int array[const], size_t sz )
{
srand(time(NULL));
for(int i = 0; i < sz; ++i)
{
array[i] = rand() % 901;
printf("%3d%s", array[i], (i+1)%16? " ": "\n" );
}
}
void sort( int array[const], size_t sz )
{
for (int i = 0 ; i < SIZE; i++)
{
for (int j = 0; j < SIZE - 1; j++)
{
if (array[j] > array[j+1])
{
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
int main()
{
int data[SIZE];
fill_random_array( data, SIZE );
printf("\n\nResult:\n");
sort( data, SIZE );
for(int i = 0; i < SIZE; ++i)
{
printf("%3d%s", data[i], (i+1)%16? " ": "\n" );
}
return 0;
}
Example Output:
Success #stdin #stdout 0s 5536KB
757 872 260 877 827 747 839 279 468 311 361 584 382 364 528 24
848 32 307 479 594 59 172 54 811 530 550 451 618 893 39 474
261 597 450 187 740 686 467 307 393 224 288 775 588 816 195 832
848 502 707 838 859 879 892 769 806 839 616 523 831 656 97 191
352 844 676 488 629 539 796 121 763 183 896 747 395 190 74 639
89 781 873 47 759 865 212 60 199 828 584 129 880 77 618 628
20 690 216 650
Result:
20 24 32 39 47 54 59 60 74 77 89 97 121 129 172 183
187 190 191 195 199 212 216 224 260 261 279 288 307 307 311 352
361 364 382 393 395 450 451 467 468 474 479 488 502 523 528 530
539 550 584 584 588 594 597 616 618 618 628 629 639 650 656 676
686 690 707 740 747 747 757 759 763 769 775 781 796 806 811 816
827 828 831 832 838 839 839 844 848 848 859 865 872 873 877 879
880 892 893 896
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 100
#define N 10
void fill_random_array( int array[SIZE], size_t size )
{
int i= 0;
srand(time(NULL));
for(i = 0; i < SIZE; ++i)
{
array[i] = rand() % 901;
}
for(i = 0; i < SIZE; i++) {
printf("%4d", array[i]);
if(i % 10 == 9)
printf("\n");
}
}
void sort( int array[SIZE], size_t size )
{
int i = 0;
int j = 0;
for (i = 0 ; i < SIZE; i++)
{
for (j = 0; j < SIZE - 1; j++)
{
if (array[j] > array[j+1])
{
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
for(i = 0; i < SIZE; i++) {
printf("%4d", array[i]);
if(i % 10 == 9)
printf("\n");
}
}
void calculations(int array[SIZE], size_t size) {
//max och min
int i = 0;
int max = 0;
int min = 900;
int sum = 0;
double average = 0;
double median = 0;
for(i = 0; i < SIZE; i++){
if(array[i] > max) {
max = array[i];
}
if(array[i] < min) {
min = array[i];
}
}
//average
for(i = 0; i < SIZE; i++) {
sum += array[i];
}
average = sum / SIZE;
//median
median = (array[49] + array[50])/2;
printf("Max: %d Min: %d Average: %f Median: %f\n", max, min, average, median);
}
void binsearch(int array[SIZE], size_t size) {
//binary search
int i = 0;
int pos = 0; //position
int start = 0; //start position i vector
int end = 99; //end position i vector
int number = 0;
int flag;
int row = 0; //row
int col = 0; //column
printf("Enter number: \n");
scanf("%d", &number);
flag = 0;
while(start <= end) {
pos = (start + end)/2;
if(array[pos] == number){
row = (pos / N) + 1;
col = (pos % N) + 1;
printf("The number %d was found in position %d and row %d and column %d\n", number, pos, row, col);
flag = 1;
break;
}
else if(array[pos] < number)
start = pos + 1;
else if(array[pos] > number)
end = pos - 1;
break;
}
if(flag == 0)
printf("Number not found\n");
}
int main()
{
int data[SIZE];
fill_random_array( data, SIZE );
printf("\n");
sort( data, SIZE );
printf("\n");
calculations( data, SIZE);
printf("\n");
binsearch(data, SIZE);
return 0;
}
This is what my code looks like now. The program works okay now I think but when I run it, it generates a random number sequence, and sort it and then print out max min, average value and median. But when I enter a number for the binarysearch it says: number not found even though the number is in the sorted sequence, how come it does that? And how do I fix it?

Fill a nxn matrix in spiral order from 1 to n²

I was supposed to fill an nxn matrix in spiral order from 1 to n² using functions and then print its result but I don't know why my code doesn't function can anyone help please?
The principle was to create different functions, each filling the matrix at different time intervals then calling those functions in the main program which prints them in a spiral matrix.
#include <stdio.h>
#include <stdlib.h>
/* initializing the array and variables for the whole program*/
int A[5][5],top,bottom,left,right;
int FillRowForward(int A[5][5],int top,int left,int right,int z)
/*function that fills the top of the matrix from left to right*/
{ left = 0;
for(top=left,right=0;right<=4;right++)
{
A[top][right]=z;
z++;
}
return A[top][right];
}
int FillRowBackwards(int A[5][5],int bottom,int left,int right,int z)
/*fills the lower part from right to left*/
{ bottom =4;
for(left=bottom,right=4;right>=0;right--)
{
A[left][right-1]=A[left][right]+z;
}
return A[left][right-1];
}
int FillColumnDownward(int A[5][5],int top,int bottom,int left,int z)
/*fills the last column from top to bottom*/
{
left=0;
for(top=left,bottom=4;top<=4;top++)
{
A[top+1][bottom]= A[top][bottom]+z;
}
return A[top][bottom];
}
int FillColumnUpward(int A[5][5],int top,int bottom,int left, int z)
/*fills the first column from bottop to top*/
{
left =0;
for(bottom=left,top=0;bottom>=1;bottom--)
{
A[bottom-1][top]=A[bottom][top]+z
}
return A[bottom][top];
}
int main()
{
int i,j,k=1;
while(k<5*5){
int FillRowForward(int A[5][5],int top,int left,int right,int k);
top++;
int FillColumnDownward(int A[5][5],int top,int bottom,int right,int k);
right--;
int FillRowBackwards(int A[5][5],int bottom,int left,int right,int k);
bottom--;
int FillColumnUpward(int A[5][5],int top,int bottom,int left,int k);
}
//prints the matrix
for(i=0;i<=4;i++)
for(j=0;j<=4;j++)
printf("%d",A[i][j]);
return 0;
}
You have a number of problems like:
int FillRowForward(int A[5][5],int top,int left,int right,int k);
not being a function call and that you you never change k, i.e. you have an endless loop.
This solution uses a variable direction to track the current direction of filling the matrix.
#include <stdio.h>
#define ARRSIZE 10
int main()
{
int A[ARRSIZE][ARRSIZE] = { 0 };
int i=0, j=0;
int direction = 0;
for(int k = 1; k <= (ARRSIZE*ARRSIZE); ++k)
{
A[i][j] = k;
switch (direction)
{
case 0 : // Go rigth
if (((j + 1) == ARRSIZE) || (A[i][j+1] != 0))
{
// Switch direction
direction = 1;
++i;
}
else
{
++j;
}
break;
case 1 : // Go down
if (((i + 1) == ARRSIZE) || (A[i+1][j] != 0))
{
// Switch direction
direction = 2;
--j;
}
else
{
++i;
}
break;
case 2 : // Go left
if (((j - 1) == -1) || (A[i][j-1] != 0))
{
// Switch direction
direction = 3;
--i;
}
else
{
--j;
}
break;
case 3 : // Go up
if (((i - 1) == -1) || (A[i-1][j] != 0))
{
// Switch direction
direction = 0;
++j;
}
else
{
--i;
}
break;
}
}
for(i=0; i<ARRSIZE; i++)
{
for(j=0; j<ARRSIZE; j++)
printf("%4d",A[i][j]);
printf("\n");
}
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 10
36 37 38 39 40 41 42 43 44 11
35 64 65 66 67 68 69 70 45 12
34 63 84 85 86 87 88 71 46 13
33 62 83 96 97 98 89 72 47 14
32 61 82 95 100 99 90 73 48 15
31 60 81 94 93 92 91 74 49 16
30 59 80 79 78 77 76 75 50 17
29 58 57 56 55 54 53 52 51 18
28 27 26 25 24 23 22 21 20 19
You have a couple of problems here:
I suppose there is no need for global variables, so you can define everything in the main() function
As already pointed out "In main() you are only providing declarations of the functions, not calling them. "
You have an infinite loop in main() function because you never increased var k
Try to avoid using numbers in your function, use variables or symbolic constants instead. No difference on such small projects, but in bigger projects, you can easily confuse them, also if you want to change, you must change every value, etc.
Your functions are not doing what they are supposed to do. You can write something like this (I found my old program and modified it a bit):
#include <stdio.h>
void print_mat(int mat[][5], int m, int n)
{
int i,j;
for(i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
printf("%d\t", mat[i][j]);
}
printf("\n\n");
}
printf("\n");
}
void spiral(int mat[][5], int m, int n)
{
int i, k = 0, l = 0;
int counter = 1;
while(k < m && l < n)
{
for(i = l; i < n; i++)
{
mat[k][i] = counter++;
}
k++;
for(i = k; i < m; i++)
{
mat[i][n-1] = counter++;
}
n--;
if(k < m)
{
for(i = n-1; i >= l; i--)
{
mat[m-1][i] = counter++;
}
m--;
}
if(l < n)
{
for(i = m-1; i >= k; i--)
{
mat[i][l] = counter++;
}
l++;
}
}
}
int main()
{
int mat[5][5];
int n = 5;
spiral(mat,n,n);
print_mat(mat,n,n);
return 0;
}
Since you need to create different functions, you can try to divide this spiral() function into several smaller functions, it can be a good exercise.

Wrong function of the code in C. the program seems to display garbage [duplicate]

This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 2 years ago.
I wrote a program to run the insertion sorting algorithms. Everything seems good. But when I execute it there is a strange result. It seems that the programs uses garbage in memory. How could I fix it?
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void insertion_inc(int Array[], int size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
j = i - 1;
key = Array[i];
while (j >=0 && Array[j]>key )
{
Array[j + 1] = Array[j];
j--;
}
Array[j++] = key;
}
}
void insertion_dec(int Array[], int size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
j = i - 1;
key = Array[i];
while (j >= 0 && Array[j] < key)
{
Array[j + 1] = Array[j];
j--;
}
Array[j++] = key;
}
}
void print_array(int arr[], int size)
{
for (int i = 0; i < size; i++)
printf(" %d ", arr[i]);
}
/////////////////////////////////////////////
int main()
{
time_t t;
srand((unsigned)time(&t));
int Arr[10];
int size = sizeof(Arr);
printf("The unsorted Array : \n ");
for (int i = 0; i < size;i++)
Arr[i] = rand()/10;
print_array(Arr, size);
printf("\n\n\n The sorted Array : \n");
insertion_inc(Arr, size);
print_array(Arr, size);
return 0;
}
**The output always looks like this : **
The unsorted Array :
12 23 54 87 2 68 29 57 97 12 -858993460 272204808 7601072 7742451 1 15039136 15044096 1 15039136 15044096 7601164 7742023 272204692 7738189 7738189 8462336 0 0 0 0 0 0 0 0 7775604 7775616 0 7601080 0 7601272
The sorted Array :
23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 57 68 7601272 7738189 7738189 7738189 7742023 7775616 8462336 8462336 8462336 15039136 15039136 15039136 15039136 15044096 272204692 272204808 272204808 272204808 272204808 272204808 272204808 272204808 272204808
Even when I ignore the use of srand() and rand(), there is still the problem.
This line:
int size = sizeof(Arr);
does not do what you think it does. It is returning the size in bytes, rather than elements.
See How do I determine the size of my array in C?
You're not calculating the array size correctly:
int size = sizeof(Arr);
The sizeof operator gives the size of its operand in bytes. So assuming an int is 4 bytes on your system, sizeof(Arr) evaluates to 40.
You instead want to divide the size of the array by the size of an element of the array to get the number of elements.
int size = sizeof(Arr) / sizeof(*Arr);

Error in implementing bubble sorting in a merge sort program in C

I am learning data structure and algorithms. The program takes a set number of inputs in an array and sorts them out using merge sort. The condition is whenever the size of a sub-array is equal to or smaller than 10, it should sort the elements out using bubble sort and then merge them together. My problem is with getting the program to bubble sort. So far I have been unable to find out the mistake in my program. I am still learning everyday. I would really appreciate it if someone could help me find the error and fix it please. Thank you very much and have a g'day.
Here's the code:
#include<stdio.h>
#include<stdlib.h>
#define arrsize 10
void merge_sort(int, int);
void merge_array(int, int, int, int);
int arr_sort[arrsize];
void bubblesort(int a[],int size);
void main()
{
int a[50],n,i;
printf("\nEnter %d Elements for Sorting\n", arrsize);
for (i = 0; i < arrsize; i++)
scanf("%d", &arr_sort[i]);
printf("\nYour Data :");
for (i = 0; i < arrsize; i++) {
printf("\t%d", arr_sort[i]);
}
merge_sort(0, arrsize - 1);
printf("\n\nSorted Data :");
for (i = 0; i < arrsize; i++) {
printf("\t%d", arr_sort[i]);
}
}
void bubblesort(int arr_sort[],int size)
{
int temp,i,j;
for(i=0;i<size;i++)
{
for(j=0;j<size-1;j++)
{
if(arr_sort[j]>arr_sort[j+1])
{
temp=arr_sort[j];
arr_sort[j]=arr_sort[j+1];
arr_sort[j+1]=temp;
}
}
}
}
void merge_sort(int i, int j) {
int m;
if (i < j) {
m = (i + j) / 2;
if(m<=5)
{
for(i=0;i<=m;i++){
for(j=i+1;j<=m;j++){
bubblesort(arr_sort[i],m);
bubblesort(arr_sort[j],m);}}
merge_array(i,m,m+1,j);
}
else
merge_sort(i, m);
merge_sort(m + 1, j);
merge_array(i, m, m + 1, j);
}
}
void merge_array(int a, int b, int c, int d) {
int t[50];
int i = a, j = c, k = 0;
while (i <= b && j <= d) {
if (arr_sort[i] < arr_sort[j])
t[k++] = arr_sort[i++];
else
t[k++] = arr_sort[j++];
}
while (i <= b)
t[k++] = arr_sort[i++];
while (j <= d)
t[k++] = arr_sort[j++];
for (i = a, j = 0; i <= d; i++, j++)
arr_sort[i] = t[j];
}
Among the issues in your code:
From merge_sort, you should be calling bubble_sort for a given floor magnitude, hard-fixed in your merge_sort, specified globally, or as an argument to your functions. The former of these is easiest to achieve.
Your bubble_sort invocation from merge_sort is wrong from inception, as you're passing int values where int* should be present.
Your functions should all take the array to sort as an argument, and at least the length as well. This makes the functions more robust, and thanks to pointer arithmetic, easier to implement than you may think.
Fixing this requires major surgery.
Updated merge_array
First some surgery for the merge_array function. This assumes you support variable length arrays (VLAs). Notice the function accepts the array base address, the mid point, and the overall length.
void merge_array(int a[], int mid, int len)
{
// change to int tmp[arrsize], or use dynamic allocation, if your
// platform doesn't support VLAs
int tmp[len];
int i = 0, j = mid, k = 0;
while (i < mid && j < len)
tmp[k++] = ((a[i] < a[j]) ? a[i++] : a[j++]);
while (i < mid)
tmp[k++] = a[i++];
for (i = 0; i < k; ++i)
a[i] = tmp[i];
}
Updated merge_sort
Now the merge_sort function as described in the problem analysis. Like the above, it should take an array base address and a length, but that's all it needs. Pointer arithmetic will let us partition on recursed calls.
void merge_sort(int a[], int len)
{
if (len < 5)
{
// bubblesort short partitions (less than length:5)
bubble_sort(a, len);
}
else
{
int mid = len / 2;
merge_sort(a, mid);
merge_sort(a + mid, len - mid); // note pointer arithmetic here
merge_array(a, mid, len);
}
}
Updated bubble_sort
This simple bubble sort uses forward swap detection to leave early on already-sorted detection. Like the prior functions, we have the base address of some array and a specified length.
void bubble_sort(int a[], int size)
{
int swapped = 1;
while (swapped && size-- > 0)
{
swapped = 0;
for (int i = 0; i < size; ++i)
{
if (a[i + 1] < a[i])
{
int tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
swapped = 1;
}
}
}
}
Putting It All Together
Below is the complete program, which includes a print helper to dump an array to the console, and a random-generator to avoid lengthy keyboard input. The provided main() creates a random-filled array, prints it, sorts it, then prints the result. Obviously the output will vary with each run, but you hopefully get the idea of how the above functions are called.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define arrsize 40
void merge_sort(int a[], int len);
void merge_array(int a[], int mid, int len);
void bubble_sort(int a[], int size);
void merge_array(int a[], int mid, int len)
{
// change to int tmp[arrsize], or use dynamic allocation, if your
// platform doesn't support VLAs
int tmp[len];
int i = 0, j = mid, k = 0;
while (i < mid && j < len)
tmp[k++] = ((a[i] < a[j]) ? a[i++] : a[j++]);
while (i < mid)
tmp[k++] = a[i++];
for (i = 0; i < k; ++i)
a[i] = tmp[i];
}
void merge_sort(int a[], int len)
{
if (len < 5)
{
// bubblesort short partitions (less than length:5)
bubble_sort(a, len);
}
else
{
int mid = len / 2;
merge_sort(a, mid);
merge_sort(a + mid, len - mid); // note pointer arithmetic here
merge_array(a, mid, len);
}
}
void bubble_sort(int a[], int size)
{
int swapped = 1;
while (swapped && size-- > 0)
{
swapped = 0;
for (int i = 0; i < size; ++i)
{
if (a[i + 1] < a[i])
{
int tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
swapped = 1;
}
}
}
}
void print_arr(int const arr[], int len)
{
while (len-- > 0)
printf("%d ", *arr++);
fputc('\n', stdout);
}
int main()
{
srand((unsigned)time(NULL));
int arr_sort[arrsize];
// generate random array
for (int i = 0; i < arrsize; ++i)
arr_sort[i] = 1 + rand() % 99;
print_arr(arr_sort, arrsize);
// sort the array
merge_sort(arr_sort, arrsize);
print_arr(arr_sort, arrsize);
}
Sample Output
16 81 73 86 87 66 14 93 19 13 62 32 70 56 29 88 20 21 7 27 70 46 72 42 95 83 24 2 5 43 67 79 8 18 82 39 81 56 56 45
2 5 7 8 13 14 16 18 19 20 21 24 27 29 32 39 42 43 45 46 56 56 56 62 66 67 70 70 72 73 79 81 81 82 83 86 87 88 93 95
Hope it helps.

Floating point exception in OpenAcc Merge Sort program

#include<stdlib.h>
#include<stdio.h>
#include <time.h>
#include <omp.h>
#include <openacc.h>
#define THR 10
//Function to test if the output is in asending order or not
void test(int a[], int n) {
int i;
for (i=1;i<n;++i) {
if (a[i]<a[i-1]) {
break;
}
}
if (i<n) {
for (i=1;i<n;++i) {
if (a[i]>a[i-1]){
break;
}
}
if (i<n) {
printf("\nArray is not sorted\n");
}
}
else {
printf("\nArray is sorted\n");
}
}
/* Function to sort an array using insertion sort in serial*/
void isort (int *array, int low, int mid, int high) {
for (int i = mid; i <= high; i++) {
for (int j = i - 1; j >= 0; j--) {
if (array[i] < array [j]) {
int holder = array[j];
array[j] = array[i];
array[i] = holder;
i--;
}
}
}
}
/* Function to merge */
void merge(int arr[], int l, int m, int r);
// Utility function to find minimum of two integers
#pragma acc routine seq
int min(int x, int y) { return (x<y)? x :y; }
/* Iterative mergesort function to sort arr[0...n-1] */
void mergeSort(int arr[], int n)
{
int curr_size; // For current size of subarrays to be merged
// curr_size varies from 1 to n/2
int left_start; // For picking starting index of left subarray
// to be merged
#pragma acc kernels //pcopy(arr[0:n1])// pcopying (R[0:n2])
{
#pragma acc loop independent
for (curr_size=1; curr_size<=n-1; curr_size = 2*curr_size)
{
#pragma acc loop independent
// Pick starting point of different subarrays of current size
for (left_start=0; left_start<n-1; left_start += 2*curr_size)
{
// Find ending point of left subarray. mid+1 is starting
// point of right
int mid = left_start + curr_size - 1;
int right_end = min(left_start + 2*curr_size - 1, n-1);
// Merge Subarrays arr[left_start...mid] & arr[mid+1...right_end]
merge(arr, left_start, mid, right_end);
}
}
}}
/* Function to merge the two haves arr[l..m] and arr[m+1..r] of array arr[]
*/
#pragma acc routine vector
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int *L, *R;
L = (int *)malloc(sizeof(int) * n1);
R = (int *)malloc(sizeof(int) * n2);
/* Copy data to temp arrays L[] and R[] */
#pragma acc loop independent
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
#pragma acc loop independent
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0;
j = 0;
k = l;
#pragma acc loop independent private(k) reduction(+:j) private (L[0:n1]) private (R[0:n1]) private (arr[0:n1])reduction(+:i)
// private(k) reduction(+:j)
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there are any */
#pragma acc loop seq private (arr[0:n2])
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there are any */
#pragma acc loop seq private (arr[0:n2])
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
free(L);
free(R);
}
/* Function to print an array */
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
/* Driver program to test above functions */
int main()
{
int i, n=20, *a;
double startTime, endTime;
printf("How many elements in the array? ");
a = (int *)malloc(sizeof(int) * n);
srand(time(0));
for(i=0;i<n;i++)
{
a[i]=rand()%1000;
}
printf("List Before Sorting...\n");
printArray(a, n);
if (n<=THR)
{
startTime = omp_get_wtime();
isort(a,0,0,n);
endTime = omp_get_wtime();
printf("\nSorted array: ");
printArray(a,n);
printf("\n");
test(a,n);
printf("IN");
printf("\nTime: %g\n",endTime-startTime);
exit(0);
}
else
{
startTime = omp_get_wtime();
mergeSort(a,n);
endTime = omp_get_wtime();
printf("\nSorted array: ");
printArray(a,n);
printf("\n");
test(a,n);
printf("ACC");
printf("\nTime: %g\n",endTime-startTime);
printf("\nSize of the array is %d",n);
exit(0);
}
}
After reading plenty of articles in PGI forum and help of #MAT from stackoverflow, I managed to resolve most of the errors and now I am using iterative Merge Sort instead of recursive as I found that OpenAcc doesn't work well with recursive functions. Now, I have only one error remaining this is in merge function:-
109, Loop without integer trip count will be executed in sequential mode
And I read http://www.pgroup.com/userforum/viewtopic.php?p=17748&sid=0aa1537bdc68fc1f6fac74f66a788970 also but can't get certain idea to use it in my program. Because of this error, my result is:-
How many elements in the array? List Before Sorting...
801 673 288 374 516 908 473 130 874 928 491 406 276 302 186 442 865 341 624 725
Floating point exception
It's saying floating point exception even when I am using integers in my program.
There's a few problems here.
It looks like there can be a case where "mid" is greater that "right_end" which will cause a malloc to have a negative size. While I'm not sure it's the correct fix, I added an if statement to skip the merge when mid>right_end.
Parallel loops must be countable, i.e. that the number of iterations is known at the start of the loop. Hence you can't put "loop" directives around while loops.
Putting "arr" in a private clause isn't what you want here. You want to update the global array, not a private copy. Private will make a private copy of the variable for every gang, vector, or worker (depending upon the schedule of the loop with the private clause). The private variable goes away after the kernel executes.
Also your "curr_size" for loop has a dependency so can't be parallelized. The problem here is that it strides by "curr_size=2*curr_size". Each iteration needs the previous iteration's curr_size value before it can compute it's own curr_size.
Note that using "malloc" within a compute region is problematic. First, device side mallocs are very slow so will have an adverse impact on performance. Also, the heap on the device is quite small (default 8MB but can be increased but setting the environment variable PGI_ACC_HEAPSIZE) so very large values of n may overflow the heap and give an illegal address error.
Here's the fixed code:
% cat test.c
#include<stdlib.h>
#include<stdio.h>
#include <time.h>
#include <omp.h>
#include <openacc.h>
#define THR 10
//Function to test if the output is in asending order or not
void test(int a[], int n) {
int i;
for (i=1;i<n;++i) {
if (a[i]<a[i-1]) {
break;
}
}
if (i<n) {
for (i=1;i<n;++i) {
if (a[i]>a[i-1]){
break;
}
}
if (i<n) {
printf("\nArray is not sorted\n");
}
}
else {
printf("\nArray is sorted\n");
}
}
/* Function to sort an array using insertion sort in serial*/
void isort (int *array, int low, int mid, int high) {
for (int i = mid; i <= high; i++) {
for (int j = i - 1; j >= 0; j--) {
if (array[i] < array [j]) {
int holder = array[j];
array[j] = array[i];
array[i] = holder;
i--;
}
}
}
}
/* Function to merge */
void merge(int arr[], int l, int m, int r);
// Utility function to find minimum of two integers
#pragma acc routine seq
int min(int x, int y) { return (x<y)? x :y; }
/* Iterative mergesort function to sort arr[0...n-1] */
void mergeSort(int arr[], int n)
{
int curr_size; // For current size of subarrays to be merged
// curr_size varies from 1 to n/2
int left_start; // For picking starting index of left subarray
// to be merged
#pragma acc data copy(arr[0:n])// pcopying (R[0:n2])
{
for (curr_size=1; curr_size<=n-1; curr_size = 2*curr_size)
{
#pragma acc parallel loop
// Pick starting point of different subarrays of current size
for (left_start=0; left_start<n-1; left_start += 2*curr_size)
{
// Find ending point of left subarray. mid+1 is starting
// point of right
int mid = left_start + curr_size - 1;
int right_end = min(left_start + 2*curr_size - 1, n-1);
// Merge Subarrays arr[left_start...mid] & arr[mid+1...right_end]
if (mid < right_end) merge(arr, left_start, mid, right_end);
}
}
}}
/* Function to merge the two haves arr[l..m] and arr[m+1..r] of array arr[]
*/
#pragma acc routine(merge) vector
void merge(int arr[], int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
int *L, *R;
L = (int *)malloc(sizeof(int) * n1);
R = (int *)malloc(sizeof(int) * n2);
/* Copy data to temp arrays L[] and R[] */
#pragma acc loop independent
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
#pragma acc loop independent
for (j = 0; j < n2; j++)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
/* Copy the remaining elements of L[], if there are any */
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there are any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
free(L);
free(R);
}
/* Function to print an array */
void printArray(int A[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
}
/* Driver program to test above functions */
int main()
{
int i, n=100, *a;
double startTime, endTime;
printf("How many elements in the array? ");
a = (int *)malloc(sizeof(int) * n);
srand(time(0));
for(i=0;i<n;i++)
{
a[i]=rand()%1000;
}
printf("List Before Sorting...\n");
printArray(a, n);
if (n<=THR)
{
startTime = omp_get_wtime();
isort(a,0,0,n);
endTime = omp_get_wtime();
printf("\nSorted array: ");
printArray(a,n);
printf("\n");
test(a,n);
printf("IN");
printf("\nTime: %g\n",endTime-startTime);
exit(0);
}
else
{
startTime = omp_get_wtime();
mergeSort(a,n);
endTime = omp_get_wtime();
printf("\nSorted array: ");
printArray(a,n);
printf("\n");
test(a,n);
printf("ACC");
printf("\nTime: %g\n",endTime-startTime);
printf("\nSize of the array is %d\n",n);
exit(0);
}
}
% pgcc -Minfo=accel -acc test.c -fast -o gpu
min:
51, Generating acc routine seq
Generating Tesla code
mergeSort:
60, Generating copy(arr[:n])
64, Accelerator kernel generated
Generating Tesla code
66, #pragma acc loop gang /* blockIdx.x */
merge:
84, Generating Tesla code
95, #pragma acc loop vector /* threadIdx.x */
98, #pragma acc loop vector /* threadIdx.x */
106, #pragma acc loop seq
123, #pragma acc loop seq
131, #pragma acc loop seq
95, Loop is parallelizable
98, Loop is parallelizable
106, Loop carried scalar dependence for i at line 119,126,125
Loop carried scalar dependence for j at line 106,108
Loop carried scalar dependence for i at line 111,110
Loop carried scalar dependence for j at line 116
Scalar last value needed after loop for i at line 123
Loop carried scalar dependence for j at line 134,133
Loop carried scalar dependence for i at line 108
Loop carried scalar dependence for j at line 115
110, Accelerator restriction: induction variable live-out from loop: k
115, Accelerator restriction: induction variable live-out from loop: k
118, Accelerator restriction: induction variable live-out from loop: k
% ./gpu
How many elements in the array? List Before Sorting...
58 612 99 182 914 802 452 229 856 644 932 339 650 915 533 300 456 892 860 764 866 229 400 561 328 170 573 121 364 392 801 775 356 901 309 622 703 762 851 911 406 135 602 56 51 136 708 507 380 568 623 246 797 24 160 125 194 733 599 910 477 400 685 185 653 995 808 709 109 659 972 867 147 575 276 198 711 984 57 91 553 680 689 702 56 849 828 602 935 779 865 412 179 550 598 185 897 758 894 6
Sorted array: 6 24 51 56 56 57 58 91 99 109 121 125 135 136 147 160 170 179 182 185 185 194 198 229 229 246 276 300 309 328 339 356 364 380 392 400 400 406 412 452 456 477 507 533 550 553 561 568 573 575 598 599 602 602 612 622 623 644 650 653 659 680 685 689 702 703 708 709 711 733 758 762 764 775 779 797 801 802 808 828 849 851 856 860 865 866 867 892 894 897 901 910 911 914 915 932 935 972 984 995
Array is sorted
ACC
Time: 1.26239
Size of the array is 100

Resources