I am reading C The Complete Reference 4th edition by Herbert Schildt. In Chapter 4 - Arrays and Strings, it mentions "One major reason for the addition of variable-length arrays to C99 is to support numeric processing".
My question is: What is numeric processing? And how do variable-length arrays support numeric processing?
There are three places where variable-length arrays can appear:
Automatic local variables.
Dynamically allocated arrays.
Function parameters.
Automatic local variables can be problematic — they occupy stack space, and there's no portable way to find out whether there's enough stack space left to allocate the array you want to create. If there isn't enough space, the program will halt unilaterally; there is no way to recover from the error. This has many people up in arms against VLAs.
Dynamically allocated arrays are not problematic — though the notation is not singularly convenient. You can tell when an allocation fails and react appropriately.
Function parameters are where the flexibility comes into play — especially with 2D arrays (and higher dimensions too).
Prior to the introduction of VLAs, you had to either treat the array as a 1D vector and calculate the indexes manually or you had to write different functions for each different size of matrix — or, at least, for each different number of columns.
You could use:
enum { NCOLS = 8 };
static void dump_array(const char *tag, size_t nrows, int array[][NCOLS])
{
printf("%s: (%zux%d)\n", tag, nrows, NCOLS); // Note %zu vs %d!
for (size_t r = 0; r < nrows; r++)
{
for (size_t c = 0; c < NCOLS; c++)
printf(" %5d", array[r][c]);
putchar('\n');
}
}
That's fine as far as it goes, but if you want matrices with different numbers of columns, you have to write (and call) different functions.
An alternative was to use a large 1D vector and calculate the 2D subscripts in your code:
static void dump_array(const char *tag, size_t nrows, size_t ncols, int array[])
{
printf("%s: (%zux%zu)\n", tag, nrows, ncols);
for (size_t r = 0; r < nrows; r++)
{
for (size_t c = 0; c < ncols; c++)
printf(" %5d", array[r * ncols + c]);
putchar('\n');
}
}
With VLA notation for the arguments, though, you can write a single function to print any 2D matrix (of a given base type) and use direct subscript notation for maximum convenience:
static void dump_array(const char *tag, size_t nrows, size_t ncols, int array[nrows][ncols])
{
printf("%s: (%zux%zu)\n", tag, nrows, ncols);
for (size_t r = 0; r < nrows; r++)
{
for (size_t c = 0; c < ncols; c++)
printf(" %5d", array[r][c]);
putchar('\n');
}
}
There isn't much difference in the notation, but the gain in flexibility is enormous. You can write a single matrix multiplication function that will work for any sizes of matrix, for example, whereas before VLAs were available, only the 1D version could deal with arbitrary sizes of array.
The dynamic allocation is reasonably simple, though not entirely obvious:
/* SO 7531-3779 */
#include <stdio.h>
#include <stdlib.h>
static void dump_array(const char *tag, size_t rows, size_t cols, int array[rows][cols])
{
printf("%s (%zux%zu):\n", tag, rows, cols);
for (size_t r = 0; r < rows; r++)
{
printf("%2zu:", r);
for (size_t c = 0; c < cols; c++)
printf(" %5d", array[r][c]);
putchar('\n');
}
}
int main(void)
{
size_t rows = 13;
size_t cols = 8;
int (*array)[8] = malloc(sizeof(int [rows][cols]));
for (size_t r = 0; r < rows; r++)
{
int sign = -1;
for (size_t c = 0; c < cols; c++)
{
array[r][c] = sign * ((r + 1) * 100 + c + 1);
sign = -sign;
}
}
dump_array("Array 1", rows, cols, array);
free(array);
return 0;
}
Output:
Array 1 (13x8):
0: -101 102 -103 104 -105 106 -107 108
1: -201 202 -203 204 -205 206 -207 208
2: -301 302 -303 304 -305 306 -307 308
3: -401 402 -403 404 -405 406 -407 408
4: -501 502 -503 504 -505 506 -507 508
5: -601 602 -603 604 -605 606 -607 608
6: -701 702 -703 704 -705 706 -707 708
7: -801 802 -803 804 -805 806 -807 808
8: -901 902 -903 904 -905 906 -907 908
9: -1001 1002 -1003 1004 -1005 1006 -1007 1008
10: -1101 1102 -1103 1104 -1105 1106 -1107 1108
11: -1201 1202 -1203 1204 -1205 1206 -1207 1208
12: -1301 1302 -1303 1304 -1305 1306 -1307 1308
And the VLA notation can be used with fixed-size arrays — global or local — too. That is, ordinary arrays can be passed to functions that accept a VLA as long as you describe the arrays accurately:
/* SO 7531-3779 */
#include <stdio.h>
#include <stdlib.h>
static void dump_array(const char *tag, size_t rows, size_t cols, int array[rows][cols])
{
printf("%s (%zux%zu):\n", tag, rows, cols);
for (size_t r = 0; r < rows; r++)
{
printf("%2zu:", r);
for (size_t c = 0; c < cols; c++)
printf(" %5d", array[r][c]);
putchar('\n');
}
}
/* Created by: gen_matrix -r 9 -c 5 -L -9999 -H +9999 -x -n matrix1 -w5 -E */
/* Random seed: 0x7F3F1FA0 */
int matrix1[9][5] =
{
{ 9337, 5320, 5059, 1115, 14, },
{ -7514, -1643, 8461, 1613, 6968, },
{ 2469, 8307, -8045, 2327, -7862, },
{ 8174, -7062, 666, -3480, 1836, },
{ -2400, -7863, -1859, 2436, -6840, },
{ 5819, -4112, -2037, 9005, -9748, },
{ 823, -9687, 1245, -2074, 3741, },
{ 4812, -9254, -6365, -1263, -9265, },
{ -9400, -5479, -3756, -7417, -5726, },
};
enum { MATRIX1_ROWS = 9, MATRIX1_COLS = 5 };
int main(void)
{
/* Created by: gen_matrix -E -r 13 -c 8 -H 999 -L -999 -i -w4 -n matrix2 */
/* Random seed: 0x64347CFE */
int matrix2[13][8] =
{
{ -27, -268, 73, 112, -148, 407, -411, 418, },
{ -782, 368, -306, -830, -851, 9, 505, 33, },
{ -558, -979, 471, 376, -290, -270, -910, 812, },
{ -374, 201, 454, 966, -39, 653, -747, -664, },
{ 322, 385, -141, -326, 37, 941, -298, -281, },
{ 529, 68, -995, -30, -942, -670, 563, -244, },
{ 773, 46, -315, -363, 732, 218, 230, 536, },
{ 566, -164, -493, 568, -256, -196, -635, -387, },
{ 452, -348, 79, 103, -416, -756, 688, -473, },
{ -294, -641, 530, -307, 508, 878, -786, -745, },
{ 427, 462, -229, 253, 116, -804, -72, -35, },
{ -776, 290, 158, 154, 662, -621, 576, 388, },
{ 999, -684, -207, -506, 708, -949, 149, -969, },
};
enum { MATRIX2_ROWS = 13, MATRIX2_COLS = 8 };
dump_array("Matrix 1", MATRIX1_ROWS, MATRIX1_COLS, matrix1);
dump_array("Matrix 2", MATRIX2_ROWS, MATRIX2_COLS, matrix2);
return 0;
}
Output:
Matrix 1 (9x5):
0: 9337 5320 5059 1115 14
1: -7514 -1643 8461 1613 6968
2: 2469 8307 -8045 2327 -7862
3: 8174 -7062 666 -3480 1836
4: -2400 -7863 -1859 2436 -6840
5: 5819 -4112 -2037 9005 -9748
6: 823 -9687 1245 -2074 3741
7: 4812 -9254 -6365 -1263 -9265
8: -9400 -5479 -3756 -7417 -5726
Matrix 2 (13x8):
0: -27 -268 73 112 -148 407 -411 418
1: -782 368 -306 -830 -851 9 505 33
2: -558 -979 471 376 -290 -270 -910 812
3: -374 201 454 966 -39 653 -747 -664
4: 322 385 -141 -326 37 941 -298 -281
5: 529 68 -995 -30 -942 -670 563 -244
6: 773 46 -315 -363 732 218 230 536
7: 566 -164 -493 568 -256 -196 -635 -387
8: 452 -348 79 103 -416 -756 688 -473
9: -294 -641 530 -307 508 878 -786 -745
10: 427 462 -229 253 116 -804 -72 -35
11: -776 290 158 154 662 -621 576 388
12: 999 -684 -207 -506 708 -949 149 -969
Related
Well I posted this before but it's kinda improved now, and I only have one problem (I guess).
The assignment was to write a function which reads an integer matrix given in a ‘.txt file’ using
I/O redirection, then write another function to print it.
I read txt into a 1D array (arr) then create 2D matrix (mat) out of it, before those, I allocated memory dynamically bc our professor asked to do it that way. The problem is that arr seems to be changing when I put it on for loop and try to address it for the matrix. I would appreciate any ideas... Also, it would be helpful if you guys can comment on my way of allocating memory. (Don't forget we have 3 different input.txts some of them has -5.58234 like values or they are not seperated by "," in this example, so I want to make my code usable in any cases)
example txt file:
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int readMatrix(int *arr, int **mat);
void printMatrix(int **mat, int size);
int main(){
// declare 1D array and allocate memory
int *arr;
arr = malloc(sizeof(stdin)*sizeof(int));
// declare 2D Matrix and allocate memory
int **mat;
mat = (int **)malloc(sizeof(stdin)*sizeof(int));
// function implementations
int size;
size = readMatrix(arr, mat);
printMatrix(mat,size);
return 0;
}
int readMatrix(int *arr, int **mat){
// reading
int i=0, size=0; // loop var i and size to count the elements of array
while(scanf("%d,", &arr[i]) != EOF)
{
i++;
size++;
}
printf("arr[63] = %d \n\n",arr[63]); // VALUE IS CORRECT HERE
// finding row and column numbers
int rows = sqrt(size), cols = rows;
// appending 1d array into matrix
int m = 0;
// test printf("rows = %d, cols = %d\n", rows, cols);
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
printf("arr[%d] = %d\n",m, arr[m]); // VALUES OF arr[] BECAME WEIRD AFTER arr[12]
//mat[i][j] = arr[m]; // segmentation fault
//*(*(mat+i)+j) = arr[m]; // segmentation fault
//*(*(mat+i)+j) = &arr[m]; // segmentation fault
*(mat + i*cols + j) = &arr[m]; // I don't know if this is the proper way but it works
m++;
}
}
printf("\narr[63] = %d\n",arr[63]); // HOWWWWW
// return size for further implementations
//
return size;
}
void printMatrix(int **mat, int size){
int rows = sqrt(size), cols = rows;
printf("\nMATRIX A:\n");
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++)
{
printf("%d ", mat[i][j]);
//if(mat[i][j]>=10 && mat[i][j]<100 ){printf("%d ", mat[i][j]);}
//else if(mat[i][j]>=100 ){printf("%d ", mat[i][j]);}
//else{printf("%d ", mat[i][j]);}
}
printf("\n");
}
}
output:
$ ./secondtry < input1.txt
arr[63] = 99
arr[0] = 16
arr[1] = 11
arr[2] = 10
arr[3] = 16
arr[4] = 24
arr[5] = 40
arr[6] = 51
arr[7] = 61
arr[8] = 12
arr[9] = 12
arr[10] = 14
arr[11] = 19
arr[12] = 976
arr[13] = 8
arr[14] = 980
arr[15] = 8
arr[16] = 984
arr[17] = 8
arr[18] = 988
arr[19] = 8
arr[20] = 992
arr[21] = 8
arr[22] = 996
arr[23] = 8
arr[24] = 1000
arr[25] = 8
arr[26] = 1004
arr[27] = 8
arr[28] = 1008
arr[29] = 8
arr[30] = 1012
arr[31] = 8
arr[32] = 1016
arr[33] = 8
arr[34] = 1020
arr[35] = 8
arr[36] = 1024
arr[37] = 8
arr[38] = 1028
arr[39] = 8
arr[40] = 1032
arr[41] = 8
arr[42] = 1036
arr[43] = 8
arr[44] = 1040
arr[45] = 8
arr[46] = 1044
arr[47] = 8
arr[48] = 1048
arr[49] = 8
arr[50] = 1052
arr[51] = 8
arr[52] = 1056
arr[53] = 8
arr[54] = 1060
arr[55] = 8
arr[56] = 1064
arr[57] = 8
arr[58] = 1068
arr[59] = 8
arr[60] = 1072
arr[61] = 8
arr[62] = 1076
arr[63] = 8
arr[63] = 8
MATRIX A:
16 11 10 16 24 40 51 61
11 10 16 24 40 51 61 12
10 16 24 40 51 61 12 12
16 24 40 51 61 12 12 14
24 40 51 61 12 12 14 19
40 51 61 12 12 14 19 976
51 61 12 12 14 19 976 8
61 12 12 14 19 976 8 980
Because we're reading from stdin, we can not do simple things like:
read/parse the first to determine number of columns
rewind file
read/parse all lines and store in matrix (allocating space as we go)
Note that using sqrt on the count to get number of rows/columns is a bit "unique". This is the first time I've seen that done.
When handling a 2D matrix that has dynamic dimensions, it helps to define a control struct to be able to store the dimensions. Then, all relevant info for the matrix is available to everyone.
In general, I really prefer fgets/strtok/strtol over scanf.
In this use case, I'm not sure if scanf("%d,",&val) can parse both (e.g.) 103, and 99. That is, the last number of the input file has no comma after it.
So, I had to refactor the code quite a bit. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
printf(_fmt)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
// matrix control
typedef struct {
int mtx_cols; // number of columns
int mtx_rows; // number of rows (input lines)
int *mtx_base; // pointer to matrix data
} mtx_t;
// helper macro to access a given matrix coordinate
#define MTX(_mtx,_irow,_icol) \
_mtx->mtx_base[((_irow) * _mtx->mtx_cols) + _icol]
// newMatrix -- get new matrix control
mtx_t *
newMatrix(void)
{
mtx_t *mtx;
mtx = calloc(1,sizeof(*mtx));
return mtx;
}
// readMatrix -- read in matrix from stream
void
readMatrix(mtx_t *mtx,FILE *xfin)
{
char *bp;
char *cp;
char buf[1000];
// get first line as a special case to calculate the number of columns
fgets(buf,sizeof(buf),xfin);
// we need to preserve the original data for the second loop below
char tmp[1000];
strcpy(tmp,buf);
// calculate number of columns
bp = tmp;
while (1) {
char *cp = strtok(bp," ,\n");
bp = NULL;
if (cp == NULL)
break;
mtx->mtx_cols += 1;
}
// read in row by row
while (1) {
// get current row index and advance the row count
int irow = mtx->mtx_rows++;
dbgprt("BUF/%d: %s",irow,buf);
// add space for this row
mtx->mtx_base = realloc(mtx->mtx_base,
sizeof(*mtx->mtx_base) * mtx->mtx_rows * mtx->mtx_cols);
if (mtx->mtx_base == NULL) {
perror("realloc");
exit(2);
}
// parse this row
bp = buf;
for (int icol = 0; icol < mtx->mtx_cols; ++icol) {
char *cp = strtok(bp," ,\n");
bp = NULL;
if (cp == NULL)
break;
MTX(mtx,irow,icol) = strtol(cp,&cp,10);
dbgprt(" %d\n",MTX(mtx,irow,icol));
}
// get data for next row
if (fgets(buf,sizeof(buf),xfin) == NULL)
break;
}
}
void
printMatrix(const mtx_t *mtx)
{
printf("\nMATRIX A:\n");
for (int irow = 0; irow < mtx->mtx_rows; ++irow) {
for (int icol = 0; icol < mtx->mtx_cols; ++icol)
printf(" %d",MTX(mtx,irow,icol));
printf("\n");
}
}
int
main(int argc,char **argv)
{
--argc;
++argv;
FILE *xfin;
if (argc > 0)
xfin = fopen(*argv,"r");
else
xfin = stdin;
if (xfin == NULL)
exit(1);
// declare 1D array and allocate memory
mtx_t *mtx = newMatrix();
readMatrix(mtx,xfin);
printMatrix(mtx);
return 0;
}
CODE
#include<stdio.h>
#include<string.h>
void worst_fit(int space[],int requests[],int m,int n)
{
int cp[m];
int i,j;
for(i=0;i<m;i++)
cp[i]=space[i];
int allocation[n];
memset(allocation,-1,sizeof(allocation));
int check[m];
for(i=0;i<n;i++)
{
memset(check,0,sizeof(check));
int max=-1;
for(j=0;j<m;j++)
{
if(requests[i]<=space[j])
{
check[j]=1;
if(max==-1)
max=j;
}
}
//printf("%d \n",requests[i]);
for(j=0;j<m;j++)
{
if(check[j]!=0)
{
if(space[j]>space[max])
max=j;
}
}
//printf("%d \n",requests[i]);
allocation[i]=cp[max];//copy of space should done: pending
printf("%d %d -\n",requests[i],space[max]);
space[max]=space[max]-requests[i];
printf("%d %d\n",requests[i],space[max]);
}
printf("\nProcess No.\tProcess Size\tBlock no.\n");
for (int i = 0; i < n; i++)
{
//printf("%d\n",requests[i]);
printf("%d \t\t%d \t\t",i+1,requests[i]);
if (allocation[i] != -1)
printf("%d \n",allocation[i]);
else
printf("Not Allocated \n");
}
}
int main()
{
int i;
int s[]={100, 500, 200, 300, 600};
int r[]={212, 417, 112, 426};
int m = sizeof(s) / sizeof(s[0]);
int n = sizeof(r) / sizeof(r[0]);
worst_fit(s,r,m,n);
}
The output is showing an unexpected error due to the below snippet
printf("%d %d -\n",requests[i],space[max]);
space[max]=space[max]-requests[i];
printf("%d %d\n",requests[i],space[max]);
OUTPUT for the above will be
212 600 -
212 388
417 500 -
417 83
112 388 -
112 276
426 426 -
0 0
I don't understand how 426 which is stored in requests[i] is reduced to 0.
The complete output is
212 600 -
212 388
417 500 -
417 83
112 388 -
112 276
426 426 -
0 0
Process No. Process Size Block no.
1 212 600
2 417 500
3 112 600
4 0 Not Allocated
I am new to multithreaded programming and so I thought I would work on a project to help me learn it. Here are the details of the project:
Write a multithreaded sorting program in c that works as follows: A list of integers is divided into two smaller lists of equal size. Two separate threads (which we will term sorting threads) sort each sublist using a sorting algorithm of your choice. The two sublists are then merged by a third thread - a merging thread - which merges the two sublists into a single sorted list.
//Sort a list of numbers using two separate threads
//by sorting half of each list separately then
//recombining the lists
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
#define NUMBER_OF_THREADS 3
void *sorter(void *params); /* thread that performs basic sorting algorithm */
void *merger(void *params); /* thread that performs merging of results */
int list[SIZE] = {7,12,19,3,18,4,2,6,15,8};
int result[SIZE];
typedef struct
{
int from_index;
int to_index;
} parameters;
int main (int argc, const char * argv[])
{
int i;
pthread_t workers[NUMBER_OF_THREADS];
/* establish the first sorting thread */
parameters *data = (parameters *) malloc (sizeof(parameters));
data->from_index = 0;
data->to_index = (SIZE/2) - 1;
pthread_create(&workers[0], 0, sorter, data);
/* establish the second sorting thread */
data = (parameters *) malloc (sizeof(parameters));
data->from_index = (SIZE/2);
data->to_index = SIZE - 1;
pthread_create(&workers[1], 0, sorter, data);
/* now wait for the 2 sorting threads to finish */
for (i = 0; i < NUMBER_OF_THREADS - 1; i++)
pthread_join(workers[i], NULL);
/* establish the merge thread */
data = (parameters *) malloc(sizeof(parameters));
data->from_index = 0;
data->to_index = (SIZE/2);
pthread_create(&workers[2], 0, merger, data);
/* wait for the merge thread to finish */
pthread_join(workers[2], NULL);
/* output the sorted array */
return 0;
}
void *sorter(void *params)
{
parameters* p = (parameters *)params;
//SORT
int begin = p->from_index;
int end = p->to_index+1;
int z;
for(z = begin; z < end; z++){
printf("The array recieved is: %d\n", list[z]);
}
printf("\n");
int i,j,t,k;
for(i=begin; i< end; i++)
{
for(j=begin; j< end-i-1; j++)
{
if(list[j] > list[j+1])
{
t = list[j];
list[j] = list[j+1];
list[j+1] = t;
}
}
}
for(k = begin; k< end; k++){
printf("The sorted array: %d\n", list[k]);
}
int x;
for(x=begin; x<end; x++)
{
list[x] = result[x];
}
printf("\n");
pthread_exit(0);
}
void *merger(void *params)
{
parameters* p = (parameters *)params;
//MERGE
int begin = p->from_index;
int end = p->to_index+1;
int i,j,t;
printf("list[1]: %d",list[1]);
printf("result[1]: %d",result[1]);
for(i=begin; i< end; i++)
{
for(j=begin; j< end-i; j++)
{
if(result[j] > result[j+1])
{
t = result[j];
result[j] = result[j+1];
result[j+1] = t;
}
}
}
int d;
for(d=0; d<SIZE; d++)
{
printf("The final resulting array is: %d\n", result[d]);
}
pthread_exit(0);
}
I'm not sure what I'm doing wrong in my algorithms that its not working. It doesn't seem to catch the new sorted array. Any help on this problem would be appreciated VERY much! Thanks again in advance for all your help!
Your approach is incorrect. You should be splitting your partitions, then recursing or threading into them, joining the results, then merging. Its easy to screw this algorithm up, believe me.
Before anything else, make sure your merge algorithm is solid. If your merge has issues in a single-threaded arena, adding threads is only going to make it worse. In your case, you're making it worse because your merge thread appears to be running concurrently with your sorter threads.
That said, step back and consider this. Mergesort is about divide and conquer. To thread up a merge sort you should be doing the following:
Establish a maximum number of threads. Believe me, the last thing you want happening is spinning a thread for each partition. a sequence of 1024 values has 1023 partitions if you crunch the math hard enough. that many threads is not a solution. Establish some boundaries.
Establish a minimum partition size that you're willing to spin a thread for. This is as important as the first item above. Just like you don't want to be spinning 1023 threads to sort a 1024-slot sequence, you also don't want to be spinning a thread just to sort a sequence that has two items. There is zero benefit and much cost.
Have a solid merge algorithm. There are many efficient ways to do it, but do something simple and enhance it later. Right now we're just interested in getting the general threading down right. There is always time to enhance this with a fancy merge algorithm (like in-place, which believe me is harder than it sounds).
Having the above the idea is this:
The merge sort algorithm will have three parameters: a starting pointer, a length, and a thread-depth. For our purposes the thread depth will be N in a situation where we are using at-most 2N-1 threads. (more on that later, but trust me, it makes it easier to do the math this way).
If the thread depth has reached zero OR the sequence length is below a minimum threshold *we set), do not setup and run a new thread. Just recurse into our function again.
Otherwise, split the partition. Setup a structure that holds a partition definition (which for us will be a starting point and a length as well as the thread depth which will be N/2), launch a thread with that parameter block, then do NOT launch another thread. instead use the current thread to recurse into merge_sort_mt() for the "other" half.
Once the current thread returns from its recursion is must wait on the other thread via a join. once that is done both partitions will be done and they can be merged using your trivial merge algorithm.
Whew. Ok. so how does it look in practice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
struct Params
{
int *start;
size_t len;
int depth;
};
// only used for synchronizing stdout from overlap.
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
// forward declare our thread proc
void *merge_sort_thread(void *pv);
// a simple merge algorithm. there are *several* more efficient ways
// of doing this, but the purpose of this exercise is to establish
// merge-threading, so we stick with simple for now.
void merge(int *start, int *mid, int *end)
{
int *res = malloc((end - start)*sizeof(*res));
int *lhs = start, *rhs = mid, *dst = res;
while (lhs != mid && rhs != end)
*dst++ = (*lhs < *rhs) ? *lhs++ : *rhs++;
while (lhs != mid)
*dst++ = *lhs++;
// copy results
memcpy(start, res, (rhs - start) * sizeof *res);
free(res);
}
// our multi-threaded entry point.
void merge_sort_mt(int *start, size_t len, int depth)
{
if (len < 2)
return;
if (depth <= 0 || len < 4)
{
merge_sort_mt(start, len/2, 0);
merge_sort_mt(start+len/2, len-len/2, 0);
}
else
{
struct Params params = { start, len/2, depth/2 };
pthread_t thrd;
pthread_mutex_lock(&mtx);
printf("Starting subthread...\n");
pthread_mutex_unlock(&mtx);
// create our thread
pthread_create(&thrd, NULL, merge_sort_thread, ¶ms);
// recurse into our top-end parition
merge_sort_mt(start+len/2, len-len/2, depth/2);
// join on the launched thread
pthread_join(thrd, NULL);
pthread_mutex_lock(&mtx);
printf("Finished subthread.\n");
pthread_mutex_unlock(&mtx);
}
// merge the partitions.
merge(start, start+len/2, start+len);
}
// our thread-proc that invokes merge_sort. this just passes the
// given parameters off to our merge_sort algorithm
void *merge_sort_thread(void *pv)
{
struct Params *params = pv;
merge_sort_mt(params->start, params->len, params->depth);
return pv;
}
// public-facing api
void merge_sort(int *start, size_t len)
{
merge_sort_mt(start, len, 4); // 4 is a nice number, will use 7 threads.
}
int main()
{
static const unsigned int N = 2048;
int *data = malloc(N * sizeof(*data));
unsigned int i;
srand((unsigned)time(0));
for (i=0; i<N; ++i)
{
data[i] = rand() % 1024;
printf("%4d ", data[i]);
if ((i+1)%8 == 0)
printf("\n");
}
printf("\n");
// invoke our multi-threaded merge-sort
merge_sort(data, N);
for (i=0; i<N; ++i)
{
printf("%4d ", data[i]);
if ((i+1)%8 == 0)
printf("\n");
}
printf("\n");
free(data);
return 0;
}
The output for this looks something like this:
825 405 691 290 900 715 125 969
534 809 783 820 933 895 310 687
152 19 659 856 46 765 497 371
339 660 297 509 152 796 230 465
502 948 278 317 144 941 195 208
617 428 118 505 719 161 53 292
....
994 154 745 666 590 356 894 741
881 129 439 237 83 181 33 310
549 484 12 524 753 820 443 275
17 731 825 709 725 663 647 257
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
0 0 1 1 1 2 3 3
5 5 5 5 6 6 7 7
7 7 7 8 8 10 10 11
11 11 12 12 12 13 14 14
15 15 15 15 16 17 17 17
17 18 18 19 19 19 20 21
21 21 22 22 23 24 24 24
25 25 25 26 26 28 28 29
29 29 30 30 30 30 30 31
....
994 995 996 998 1000 1001 1001 1003
1003 1003 1003 1004 1004 1005 1007 1007
1010 1010 1010 1010 1011 1012 1012 1012
1012 1013 1013 1013 1015 1015 1016 1016
1016 1017 1018 1019 1019 1019 1020 1020
1020 1021 1021 1021 1021 1022 1023 1023
The most important part of this is the limiters that keep us from going thread-wild (which is easy to accidentally do with recursive threaded algorithms), and the join of the threads before merging their content with the other half of the partition (which we sorted on our thread, and may also have done the same thing).
It's a fun exercise, and I hope you got something out of it. Best of luck.
Update: Integrating qsort()
An interesting task would be performing this functionality using qsort() for sorting the smaller partitions or once the thread pool reaches exhaustion. qsort() is a pretty big hammer to bring to this party, and as such you're going to want to raise the minimum partition size to something respectful (in the example below, we use 256 elements).
So what would it take to integrate qsort() the the sub partitions rather than a hand-rolled merge-sort? Surprisingly, not much. Start with a qsort() compatible comparator:
// comparator for qsort
int cmp_proc(const void *arg1, const void* arg2)
{
const int *lhs = arg1;
const int *rhs = arg2;
return (*lhs < *rhs) ? -1 : (*rhs < *lhs ? 1 : 0);
}
Pretty brain-dead. Now, modify the mt-wrapper to look something like this:
// our multi-threaded entry point.
void merge_sort_mt(int *start, size_t len, int depth)
{
if (len < 2)
return;
// invoke qsort on the partition. no need for merge
if (depth <= 0 || len <= 256)
{
qsort(start, len, sizeof(*start), cmp_proc);
return;
}
struct Params params = { start, len/2, depth/2 };
pthread_t thrd;
pthread_mutex_lock(&mtx);
printf("Starting subthread...\n");
pthread_mutex_unlock(&mtx);
// create our thread
pthread_create(&thrd, NULL, merge_sort_thread, ¶ms);
// recurse into our top-end parition
merge_sort_mt(start+len/2, len-len/2, depth/2);
// join on the launched thread
pthread_join(thrd, NULL);
pthread_mutex_lock(&mtx);
printf("Finished subthread.\n");
pthread_mutex_unlock(&mtx);
// merge the paritions.
merge(start, start+len/2, start+len);
}
That's it. Seriously. That is all it takes. Proving this works is a simple test run with the original program, shown below:
986 774 60 596 832 171 659 753
638 680 973 352 340 221 836 390
930 38 564 277 544 785 795 451
94 602 724 154 752 381 433 990
539 587 194 963 558 797 800 355
420 376 501 429 203 470 670 683
....
216 748 534 482 217 178 541 242
118 421 457 810 14 544 100 388
291 29 562 718 534 243 322 187
502 203 912 717 1018 749 742 430
172 831 341 331 914 866 931 368
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Starting subthread...
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
Finished subthread.
0 0 1 1 1 1 3 3
3 4 5 5 6 6 6 6
7 7 8 9 10 10 10 10
11 12 12 12 13 13 14 14
14 15 15 15 16 17 17 19
19 20 20 21 21 21 22 22
23 23 23 24 24 24 25 26
26 26 26 27 28 28 28 28
....
1000 1000 1000 1001 1001 1002 1003 1003
1004 1004 1004 1005 1005 1005 1006 1007
1008 1010 1010 1010 1010 1010 1011 1011
1011 1012 1012 1012 1012 1013 1013 1013
1015 1015 1015 1016 1016 1017 1017 1017
1018 1018 1018 1019 1019 1021 1021 1022
As you can see, the results are similar.
A couple of issues:
1 - What do you think this code is doing:
int x;
for(x=begin; x<end; x++)
{
list[x] = result[x];
}
2 - Your merger currently looks exactly like your sorter. It should instead be merging the sorted values from the first half of the list and the second half of the list into the result.
Your code is correct i have modified your code and tried to figure out the error,
the loop indexes are not correctly mapped and you are assigning the null result list into actual data in one loop, so the list is taking zeroes.
Find below the modified code and output.
//Sort a list of numbers using two separate threads
//by sorting half of each list separately then
//recombining the lists
void *sort(void *params)
{
parameters* p = (parameters *)params;
//SORT
int begin = p->fromVal;
int end = p->toVal+1;
for(int i = begin; i < end; i++){
printf("The array recieved is: %d\n", list[i]);
}
printf("\n");
int temp=0;
for(int i=begin; i< end; i++)
{
for(int j=begin; j< end-1; j++)
{
if(list[j] > list[j+1])
{
temp = list[j];
list[j] = list[j+1];
list[j+1] = temp;
}
}
}
for(int k = begin; k< end; k++){
printf("The sorted array: %d\n", list[k]);
}
for(int i=begin; i<end; i++)
{
result[i] = list[i];
}
printf("\n");
pthread_exit(NULL);
}
void *merging(void *params)
{
parameters* p = (parameters *)params;
//MERGE
int begin = p->fromVal;
int end = p->toVal+1;
int temp;
for(int i=begin; i< end; i++)
{
for(int j=begin; j< end-1; j++)
{
if(result[j] > result[j+1])
{
temp= result[j];
result[j] = result[j+1];
result[j+1] = temp;
}
}
}
printf("\n\nFINAL RESULT IS:\n");
for(int d=begin+1; d<end; d++)
{
printf("The final resulting array is: %d\n", result[d]);
}
pthread_exit(NULL);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
/*globle variables*/
/* structure for passing data to threads */
typedef struct
{
int *start;
int end;
int size;
} parameters;
int t = 1;
int *arr1, *arr2;
//for using quicksort
int comparator (const void * a, const void * b) {
return ( *(int*)a - *(int*)b );
}
void *merge(void *params){
//get data
int *len = params;
//SORT
int start = 0;
int end = *len/2;
int counter = end;
int size = *len;
int index = 0;
while (start < end && counter < size)
{
if (arr1[start] < arr1[counter])
{
arr2[index] = arr1[start];
start ++;
}
else
{
arr2[index] = arr1[counter];
counter ++;
}
index ++;
}
/* Copy the remaining elements , if there
are any */
while ( start < end)
{
arr2[index] = arr1[start];
start ++;
index ++;
}
/* Copy the remaining elements , if there
are any */
while ( counter < size)
{
arr2[index] = arr1[counter];
counter ++;
index ++;
}
}
void *sorting_thread(void *params){
printf("Thread %d ......\n", t);
t++;
//get data
parameters* data = (parameters *)params;
//SORT
int end = data->end;
int size = data->size;
//qsort
qsort(data->start, end, sizeof(*data->start), comparator);
printf("The array after sort : \n");
for(int i = size - end; i < size; i ++){
printf("arr1[%d]:%d, \n", i,arr1[i]);
}
printf("\n");
pthread_exit(0);
}
void *merge_sort_thread(void *params){
int *len = params;
//varaible allocation for two sorting threads.
parameters *data = (parameters *) malloc (sizeof(parameters));
parameters *data1 = (parameters *) malloc (sizeof(parameters));
if(data == NULL&& data1 == NULL){
printf("Memory not allocated. \n");
exit(0);
}
//value for data passing
data->start= arr1;
data->end = *len/2;
data->size = *len/2;
data1->start = arr1 + *len/2;
data1->end = *len-*len/2;
data1->size = *len;
pthread_t left, right;/* the thread identifier */
printf("Entering merge_Sorting..\n");
/* create the sorting thread */
pthread_create(&left, NULL, sorting_thread, data);
pthread_create(&right, NULL, sorting_thread, data1);
/* wait for the thread to exit */
pthread_join(left, NULL);
//free memory
free(data);
pthread_join(right, NULL);
printf("Merging Thread %d ......\n", t);
merge(len);
printf("Process is done.\n");
printf("The final output: \n");
for(int i = 0; i < *len; i ++){
if(i%10==0){
printf("\n");
}
printf("%d, ", arr2[i]);
}
printf("\n");
//free memory
free(data1);
pthread_exit(0);
}
int main( int argc, char *argv[] ) {
long len;
int temp, c, j, k;
char *ptr;
//
//check if the right amount of argument
if( argc == 2 ) {
printf("The input array size is %s\n", argv[1]);
//covert the user input to integer
len = strtol(argv[1], &ptr, 10);
//check if the input is valid.
if(len == 0) {//if not, leave the program.
printf("Please enter a proper number. Leaving the program...\n");
}else{
//dynamically allocate memory
arr1 = (int*)malloc(len * sizeof(int));
arr2 = (int*)malloc(len * sizeof(int));
//check Memory
if(arr1 == NULL && arr2 == NULL){
printf("Memory not allocated. \n");
exit(0);
}
printf("Memory allocated. \n");
//decide the value of data.
//generate random number to 100
srand(time(0));
printf("The array before sorting is: \n");
for(int i = 0; i < len; i ++){
arr1[i] = rand() % 100;
if(i%10==0){
printf("\n");
}
printf("%d, ", arr1[i]);
}
printf(" \n");
//merge sort handle all the threads
pthread_t tid;/* the thread identifier */
/* create the parent sorting thread */
pthread_create(&tid, NULL, merge_sort_thread, &len);
//wait for children thread
pthread_join(tid, NULL);
//printout array after merging threading
printf("\nThe program is finished. \n");
//free memory space
free(arr2);
free(arr1);
}
}
else if( argc > 2 ) {
printf("Too many arguments supplied.\n");
}
else {
printf("One argument expected.\n");
}
return 0;
}
I'm trying to populate a structure in a mex function. I have the basics of the structure created in the mexFunction, but its getting a little confusing when a field in the structure is an array and i want to populate each element in this array as the 'for' loop iterates.
....
mxArray *value;
mwSize dims[2] = {16,8};
int numFields = 2;
const char *fieldNames[] = {"array1", "array2"};
plhs[2] = mxCreateStructArray(2, dims, numFields, fieldNames);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 8; j ++)
{
value1 = (some calculation);
value = mxCreateDoubleMatrix(1,18,mxREAL);
*mxGetPr(value[sampleIndex]) = value1;
mxSetField(plhs[2], i, "array1", value);
// i want to set the array1[j] element
value2 = (some other calculation);
value = mxCreateDoubleMatrix(1,8,mxREAL);
*mxGetPr(value) = value2;
mxSetField(plhs[2], i, "array2", value);
}
}
....
The fields "array1" and "array2" are both vectors of the same size (lets say 8 elements) i am not sure how to populate each individual element. How do i set the field name by array index 'j'.
To aid in the explanation, this is how the structure should look:
structure is an array of 16 elements, each element has 2 fields, each field has 8 elements each
structure(0).array1 = [1 2 3 4 5 6 7 8];
structure(0).array2 = [11 12 13 14 15 16 17 18];
structure(1).array1 = [21 22 23 24 25 26 27 28];
structure(1).array2 = [211 212 213 214 215 216 217 218];
structure(2).array1 = [31 32 33 34 35 36 37 38];
structure(2).array2 = [311 312 313 314 315 316 317 318];
structure(3).array1 = [41 42 43 44 45 46 47 48];
structure(3).array2 = [411 412 413 414 415 416 417 418];
...
The values are just arbitrary.
Consider the following C code:
structArrayMEX.c
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mxArray *x, *y;
double *xData, *yData;
mwIndex idx, i;
int counter = 1;
// create a 16x1 structure array, each with two fields x and y
const char *fieldNames[] = {"x", "y"};
mxArray *s = mxCreateStructMatrix(16, 1, 2, fieldNames);
// fill structure array
for (idx=0; idx<16; idx++) {
// create x and y matrices each of size 1x8
x = mxCreateDoubleMatrix(1, 8, mxREAL);
y = mxCreateDoubleMatrix(1, 8, mxREAL);
// fill x and y matrices: x[i], y[i]
xData = mxGetPr(x);
yData = mxGetPr(y);
for (i=0; i<8; i++) {
xData[i] = counter;
yData[i] = counter + 100;
counter++;
}
// set fields: s(idx).x = x and s(idx).y = y
mxSetField(s, idx, "x", x);
mxSetField(s, idx, "y", y);
}
// return structure array
plhs[0] = s;
}
The returned structure array:
>> s = structArrayMEX();
>> whos s
Name Size Bytes Class Attributes
s 16x1 4096 struct
>> s(1)
ans =
x: [1 2 3 4 5 6 7 8]
y: [101 102 103 104 105 106 107 108]
>> s(16)
ans =
x: [121 122 123 124 125 126 127 128]
y: [221 222 223 224 225 226 227 228]
The above MEX-function should be equivalent to the following MATLAB code
vals = reshape(1:16*8, [8 16])';
s = struct('x',num2cell(vals,2), 'y',num2cell(vals+100,2));
I would like to create a dynamic array which store permutation sequence, such that
order[0][]={1,2,3}
order[1][]={2,1,3}
order[2][]={2,3,1}
let say order[m][n], m = number of permutation, n = number of term, m and n are identified in real-time.
I did the below, and found that the pointer address is overlapping, resulting in incorrect value storage. How can do it correctly using dynamic array via double pointer?
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
/* debug only */
for(y=num_term, x=0; y>0; y--, x++){
term[x] = y;
}
fprintf(stderr, "\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %-11d", x);
}
printf("\n");
for(y=0; y<num_permute; y++){
printf("%-5d%12p", y, (order+y));
memcpy(&(order[y]), term, sizeof(term));
for (x=0; x<num_term; x++)
printf(" %12p", order+y+x);
printf("\n");
}
}
int main(){
int y, z;
int** x;
x = (int*) malloc(5*5*sizeof(int*));
permute(5, 5, x);
printf("\n");
printf("x ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<5; y++){
printf("%-4d", y);
for(z=0; z<5; z++){
printf(" %2d ", *(x+y+z));
}
printf("\n");
}
free(x);
return 0;
}
Result: order[0][1] and order[1][0] point to same address... and so do others. With rows as the major axis and columns the minor:
order 0 1 2 3 4
0 0x100100080 0x100100080 0x100100084 0x100100088 0x10010008c 0x100100090
1 0x100100084 0x100100084 0x100100088 0x10010008c 0x100100090 0x100100094
2 0x100100088 0x100100088 0x10010008c 0x100100090 0x100100094 0x100100098
3 0x10010008c 0x10010008c 0x100100090 0x100100094 0x100100098 0x10010009c
4 0x100100090 0x100100090 0x100100094 0x100100098 0x10010009c 0x1001000a0
x 0 1 2 3 4
0 5 5 5 5 5
1 5 5 5 5 4
2 5 5 5 4 3
3 5 5 4 3 2
4 5 4 3 2 1
Source Code:
The code will be something like:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
}
Concept:
array is a pointer-to-pointer-to-int: at the first level, it points to a block of pointers, one for each row. That first-level pointer is the first one to be allocated; it has nrows elements, with each element big enough to hold a pointer-to-int, or int *. If the allocation is successful then fill in the pointers (all nrows of them) with a pointer (also obtained from malloc) to ncolumns number of ints, the storage for that row of the array.
Pictorial Depiction:
It is simple to grasp if you visualize the situation as:
Taking this into account, the sample code could be rewritten as:
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
int* ptr = NULL;
for (y=num_term, x=0; y>0; y--, x++) {
term[x] = y;
}
printf("\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %2d ", x);
}
printf("\n");
for (y=0; y<num_permute; y++) {
ptr = order[y];
memcpy(ptr, term, sizeof(term));
printf("%-5d%12p", y, ptr);
for (x=0; x<num_term; x++) {
printf(" %2d ", ptr[x]);
}
printf("\n");
}
}
int main() {
int y, z;
int** x = NULL;
int num_term = 5;
int num_permutation = 5;
int* pchk = NULL;
x = (int**) malloc(num_permutation * sizeof(int*));
for (y=0; y<num_permutation; y++){
x[y] = (int*) malloc(num_term * sizeof(int));
printf("x[%d]: %p\n", y, x[y]);
}
permute(num_permutation, num_term, x);
printf("\nx: ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<num_permutation; y++){
pchk = x[y];
printf("%-4d", y);
for(z=0; z<num_term; z++){
printf(" %2d ", pchk[z]);
}
printf("\n");
}
for (y=0; y<num_permutation; y++) {
free(x[y]);
}
free(x);
return 0;
}
The code sample only simulates a multidimensional array, and does it incorrectly. To see what's going wrong, start by considering what happens when you declare a multidimensional array:
int foo[3][5];
This allocates a contiguous region of memory of size 3*5*sizeof(int). In an expression such as foo[i], the foo is converted to a int [5] pointer, then the index operator is applied. In other words, foo[i] is equivalent to *( (int (*)[5])foo) + i). Each foo[i] would be considered as having size 5*sizeof(int).
x,y: 0,0 0,1 0,2 0,3 0,4 1,0
foo --> | 1 | 2 | 3 | 4 | 5 | 1 |...
<- 5 * sizeof(int) ->
When you create x in the sample code, you're replicating this type of multidimensional array. The index expression you're using (*(order + y + x)) is thus wrong, as it doesn't properly handle the size of order[y]: order + 1 + 0 == order + 0 + 1, which is the problem you're seeing in the sample output.
The correct expressions are: (order + num_term * y) for the yth permutation and *(order + num_term * y + x) for element order[y][x].
This suggests another class of error in the sample. For this kind of simulated multidimensional array, the array types are actually pointers to single dimensional arrays. The declared types of x and order should be int*, not int**. This should be reinforced by the type warnings the sample code should generate:
when allocating space for x, the type of the pointer (int*) doesn't match the type of x
when printing the elements of x, the type of *(x+y+z) doesn't match the format "%d".
However, while simulating a multidimensional array saves space, it's more error prone when used (unless you write a function to handle indexing). A solution such as Als' may be safer, as you can use the standard indexing operator.
Emulating a 2D array with pointer arrays is a complete overkill if you have C99 (or C11). Just use
void permute(size_t num_permute, size_t num_term, unsigned order[][num_term]);
as your function signature and allocate your matrix in main with something like
unsigned (*order)[m] = malloc(sizeof(unsigned[n][m]));
Also, as you can see in the examples above, I'd suggest that you use the semantically correct types. Sizes are always best served with size_t and your permutation values look to me as if they will never be negative. Maybe for these you also should start counting from 0.
The following code snippet creates a 2d matrix for a given row and column. Please use this as a reference to debug your program.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int row, column;
int **matrix;
int i, j, val;
printf("Enter rows: ");
scanf("%d", &row);
printf("Enter columns: ");
scanf("%d", &column);
matrix = (int **) malloc (sizeof(int *) * row);
if (matrix == NULL) {
printf("ERROR: unable to allocate memory \n");
return -1;
}
for (i=0 ; i<row ; i++)
matrix[i] = (int *) malloc (sizeof(int) * column);
val=1;
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
matrix[i][j] = val++;
}
}
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
/*
Allocation of 2d matrix with only one call to malloc and
still get to access the matrix with a[i][j] format
the matrix is divided into headers and data.
headers = metadata to store the rows
data = actual data storage - buffer
allocate one contigious memory for header and data
and then make the elements in the header to point to the data are
<- headers -----><----------- data -----------
-----------------------------------------------------------------
| | | | | | .. |
| | | | | | .. |
-----------------------------------------------------------------
| ^
| |
|-----------------|
header points to data area
*/
/*
Output:
$ gcc 2darray.c
$ ./a.out
Enter rows: 10
Enter columns: 20
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 96 97 98 99 100
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
$
*/