I want to partition matrix into blocks (not stripes) and then distribute this blocks using MPI_Scatter.
I came up with solution which works, but I think it is far from "best practice". I have 8x8 matrix, filled with numbers from 0 to 63. Then I divide it into 4 4x4 blocks, using MPI_Type_vector and distribute it via MPI_Send, but this require some extra computation since i have to compute offsets for each block in big matrix.
If I use scatter, first (top left) block is transfered OK, but other blocks are not (wrong offset for start of block).
So is it possible to transfer blocks of matrix using MPI_Scatter, or what is the best way to do desired decomposition?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define SIZE 8
int main(void) {
MPI_Init(NULL, NULL);
int p, rank;
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
char i;
char a[SIZE*SIZE];
char b[(SIZE/2)*(SIZE/2)];
MPI_Datatype columntype;
MPI_Datatype columntype2;
MPI_Type_vector(4, 4, SIZE, MPI_CHAR, &columntype2);
MPI_Type_create_resized( columntype2, 0, sizeof(MPI_CHAR), &columntype );
MPI_Type_commit(&columntype);
if(rank == 0) {
for( i = 0; i < SIZE*SIZE; i++) {
a[i] = i;
}
for(int rec=0; rec < p; rec++) {
int offset = (rec%2)*4 + (rec/2)*32;
MPI_Send (a+offset, 1, columntype, rec, 0, MPI_COMM_WORLD);
}
}
MPI_Recv (b, 16, MPI_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
//MPI_Scatter(&a, 1, boki, &b, 16, MPI_CHAR , 0, MPI_COMM_WORLD);
printf("rank= %d b= \n%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n", rank, b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]);
MPI_Finalize();
return 0;
}
What you've got is pretty much "best practice"; it's just a bit confusing until you get used to it.
Two things, though:
First, be careful with this: sizeof(MPI_CHAR) is, I assume, 4 bytes, not 1. MPI_CHAR is an (integer) constant that describes (to the MPI library) a character. You probably want sizeof(char), or SIZE/2*sizeof(char), or anything else convenient. But the basic idea of doing a resize is right.
Second, I think you're stuck using MPI_Scatterv, though, because there's no easy way to make the offset between each block the same size. That is, the first element in the first block is at a[0], the second is at a[SIZE/2] (jump of size/2), the next is at a[SIZE*(SIZE/2)] (jump of (SIZE-1)*(SIZE/2)). So you need to be able to manually generate the offsets.
The following seems to work for me (I generalized it a little bit to make it clearer when "size" means "number of rows" vs "number of columns", etc):
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#define COLS 12
#define ROWS 8
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int p, rank;
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
char i;
char a[ROWS*COLS];
const int NPROWS=2; /* number of rows in _decomposition_ */
const int NPCOLS=3; /* number of cols in _decomposition_ */
const int BLOCKROWS = ROWS/NPROWS; /* number of rows in _block_ */
const int BLOCKCOLS = COLS/NPCOLS; /* number of cols in _block_ */
if (rank == 0) {
for (int ii=0; ii<ROWS*COLS; ii++) {
a[ii] = (char)ii;
}
}
if (p != NPROWS*NPCOLS) {
fprintf(stderr,"Error: number of PEs %d != %d x %d\n", p, NPROWS, NPCOLS);
MPI_Finalize();
exit(-1);
}
char b[BLOCKROWS*BLOCKCOLS];
for (int ii=0; ii<BLOCKROWS*BLOCKCOLS; ii++) b[ii] = 0;
MPI_Datatype blocktype;
MPI_Datatype blocktype2;
MPI_Type_vector(BLOCKROWS, BLOCKCOLS, COLS, MPI_CHAR, &blocktype2);
MPI_Type_create_resized( blocktype2, 0, sizeof(char), &blocktype);
MPI_Type_commit(&blocktype);
int disps[NPROWS*NPCOLS];
int counts[NPROWS*NPCOLS];
for (int ii=0; ii<NPROWS; ii++) {
for (int jj=0; jj<NPCOLS; jj++) {
disps[ii*NPCOLS+jj] = ii*COLS*BLOCKROWS+jj*BLOCKCOLS;
counts [ii*NPCOLS+jj] = 1;
}
}
MPI_Scatterv(a, counts, disps, blocktype, b, BLOCKROWS*BLOCKCOLS, MPI_CHAR, 0, MPI_COMM_WORLD);
/* each proc prints it's "b" out, in order */
for (int proc=0; proc<p; proc++) {
if (proc == rank) {
printf("Rank = %d\n", rank);
if (rank == 0) {
printf("Global matrix: \n");
for (int ii=0; ii<ROWS; ii++) {
for (int jj=0; jj<COLS; jj++) {
printf("%3d ",(int)a[ii*COLS+jj]);
}
printf("\n");
}
}
printf("Local Matrix:\n");
for (int ii=0; ii<BLOCKROWS; ii++) {
for (int jj=0; jj<BLOCKCOLS; jj++) {
printf("%3d ",(int)b[ii*BLOCKCOLS+jj]);
}
printf("\n");
}
printf("\n");
}
MPI_Barrier(MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
Running:
$ mpirun -np 6 ./matrix
Rank = 0
Global matrix:
0 1 2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31 32 33 34 35
36 37 38 39 40 41 42 43 44 45 46 47
48 49 50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69 70 71
72 73 74 75 76 77 78 79 80 81 82 83
84 85 86 87 88 89 90 91 92 93 94 95
Local Matrix:
0 1 2 3
12 13 14 15
24 25 26 27
36 37 38 39
Rank = 1
Local Matrix:
4 5 6 7
16 17 18 19
28 29 30 31
40 41 42 43
Rank = 2
Local Matrix:
8 9 10 11
20 21 22 23
32 33 34 35
44 45 46 47
Rank = 3
Local Matrix:
48 49 50 51
60 61 62 63
72 73 74 75
84 85 86 87
Rank = 4
Local Matrix:
52 53 54 55
64 65 66 67
76 77 78 79
88 89 90 91
Rank = 5
Local Matrix:
56 57 58 59
68 69 70 71
80 81 82 83
92 93 94 95
Related
Given n triangles, with sides a,b,c print them in the same style by sorting them from the smallest to the largest.
Complete problem: https://www.hackerrank.com/challenges/small-triangles-large-triangles/problem
In the solution, we have a structure named as Triangle. It has 3 integers a,b,c. An array of Triangle is made, named as tr and the input is passed to the function sort_by_area.
My approach is to apply bubble sort on this array.But instead of comparing tr[j] > tr[j+1] like we do in normal bubble sort, I'm comparing the areas of tr[j] and tr[j+1]. Now, if area of tr[j] > tr[j+1]: Swap.
The problem: In the end the results are wrong. The array doesn't sort properly. First I thought it's a typo somewhere so I rewrite the code but the problem persists.
double area (int a, int b, int c)
{
double p = (a+b+c)/2;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
void sort_by_area(triangle* tr, int n) {
/**
* Sort an array a of the length n
*/
int i,j;
double area1, area2;
triangle temp;
for(i = 0; i < n-1;++i)
{
for(j = 0; j < n-i-1; ++j)
{
area1 = area(tr[j].a , tr[j].b, tr[j].c);
area2 = area(tr[j+1].a , tr[j+1].b, tr[j+1].c);
if(area1 > area2)
{
temp = tr[j];
tr[j] = tr[j+1];
tr[j+1] = temp;
}
}
}
}
input: 20
23 37 47
22 18 5
58 31 31
28 36 40
54 62 11
31 41 14
53 18 54
41 38 55
55 44 44
44 48 18
26 41 65
20 23 21
58 61 50
28 56 56
20 39 32
33 45 49
26 41 62
31 46 39
48 49 67
57 33 45
expected output:
22 18 5
31 41 14
20 23 21
54 62 11
26 41 65
58 31 31
20 39 32
26 41 62
44 48 18
23 37 47
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50
actual output:
22 18 5
54 62 11
31 41 14
20 23 21
26 41 65
20 39 32
58 31 31
26 41 62
23 37 47
44 48 18
53 18 54
28 36 40
31 46 39
33 45 49
57 33 45
28 56 56
41 38 55
55 44 44
48 49 67
58 61 50
This is my solution for this challenge:
double area(triangle t){
double p = (t.a+t.b+t.c)/2.0;
return sqrt(p*(p-t.a)*(p-t.b)*(p-t.c));
}
void sort_by_area(triangle* tr, int n) {
int i,j;
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
if(area(tr[j]) < area(tr[i])){
triangle temp = tr[i];
tr[i]=tr[j];
tr[j]=temp;
}
}
}
}
Your usage of the 'for' loop for comparing triangles is this (by triangle, I mean triangle's area):
for(i = 0; i < n - 1; ++i){
...
...
for(j = 0; j < n - i - 1; ++j){
...
}
}
Observe carefully: The loop you used fails to compare the last elements of the arrays.
I just improvised your code and it works:
#include < stdio.h >
#include < stdlib.h >
#include < math.h >
struct triangle
{
int a;
int b;
int c;
};
typedef struct triangle triangle;
float area(int a, int b, int c)
{
float p;
p = (float)(a + b + c) / 2;
return sqrt(p * (p - a) * (p - b) * (p - c));
}
void sort_by_area(triangle* tr, int n)
{
int i, j;
float area1, area2;
triangle temp[5];
for (i = 0; i < n - 1; i++)
{
for (j = 0; j < n - i - 1; j++)
{
area1 = area(tr[j].a, tr[j].b, tr[j].c);
area2 = area(tr[j + 1].a, tr[j + 1].b, tr[j + 1].c);
if (area1 > area2)
{
temp[0] = tr[j];
tr[j] = tr[j + 1];
tr[j + 1] = temp[0];
}
}
}
}
int main()
{
int n;
scanf("%d", &n);
triangle* tr = malloc(n * sizeof(triangle));
for (int i = 0; i < n; i++)
{
scanf("%d%d%d", &tr[i].a, &tr[i].b, &tr[i].c);
}
sort_by_area(tr, n);
for (int i = 0; i < n; i++)
{
printf("%d %d %d\n", tr[i].a, tr[i].b, tr[i].c);
}
return 0;
}
An edit of #Zümrüd-ü Anka's answer to match the bubble sorts you'll find elsewhere. Your loops actually should work fine, both for loops here are the same as yours. This passes the test cases for HackerRank. I think it was actually just the integer division that was giving you an issue.
double area(triangle t){
double p = (t.a+t.b+t.c)/2.0;
return sqrt(p*(p-t.a)*(p-t.b)*(p-t.c));
}
void sort_by_area(triangle* tr, int n) {
int i,j;
for(i=0;i<n-1;i++){
for(j=0;j<n-i-1;j++){
if(area(tr[j]) > area(tr[j+1])){
triangle temp = tr[j+1];
tr[j+1]=tr[j];
tr[j]=temp;
}
}
}
}
I'm having trouble trying to implement a non-blocking send and receive in my code below and am getting this error:
16 Reading <edge192x128.pgm>
17 Rank 2 [Sat Apr 28 11:24:58 2018] [c6-0c0s13n1] Fatal error in PMPI_Wait: Request pending due to failure, error stack:
18 PMPI_Wait(207): MPI_Wait(request=0x7ffffff95534, status=0x7fffffff74b0) failed
19 PMPI_Wait(158): Invalid MPI_Request
20 Rank 3 [Sat Apr 28 11:24:58 2018] [c6-0c0s13n1] Fatal error in PMPI_Wait: Request pending due to failure, error stack:
21 PMPI_Wait(207): MPI_Wait(request=0x7ffffff95534, status=0x7fffffff74b0) failed
22 PMPI_Wait(158): Invalid MPI_Request
23 _pmiu_daemon(SIGCHLD): [NID 01205] [c6-0c0s13n1] [Sat Apr 28 11:24:58 2018] PE RANK 2 exit signal Aborted
24 [NID 01205] 2018-04-28 11:24:58 Apid 30656034: initiated application termination
25 Application 30656034 exit codes: 134
26 Application 30656034 resources: utime ~0s, stime ~0s, Rss ~7452, inblocks ~7926, outblocks ~19640
My program attempts to perform the following (assuming 4 processes for this example):
Root process reads in an image file as a two-dimensional array PM x PN into masterbuf;
Root process uses MPI_Issend to transfer subsections of masterbuf (PM/2 x PN/2) to all 4 processes (which includes itself). I have used a strided datatype to split the original array into 4 sections.
All processes use MPI_Irecv to store PM/2 x PN/2 subsection in their own copy of buf.
MPI_Wait is called to prevent program continuing until distribution of data is complete (I understand I could have used MPI_Waitall here, which I intend to do after I've got this working).
I've been playing with the code for hours now and just can't fix this issue so any help would be appreciated. Code is below. I've removed some non-relevant blocks.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <mpi.h>
4 #include <math.h>
5 #include "pgmio.h"
6
7 #define M 192
8 #define N 128
9
10 #define PX 2 // number of processes in X dimension
11 #define PY 2 // number of processes in Y dimension
12 #define MP M/PX
13 #define NP N/PY
14
15
16 #define FILEIN "edge192x128.pgm"
17 #define FILEOUT "ex7_0_192x128.pgm"
18
19 int main(int argc, char **argv)
20 {
21 double buf[MP][NP];
22 double old[MP + 2][NP + 2];
23 double new[MP + 2][NP + 2];
24 double edge[MP + 2][NP + 2];
25 double masterbuf[M][N];
26 double delta, delta_max, master_delta;
27
28 int rank, cart_rank, size, left, right, up, down, iter;
29 int dims[] = {2, 2};
30 int periods[] = {0, 0};
31 int reorder = 0;
32 int tag = 0;
33
34 MPI_Status status;
35 MPI_Comm comm = MPI_COMM_WORLD;
36 MPI_Comm cart_comm;
37
38 /* initialise MPI */
39 MPI_Init(&argc, &argv);
40 MPI_Comm_size(comm, &size);
41 MPI_Comm_rank(comm, &rank);
42 MPI_Request request[2 * size];
43 int coords[size][2];
44
45 /* initialise cartesian topology */
46 MPI_Cart_create(comm, 2, dims, periods, reorder, &cart_comm);
47 MPI_Comm_rank(cart_comm, &cart_rank);
48 MPI_Cart_shift(cart_comm, 1, 1, &left, &right);
49 MPI_Cart_shift(cart_comm, 0, 1, &up, &down);
50 printf("cart_rank: %d\n", cart_rank);
51
56
57 /* create block datatype for allocation of subsections of image to processes */
58 MPI_Datatype MPI_block;
59 MPI_Type_vector(M / PX, N / PY, N, MPI_DOUBLE, &MPI_block);
60 MPI_Type_commit(&MPI_block);
61
73
74 /* master process: read edges data file into masterbuff and distribute */
75 if (rank == 0)
76 {
77 printf("Reading <%s>\n", FILEIN);
78 pgmread(FILEIN, masterbuf, M, N);
79
80 printf("Distributing data to processes...\n");
81 for (int i = 0; i < size; i++)
82 {
83 /* send chunk to each process: i refers to cart_rank */
84 MPI_Cart_coords(cart_comm, i, 2, &coords[i][0]);
85 printf("coords = (%d, %d), rank = %d\n", coords[i][0], coords[i][1], \
86 cart_rank);
87 MPI_Issend(&masterbuf[coords[i][0] * MP][coords[i][1] * NP], MP * NP, \
88 MPI_block, i, tag, cart_comm, &request[i]);
89 }
90
91 MPI_Wait(&request[0], &status);
92 MPI_Wait(&request[1], &status);
93 MPI_Wait(&request[2], &status);
94 MPI_Wait(&request[3], &status);
95 }
96
97 /* all processes: receive data sent by master process */
98 MPI_Irecv(buf, MP * NP, MPI_block, cart_rank, tag, cart_comm, \
99 &request[cart_rank + size]);
100
101 /* Could change this to MPI_Waitall */
102 MPI_Wait(&request[5], &status);
103 MPI_Wait(&request[4], &status);
104 MPI_Wait(&request[7], &status);
105 MPI_Wait(&request[6], &status);
106
107 if (rank == 0)
108 {
109 printf("...complete.\n");
110 }
Your application deadlock when rank 0 send to itself and no receive was yet posted.
Also, there are 4 MPI_Wait() but a single MPI_Recv().
As a side note, you can MPI_Waitall() instead of calling several consecutive MPI_Wait().
What's wrong with this code?
My task is: Create a square matrix of integers with a size of 9x9. Fill the matrix with random numbers. Display the main and side diagonal symmetrically with respect to the vertical axis. The example of expected result is here: matrix
Matrix :
20 20 76 65 93 76 16 2 85
6 87 78 43 48 81 71 90 38
10 12 35 77 48 88 24 53 7
12 66 51 35 74 7 30 22 49
58 14 71 46 68 68 10 81 51
98 16 74 47 64 25 17 30 37
2 44 44 74 34 54 86 73 28
85 4 57 75 18 28 51 76 2
35 17 53 76 15 91 83 85 72
The main and side diagonal:
85 20 76 65 93 76 16 2 20
6 90 78 43 48 81 71 87 38
10 12 24 77 48 88 35 53 7
12 66 51 7 74 35 30 22 49
58 14 71 46 68 68 10 81 51
98 16 74 25 64 47 17 30 37
2 44 86 74 34 54 44 73 28
85 76 57 75 18 29 51 4 2
72 17 53 76 15 91 83 85 35
But in fact the program prints only the main matrix with random numbers and after that stops.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <Windows.h>
int main()
{
int a = 9;
int matrix[a][a];
int temp;
int i, j, n;
srand((unsigned)time(NULL));
printf("Matrix : \n\n");
for (i = 0; i < a; ++i) {
for (j = 0; j < a; ++j) {
matrix[i][j] = rand() % 100;
printf("%d\t", matrix[i][j]);
}
printf("\n\n");
}
printf("The main and side diagonal:\n\n");
for (i = 0; i < a; ++i) {
temp = matrix[i][i];
matrix[i][i] = matrix[i][(a - 1) - i];
matrix[i][(a - 1) - i] = temp;
}
for (i = 0; i < a; ++i) {
for (j = 0; j < a; ++j) {
printf("Result:", matrix[i][j]);
printf("\n\n\n");
system("pause");
return 0;
}
}
}
You are returning where you are not supposed to. (in middle of the calculation). You should return after you end up working on the for loops.
for (i = 0; i < a; ++i) {
for (j = 0; j < a; ++j) {
printf("Result:", matrix[i][j]); <--- Not printing element
printf("\n\n\n");
system("pause");
return 0; <-----
}
}
It should be
for (i = 0; i < a; ++i) {
for (j = 0; j < a; ++j) {
printf("Result: %d ", matrix[i][j]); <----You forgot the
//format specifier
printf("\n\n\n");
system("pause");
}
}
return 0;<-----
Readability is hampered when the indentation is like this. You implemented wrong logic out of it.
OP asks that it stops after printing "Result" that is because you forgot to put the format specifier in the code. That's why none of the element is printed.
Op wants to print the main and side diagonal symmetrically with respect to the vertical axis.
Now this is everything to with the print part.
Now we have to find a way that will let us distinguish which one is diagonal element and which one is not.
Suprisingly the answer should be known to someone who is writing the previous swapping logic. (Though it is not clear why OP swapped it).
Now all element matrix[p][q] will be from either diagonal if p=q or p+q=a-1. (Note that matrix is a square matrix).
But OP meant to print the matrix
for (i = 0; i < a; ++i) {
if( i == 0) printf("The main and side diagonal : \n");
for (j = 0; j < a; ++j) {
printf("%d\t", matrix[i][j]);
}
printf("\n");
}
}
Use functions. You print the matrix twice; you should have a function to print the matrix which you call twice.
With such a function, you'd not make the mistakes in the tail end of your code. For example, you could use this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
static void print_matrix(const char *tag, int size, int matrix[size][size])
{
printf("%s (%dx%d):\n\n", tag, size, size);
for (int i = 0; i < size; ++i)
{
const char *pad = "";
for (int j = 0; j < size; ++j)
{
printf("%s%-2d", pad, matrix[i][j]);
pad = " ";
}
printf("\n\n");
}
}
int main(int argc, char **argv)
{
unsigned seed = time(0);
int a = 9;
int matrix[a][a];
if (argc == 2)
seed = atoi(argv[1]);
srand(seed);
printf("Seed: %u\n", seed);
for (int i = 0; i < a; ++i)
{
for (int j = 0; j < a; ++j)
matrix[i][j] = rand() % 100;
}
print_matrix("Matrix", a, matrix);
for (int i = 0, j = a - 1; i < a; ++i, --j)
{
int temp = matrix[i][i];
matrix[i][i] = matrix[i][j];
matrix[i][j] = temp;
}
print_matrix("The main and side diagonal", a, matrix);
return 0;
}
The code reports the seed it uses; that allows you to reproduce any run by specifying the seed to use as a command line argument.
Example output:
Seed: 1511470282
Matrix (9x9):
11 39 3 88 98 63 75 81 76
93 9 60 22 45 50 46 58 65
13 99 25 43 14 57 44 70 65
30 57 55 0 37 84 47 49 40
60 28 46 1 96 78 33 20 9
93 61 11 38 84 16 91 26 15
43 85 66 72 85 39 96 45 45
45 25 33 3 78 90 61 65 62
88 84 56 34 74 8 78 57 74
The main and side diagonal (9x9):
76 39 3 88 98 63 75 81 11
93 58 60 22 45 50 46 9 65
13 99 44 43 14 57 25 70 65
30 57 55 84 37 0 47 49 40
60 28 46 1 96 78 33 20 9
93 61 11 16 84 38 91 26 15
43 85 96 72 85 39 66 45 45
45 65 33 3 78 90 61 25 62
74 84 56 34 74 8 78 57 88
The swapping process, in case it isn't obvious, swaps the first and last elements of the first row, the second and last but one element in the second row, and so on, forming an X of swapped elements.
I'm trying to do a partial sort with a threads,
my current output it
27 12 21 48 15 28 82 69 35 91
13 82 33 35 46 5 35 28 87 95
0 10 20 22 23 30 52 80 86 96
3 8 42 53 67 70 70 71 75 79
5 8 8 18 41 43 70 79 86 88
10 51 56 60 65 84 87 91 94 99
23 25 38 39 40 44 51 56 69 75
20 21 25 29 29 38 66 71 73 96
33 50 9 6 13 27 97 21 70 22
3 4 6 6 7 15 34 59 63 70
As you can see I am getting it partially sorted I want my output to be this (no merging at the end)
12 15 21 27 28 35 48 69 82 91
5 13 28 33 35 35 46 82 87 95
0 10 20 22 23 30 52 80 86 96
3 8 42 53 67 70 70 71 75 79
5 8 8 18 41 43 70 79 86 88
10 51 56 60 65 84 87 91 94 99
23 25 38 39 40 44 51 56 69 75
20 21 25 29 29 38 66 71 73 96
6 9 13 21 22 27 33 50 70 97
3 4 6 6 7 15 34 59 63 70
I can get the right output if instead of using a struct I use &array[i] and manually input the length
This is the code I have so far:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>
int cmpfunc(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
struct values {
int *arrayptr;
int length;
};
void *thread_fn(void *a) {
struct values *start = a;
qsort(start->arrayptr, start->length, sizeof(int), cmpfunc);
return (void*)a;
}
int main(int argc, const char *argv[]) {
FILE *fp = fopen(argv[3], "r");
FILE *fp1 = fopen("numS1.dat", "w+");
//amount of threads
int threadAmount = atoi(argv[1]);
//size of input
int numberAmount = atoi(argv[2]);
//multidimensional array
int array[threadAmount][numberAmount / threadAmount];
for (int i = 0; i < threadAmount; i++)
for (int j = 0; j < numberAmount / threadAmount; j++)
fscanf(fp, "%d", &array[i][j]);
pthread_t threadid[threadAmount];
for (int i = 0; i < threadAmount; ++i) {
struct values a = { array[i], numberAmount / threadAmount };
pthread_create(&threadid[i], NULL, thread_fn, &a);
}
for (int i = 0; i < threadAmount; ++i)
pthread_join(threadid[i], NULL);
for (int i = 0; i < threadAmount; i++) {
if (i != 0)
fprintf(fp1, "\n");
for (int j = 0; j < numberAmount / threadAmount; j++)
fprintf(fp1 ,"%d ", array[i][j]);
}
return 0;
}
Do you know where I am going wrong?
I think its the struct but everything I see online does what I'm doing.
You are passing a pointer to automatic storage to newly created threads: the struct values object becomes invalid as soon as the calling scope is exited, thus it cannot be reliably accessed by the new thread. You should allocate the struct values and pass the pointer to the allocated object as a parameter to pthread_create:
for (int i = 0; i < threadAmount; ++i) {
struct values *a = malloc(sizeof(*a));
a->arrayptr = array[i];
a->length = numberAmount / threadAmount;
pthread_create(&threadid[i], NULL, thread_fn, a);
}
The structure can be freed by the thread function before exiting.
Notes:
the way you split the array into chunks only works if the length is a multiple of the number of threads.
the comparison function does not work for large int values, you should use this instead:
int cmpfunc(const void *a, const void *b) {
return (*(int*)b < *(int*)a) - (*(int*)a < *(int*)b);
}
I'm trying to submit the solution for Spoj - Prime Intervals problem. But I'm getting a runtime error SIGXFSZ. It is given that, it occurs due to exceeded file size. I have used the Sieve of Eratosthenes algorithm to find the prime numbers. I don't understand what's wrong with my code and this is bugging me from last the 2 days. Please help me with the submission. Here is my code...
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#include<math.h>
int main(){
int t, turn;
long i, l,u,k,j;
scanf("%d", &t);
/*Looping for t test cases*/
for(turn=0; turn<t; turn++){
scanf("%ld %ld", &l, &u);
bool arr[u-l+1];
/*Assigning whole array with true*/
memset(arr, true, u-l+1);
/*Sieve of Eratosthenes logic for assigning false to composite values*/
for(i=0; i<=(int)sqrt(u)-l; i++){
k=0;
j = i+l;
if(arr[i]==true){
while((j*j + k*j) <= u){
arr[(j*j + k*j) - l] = false;
k++;
}
}
}
/*Printing all the primes in the interval*/
for(i=0; i<u-l; i++){
if(arr[i]==true){
printf("%ld\n", i+l);
}
}
}
return 0;
}
Test Input:
2
2 10
2 100
Output:
2
3
5
7
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
I ran the posted code. the results were far from correct.
Most of the numbers output are not primes and fails to check the last number is the range, as shown in the second set of results
Here are the results:
1 <-- 1 test case
20 100 <-- range 20...100
20 <-- the outputs
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Note: using 1 as the low end of the range usually results with no output produced
here is another run
The output should have been 5 7 11
1 <-- test cases
5 11 <-- range
5 <-- outputs
6
7
8
9
10
The following code does not try to minimize the size of the arr[] array, and if the upper end of the range is less than 16k then could declare the arr[] as short rather than unsigned int
The lowest valid value for the low end of the input is 2, but the code is not checking for that low limit, you might want to add that check.
The code makes no effort to minimize the number of loops executed by checking for the square root of the upper limit, you might want to add that check.
The code compiles cleanly, handles the case when the upper limit is a prime and when the lower limit is a prime as well as when the limit values are not primes.
#include <stdio.h>
#include <string.h>
#include <math.h>
int main()
{
int numTestCases, testCase;
size_t i; // index
size_t lowLimit;
size_t upperLimit;
size_t k; // offset multiplier
scanf("%d", &numTestCases);
/*Looping for t test cases*/
for(testCase=0; testCase<numTestCases; testCase++)
{
scanf("%lu %lu", (unsigned long*)&lowLimit, (unsigned long*)&upperLimit);
unsigned arr[upperLimit+1];
/*Assigning whole array to indicate entry is a prime*/
memset(arr, 0x01, upperLimit+1);
/*Sieve of Eratosthenes logic for assigning false to composite values*/
//size_t sqrtUpperLimit = (size_t)ceil(sqrt(upperLimit));
for(i=2; i<= upperLimit; i++)
{
if(arr[i])
{
if( i >= lowLimit )
{
printf("%ld\n", i);
}
for( k=2; (i*k) <= upperLimit; k++)
{
arr[(i*k)] = 0;
}
}
}
}
return 0;
} // end function; main
here is an edited version of the code, with the addition of some instrumentation in the way of prompts to the user via calls to printf()
#include <stdio.h>
#include <string.h>
#include <math.h>
int main()
{
int numTestCases, testCase;
size_t i; // index
size_t lowLimit;
size_t upperLimit;
size_t k; // offset multiplier
printf("enter number of test cases\n");
scanf("%d", &numTestCases);
/*Looping for t test cases*/
for(testCase=0; testCase<numTestCases; testCase++)
{
printf( "enter lower limit upper limit limits\n");
scanf("%lu %lu", (unsigned long*)&lowLimit, (unsigned long*)&upperLimit);
unsigned arr[upperLimit+1];
/*Assigning whole array to indicate entry is a prime*/
memset(arr, 0x01, upperLimit+1);
/*Sieve of Eratosthenes logic for assigning false to composite values*/
//size_t sqrtUpperLimit = (size_t)ceil(sqrt(upperLimit));
for(i=2; i<= upperLimit; i++)
{
if(arr[i])
{
if( i >= lowLimit )
{
printf("%ld\n", i);
}
for( k=2; (i*k) <= upperLimit; k++)
{
arr[(i*k)] = 0;
}
}
}
}
return 0;
} // end function; main
Using the above instrumented code and the input of:
5 2 3 30 31 20 27 2 3 4 5
it worked perfectly.
This was the output:
enter number of test cases
5
enter upper/lower limits
2 3
sizeof arr[]: 4
2
3
enter upper/lower limits
30 31
sizeof arr[]: 32
31
enter upper/lower limits
20 27
sizeof arr[]: 28
23
enter upper/lower limits
2 3
sizeof arr[]: 4
2
3
enter upper/lower limits
4 5
sizeof arr[]: 6
5