I'm currently working on some code and, up to now, everything has compiled fine. The aim of the code is this:
read input from data file and assign values to an array.
"smooth the data" by taking average of the data on a given interval and replacing each value in that interval with the average.
It's the second part that causing me trouble. In the external function, for some reason it works when my 'for' loop looks like this:
for(i=t; i<t+z; i++)
But I don't want it to do that. I want it to do this:
for(i=t*z; i<(t+1)*z; i++)
When I try to compile, it just crashes out on me. Anyone know the reason why? It's been puzzling me for hours now. All the code is shown below by the way:
#include <stdio.h>
#include <stdlib.h>
float foo(float*, int, int);
int main(int argc, char* argv[])
{
FILE *input;
const char datafile[]="datainput.dat";
input=fopen(datafile, "r");
int i;
int N=0, t=0;
int z=100;
int M=10;
float *a, avg;
a=(float*)malloc(M*sizeof(float));
if((input!=(FILE*) NULL))
{
while(fscanf(input, "%e", &a[t++])==1)
{
if (t>=M)
{
M*=2;
a=(float *)realloc(a, M*sizeof(float));
}
N++;
}
float u[N];
for(t=0; t<N; t++)
{
avg = foo(a, z, t);
u[t] = avg;
}
fclose(input);
}
else
printf("Input file could not be opened.\n");
return(0);
}
float foo(float b[], int z, int t)
{
int i;
int k=0;
float avg;
float sum=0;
for(i=t*z; i<(t+1)*z; i++)
{
sum+=b[i];
k++;
}
avg = sum/(float)k;
return(avg);
}
side note: you'll probably notice the poor practise of defining float u[N] half way down the code. I don't really like this being there, but you'll note that N is a variable that counts the number of values in the input file (initially unknown) and is initally set to N=0, so I'm not sure how I get around that.
additionally, I asked the question earlier on here but my realloc has no clause if it fails. it's something i'm working on though but at the moment it compiles without it being there.
Also, all the data values are of the form float with seven decimal places and in scientific notation, hence the %e.
Thank you!
EDIT: here are some of the values from the data file. Even though the values on the left look ordered, they are actual values in the file and not there to denote the values on the right.
8.0800000e+00 7.0872796e-01
8.0900000e+00 7.1941101e-01
8.1000000e+00 2.1635408e+00
8.1100000e+00 -5.4200807e-01
8.1200000e+00 1.1046968e+00
8.1300000e+00 1.5833782e+00
8.1400000e+00 6.6122899e-01
8.1500000e+00 1.7922273e+00
8.1600000e+00 1.2446803e+00
8.1700000e+00 3.7869871e-01
8.1800000e+00 1.4793635e+00
8.1900000e+00 1.0508171e+00
8.2000000e+00 9.1012735e-01
8.2100000e+00 6.0967729e-01
8.2200000e+00 1.3834455e+00
8.2300000e+00 -5.2312924e-01
8.2400000e+00 9.2566688e-01
8.2500000e+00 7.8145188e-01
8.2600000e+00 4.1410150e-01
8.2700000e+00 1.9796986e+00
8.2800000e+00 5.9372874e-01
8.2900000e+00 1.8696331e+00
8.3000000e+00 2.3058409e+00
So I've been staring at this for awhile. This is what I came up with. The interval (i'm assuming is 100). for the sake of sanity I've changed it to 5 in the code that follows because your sample posted data is only 46 elements long. I must assume yours is much larger than this.
Some things to note:
foo() no longer relies on some whacky 'where do I compute my average' variables. The caller is responsible for passing the starting location and count of elements to average. This, as you will see, makes that code much simpler. This was fundamentally the heart of the problem to begin with, as your allocation loop was fine (save for not checking your realloc return value). There is no reason to complicate that function to try and compute an average somewhere in the middle of some larger array. Keep it simple. Just have the caller tell the function where to start and how many to average.
Though it wasn't specified, I believe z is your "interval" width. The thing to note in the code below is the interval-count calculation. The number of intervals is simply (N+(z-1))/z, which will result in the number of intervals to process, including the last interval which may only be a partial. From there, we simply walk through the original array, partitioning up in z-sized slices, calculating the average, then rewriting the interval we just averaged with the said-same average. The last interval, again, can be a partial, which requires a little bit of extra care.
I changed the data file to be a command line parameter argv[1]. Made it easier for me to test.
Sure hope this is what you were looking for. Thx for the fun, and don't forget to reset the z value in this code back to 100 if you plan on using it.
#include <stdio.h>
#include <stdlib.h>
float foo(float a[], int count);
int main(int argc, char* argv[])
{
if (argc !=2)
return EXIT_FAILURE;
FILE *input=fopen(argv[1], "r");
if (input != NULL)
{
int z=5,t=0;
int M=10,N=0;
float *a = malloc(M*sizeof(float));
while(fscanf(input, " %e", a + N) ==1 )
{
if (++N>=M)
{
void *tmp = realloc(a, (M*=2)*sizeof(float));
if (tmp != NULL)
{
a = tmp;
}
else
{
perror("Failed to allocate memory.");
exit(EXIT_FAILURE);
}
}
}
// compute number of intervals we will process. the last
// interval may be only a partial.
for (t=0;t<N;t+=z)
{
// how many we're doing in this interval
int count = (z < (N-t) ? z : (N-t)), k=0;
float avg = foo(a+t, count);
printf("Avg[%d] = %e\n", t/z, avg);
// smooth over original array with just-found svg.
for (k=0;k<count; a[t+k++] = avg);
}
fclose(input);
// dump the final array content
for (t=0;t<N;++t)
printf("a[%d] = %e\n", t, a[t]);
// release original array.
free(a);
}
else
{
perror("Input file could not be opened.");
}
return(0);
}
// find the average of the range of floats we're given.
float foo(float a[], int count)
{
float sum = 0;
int i = 0;
for(i=0; i<count; sum += a[i++]);
return (sum)/(float)(count);
}
Output (z=5)
Avg[0] = 5.139628e+00
Avg[1] = 3.791246e+00
Avg[2] = 5.332921e+00
Avg[3] = 3.949121e+00
Avg[4] = 5.420036e+00
Avg[5] = 3.866650e+00
Avg[6] = 5.024508e+00
Avg[7] = 3.941051e+00
Avg[8] = 5.466672e+00
Avg[9] = 2.305841e+00
a[0] = 5.139628e+00
a[1] = 5.139628e+00
a[2] = 5.139628e+00
a[3] = 5.139628e+00
a[4] = 5.139628e+00
a[5] = 3.791246e+00
a[6] = 3.791246e+00
a[7] = 3.791246e+00
a[8] = 3.791246e+00
a[9] = 3.791246e+00
a[10] = 5.332921e+00
a[11] = 5.332921e+00
a[12] = 5.332921e+00
a[13] = 5.332921e+00
a[14] = 5.332921e+00
a[15] = 3.949121e+00
a[16] = 3.949121e+00
a[17] = 3.949121e+00
a[18] = 3.949121e+00
a[19] = 3.949121e+00
a[20] = 5.420036e+00
a[21] = 5.420036e+00
a[22] = 5.420036e+00
a[23] = 5.420036e+00
a[24] = 5.420036e+00
a[25] = 3.866650e+00
a[26] = 3.866650e+00
a[27] = 3.866650e+00
a[28] = 3.866650e+00
a[29] = 3.866650e+00
a[30] = 5.024508e+00
a[31] = 5.024508e+00
a[32] = 5.024508e+00
a[33] = 5.024508e+00
a[34] = 5.024508e+00
a[35] = 3.941051e+00
a[36] = 3.941051e+00
a[37] = 3.941051e+00
a[38] = 3.941051e+00
a[39] = 3.941051e+00
a[40] = 5.466672e+00
a[41] = 5.466672e+00
a[42] = 5.466672e+00
a[43] = 5.466672e+00
a[44] = 5.466672e+00
a[45] = 2.305841e+00
Output (z=10)
Avg[0] = 4.465437e+00
Avg[1] = 4.641021e+00
Avg[2] = 4.643343e+00
Avg[3] = 4.482779e+00
Avg[4] = 4.939867e+00
a[0] = 4.465437e+00
a[1] = 4.465437e+00
a[2] = 4.465437e+00
a[3] = 4.465437e+00
a[4] = 4.465437e+00
a[5] = 4.465437e+00
a[6] = 4.465437e+00
a[7] = 4.465437e+00
a[8] = 4.465437e+00
a[9] = 4.465437e+00
a[10] = 4.641021e+00
a[11] = 4.641021e+00
a[12] = 4.641021e+00
a[13] = 4.641021e+00
a[14] = 4.641021e+00
a[15] = 4.641021e+00
a[16] = 4.641021e+00
a[17] = 4.641021e+00
a[18] = 4.641021e+00
a[19] = 4.641021e+00
a[20] = 4.643343e+00
a[21] = 4.643343e+00
a[22] = 4.643343e+00
a[23] = 4.643343e+00
a[24] = 4.643343e+00
a[25] = 4.643343e+00
a[26] = 4.643343e+00
a[27] = 4.643343e+00
a[28] = 4.643343e+00
a[29] = 4.643343e+00
a[30] = 4.482779e+00
a[31] = 4.482779e+00
a[32] = 4.482779e+00
a[33] = 4.482779e+00
a[34] = 4.482779e+00
a[35] = 4.482779e+00
a[36] = 4.482779e+00
a[37] = 4.482779e+00
a[38] = 4.482779e+00
a[39] = 4.482779e+00
a[40] = 4.939867e+00
a[41] = 4.939867e+00
a[42] = 4.939867e+00
a[43] = 4.939867e+00
a[44] = 4.939867e+00
a[45] = 4.939867e+00
It unlikely that sum+=b[i]; will access the array b between 0 and N-1.
You have allocated 10 block for floats which is passed as array parameter for function. In statement sum+=b[i], here b[i] will not ensure that you are not referring at the index out side the array size, as you have "i" which can go beyond 10 e.g. when z=100 and t=1.
Related
Every time I execute my program which finds the average in a ten element array. I get slightly different results. Any idea why?
Here is my code:
#include "stdio.h"
int main()
{
float array[10];
for (int n=0; n<10;n++)
{
array[n] = n * 4.76;
printf("array[%i] = %.4f\n",n,array[n] );
}
float total;
for (int n=0; n<10; n++)
{
total = total + array[n];
}
printf("Average: %.4f\n", total/10 );
return 0;
}
and some sample results are:
array[0] = 0.0000
array[1] = 4.7600
array[2] = 9.5200
array[3] = 14.2800
array[4] = 19.0400
array[5] = 23.8000
array[6] = 28.5600
array[7] = 33.3200
array[8] = 38.0800
array[9] = 42.8400
Average: 21.2598
array[0] = 0.0000
array[1] = 4.7600
array[2] = 9.5200
array[3] = 14.2800
array[4] = 19.0400
array[5] = 23.8000
array[6] = 28.5600
array[7] = 33.3200
array[8] = 38.0800
array[9] = 42.8400
Average: 21.2826
When declaring variables in C, make sure they're initialised to a default value. Variables allocated on the stack are usually not initialised to their default values, rather, they are initialised with junk.
So, before starting summation, initialise your variable as
float total = 0.0f;
and you should get the same answer every time.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
It seems strange, but I haven't found anything on the following problem: Given a vector x of length n, how can one construct a vector oo of length n such that x[oo[i]] (for i=1,..,n) is sorted. Requirements: only C functions in the standard library are allowed to be used and the code has to be fast (note: I'm not a C programmer but experienced in R. R has order() for this task).
I found the post here but this discusses sorting directly.
The question you link to (C library function to do sort) shows how to use the standard C library function called qsort() in general, but your requirement is not one of the usual problems. To be able to sort the oo array, the comparator function must be able access the x array as well as the data passed to it from qsort() itself.
This code achieves that with reasonable economy of effort:
#include <stdio.h>
#include <stdlib.h>
typedef double VecType;
#define PRIf_VecType "f"
static VecType *base;
static int compare(const void *p1, const void *p2)
{
const int i1 = *(int *)p1;
const int i2 = *(int *)p2;
if (base[i1] < base[i2])
return -1;
else if (base[i1] > base[i2])
return +1;
else
return 0;
}
static void print_arrays(const char *tag, size_t x_size, VecType *x, int *oo)
{
printf("%s:\n", tag);
for (size_t i = 0; i < x_size; i++)
printf("%zu: oo[%zu] = %d, x[oo[%zu]] = %4.2" PRIf_VecType
", x[%zu] = %4.2" PRIf_VecType "\n",
i, i, oo[i], i, x[oo[i]], i, x[i]);
}
int main(void)
{
VecType x[] = { 3.45, 1.23, 9.14, 4.67, 2.19, 3.45, 5.92 };
size_t x_size = sizeof(x) / sizeof(x[0]);
int oo[x_size];
for (size_t i = 0; i < x_size; i++)
oo[i] = (int)i;
print_arrays("Before", x_size, x, oo);
base = x;
qsort(oo, x_size, sizeof(oo[0]), compare);
print_arrays("After", x_size, x, oo);
return 0;
}
Sample output:
Before:
0: oo[0] = 0, x[oo[0]] = 3.45, x[0] = 3.45
1: oo[1] = 1, x[oo[1]] = 1.23, x[1] = 1.23
2: oo[2] = 2, x[oo[2]] = 9.14, x[2] = 9.14
3: oo[3] = 3, x[oo[3]] = 4.67, x[3] = 4.67
4: oo[4] = 4, x[oo[4]] = 2.19, x[4] = 2.19
5: oo[5] = 5, x[oo[5]] = 3.45, x[5] = 3.45
6: oo[6] = 6, x[oo[6]] = 5.92, x[6] = 5.92
After:
0: oo[0] = 1, x[oo[0]] = 1.23, x[0] = 3.45
1: oo[1] = 4, x[oo[1]] = 2.19, x[1] = 1.23
2: oo[2] = 5, x[oo[2]] = 3.45, x[2] = 9.14
3: oo[3] = 0, x[oo[3]] = 3.45, x[3] = 4.67
4: oo[4] = 3, x[oo[4]] = 4.67, x[4] = 2.19
5: oo[5] = 6, x[oo[5]] = 5.92, x[5] = 3.45
6: oo[6] = 2, x[oo[6]] = 9.14, x[6] = 5.92
The printing for 'after' assures us that the array x is unchanged, but the array oo has been updated such that x[oo[i]] is in the ith position in sorted order.
BSD (and therefore Mac OS X too) provides a non-standard alternative to qsort(), namely qsort_r():
void qsort_r(void *base, size_t nel, size_t width, void *thunk,
int (*compar)(void *, const void *, const void *));
The qsort_r() function behaves identically to qsort(), except that it takes an additional argument, thunk, which is passed unchanged as the first argument to function pointed to compar. This allows the comparison function to access additional data without using global variables, and thus qsort_r() is suitable for use in functions which must be reentrant.
Writing the code in terms of qsort_r() is a rather trivial set of changes:
#include <stdio.h>
#include <stdlib.h>
typedef double VecType;
#define PRIf_VecType "f"
static int compare(void *thunk, const void *p1, const void *p2)
{
const VecType *base = (VecType *)thunk;
const int i1 = *(int *)p1;
const int i2 = *(int *)p2;
if (base[i1] < base[i2])
return -1;
else if (base[i1] > base[i2])
return +1;
else
return 0;
}
static void print_arrays(const char *tag, size_t x_size, VecType *x, int *oo)
{
printf("%s:\n", tag);
for (size_t i = 0; i < x_size; i++)
printf("%zu: oo[%zu] = %d, x[oo[%zu]] = %4.2" PRIf_VecType
", x[%zu] = %4.2" PRIf_VecType "\n",
i, i, oo[i], i, x[oo[i]], i, x[i]);
}
int main(void)
{
VecType x[] = { 3.45, 1.23, 9.14, 4.67, 2.19, 3.45, 5.92 };
size_t x_size = sizeof(x) / sizeof(x[0]);
int oo[x_size];
for (size_t i = 0; i < x_size; i++)
oo[i] = (int)i;
print_arrays("Before", x_size, x, oo);
qsort_r(oo, x_size, sizeof(oo[0]), x, compare);
print_arrays("After", x_size, x, oo);
return 0;
}
With sample output like this (it is the same as the output from the other code):
Before:
0: oo[0] = 0, x[oo[0]] = 3.45, x[0] = 3.45
1: oo[1] = 1, x[oo[1]] = 1.23, x[1] = 1.23
2: oo[2] = 2, x[oo[2]] = 9.14, x[2] = 9.14
3: oo[3] = 3, x[oo[3]] = 4.67, x[3] = 4.67
4: oo[4] = 4, x[oo[4]] = 2.19, x[4] = 2.19
5: oo[5] = 5, x[oo[5]] = 3.45, x[5] = 3.45
6: oo[6] = 6, x[oo[6]] = 5.92, x[6] = 5.92
After:
0: oo[0] = 1, x[oo[0]] = 1.23, x[0] = 3.45
1: oo[1] = 4, x[oo[1]] = 2.19, x[1] = 1.23
2: oo[2] = 5, x[oo[2]] = 3.45, x[2] = 9.14
3: oo[3] = 0, x[oo[3]] = 3.45, x[3] = 4.67
4: oo[4] = 3, x[oo[4]] = 4.67, x[4] = 2.19
5: oo[5] = 6, x[oo[5]] = 5.92, x[5] = 3.45
6: oo[6] = 2, x[oo[6]] = 9.14, x[6] = 5.92
The standard library's all-purpose sorting function is qsort. It takes a comparison function which takes the two elements to be compared. There is no way to pass additional information to the function.
If you have access to a sorting function that accepts additional data in its comparison function, e.g. qsort_r or g_qsort_with_data you should use that. Jonathan Leffler has shown you how. (It's a pity that qsort_r isn't part of the standard. The additional data is often useful and lends itself to a clean solution of your problem.)
If you rely on qsort, a simple solution would be to store the additional information in a global variable. That's not a nice solution, because it doesn't encapsulate the data properly and isn't thread-safe. For a small-scale program, it might be good enough, though; see Rob's answer.
Another approach, which is often used in sorting two arrays alongside each other is to combine them into structs of these variables, and sort according to one of the fields. That's usually a good approach if the data belongs together, but in your case that would mean to create an auxiliary struct array.
Finally, you could create an array of pointers and sort those with one level of indirection.
Edit: I had first proposed to use this approach to create an array of indices as requested in the question. That solution relied on size_t being of the same size as void *, which isn't necessarily true by the C standard, and also accessed the same memory as both pointers into the array and array indices, thus breaking strict aliasing rules. That solution is still available at the end of the post.
I've now come to the conclusion that the pointer solution is viable, but that the order function should populate an array of pointers into the array. So instead of accessing the element via an index, x[oo[i]], it is now accessed via a pointer *oref[i]. If the index is needed, it can be obtained via pointer arithmetic:
ix = oref[i] - x;
This is a nice C solution. Here's an implementation with example client code:
#include <stdlib.h>
#include <stdio.h>
typedef int Type;
int ptrcmp(const void *a, const void *b)
{
const Type *const *aa = a;
const Type *const *bb = b;
return (**aa > **bb) - (**aa < **bb);
}
void order_ref(Type **ptr, Type *arr, size_t n)
{
size_t i;
for (i = 0; i < n; i++) ptr[i] = arr + i;
qsort(ptr, n, sizeof(*ptr), ptrcmp);
}
#define countof(x) (sizeof(x) / sizeof(*x))
int main()
{
Type arr[] = {8, 5, 4, 9, 1, 7, 6, 3, 2, 0};
Type *ptr[countof(arr)];
size_t n = countof(arr);
size_t i;
order_ref(ptr, arr, n);
for (i = 0; i < n; i++) {
int ix = ptr[i] - arr;
printf("%4d%16d\n", ix, *ptr[i]);
}
return 0;
}
The code I originally proposed is below. I said: You can make use of the fact that size_t has the same size as a pointer and convert the pointers to unsigned integers of type size_t using pointer arithmetic. That condition isn't necessarily true on all platforms, but it is at least enforced by an assert.
Using the same array for pointers and indices is a trick that saves allocating an auxiliary array. I'm not sure whether is breaks strict aliasing, because it does the type punning on on element of the array at a time, but it certainly isn't a clean solution.
It still might be useful, so here's the code, but really prefer the qsort_r or pointer solutions.
typedef int Type; // Source data type
int ptrcmp(const void *a, const void *b)
{
const Type *const *aa = a;
const Type *const *bb = b;
return (**aa > **bb) - (**aa < **bb);
}
size_t *order(const Type *arr, size_t n)
{
const Type **ptr = malloc(n * sizeof(*ptr));
size_t *res = (size_t *) ptr;
size_t i;
assert(sizeof(size_t) == sizeof(Type *));
for (i = 0; i < n; i++) ptr[i] = arr + i;
qsort(ptr, n, sizeof(*ptr), ptrcmp);
for (i = 0; i < n; i++) res[i] = ptr[i] - arr;
return res;
}
/*
* Example client code
*/
int main()
{
Type arr[] = {8, 5, 4, 9, 1, 7, 6, 3, 2, 0};
size_t n = sizeof(arr) / sizeof(*arr);
size_t *ind = order(arr, n);
size_t i;
for (i = 0; i < n; i++) {
printf("%4d%16d\n", ind[i], arr[ind[i]]);
}
free(ind);
return 0;
}
I won't comment on whether it is fast, but this does it in a manner reasonably economical with code. Note the code is not reentrant nor is it thread safe, due to using a static to pass information between two functions.
This code assumes both the arrays x and oo are of length size.
#include <stdlib.h>
const WhateverType *array;
int our_comparison_thing(const void *a, const void *b)
{
WhateverType *aval = array + *(size_t *)a;
WhateverType *bval = array + *(size_t *)b;
return (*aval == *bval) ? 0 : ((*aval < *bval) ? -1 : 1);
}
void DoOurThing(const WhateverType *x, size_t *oo, size_t size)
{
size_t i;
array = x;
for (i = 0; i < size; ++i)
oo[i] = i;
qsort((void *)oo, size, sizeof(*oo), our_comparison_thing);
}
Not sure what i'm doing wrong here. I'm trying to circularly shift elements of a char array left by one. It seems to work, but not persist. I assume it's a pointer issue, but I still don't get how pointers work so i'm not sure where to begin. Problem is, it only seems to change the value inside the for loop and reset afterwards.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void ip();
int main(){
char d[10] = "010";
char k[10] = "1010000010";
initialPermutation(d, k);
return(0);
}
void ip(char * data, char* key){
int i;
// P10(k1, k2, k3, k4, k5, k6, k7, k8, k9, k10) = (k3, k5, k2, k7, k4, k10, k1, k9, k8, k6)
char P10[10] = {key[2],key[4],key[1],key[6],key[3],key[9],key[0],key[8],key[7],key[6]};
// split P10 into two segments
char left5[5] = {P10[0],P10[1],P10[2],P10[3],P10[4]};
char right5[5] = {P10[5],P10[6],P10[7],P10[8],P10[9]};
// pre shift binary string
printf("Pre-shift: ");
for(i=0;i<5;i++)
printf("%c",left5[i]);
for(i=0;i<5;i++)
printf("%c",right5[i]);
printf("\n");
// circular shift left one bit (here is where the problem is)
for(i=0;i<5;i++){
char templ = left5[4-i];
left5[4-i] = left5[i];
left5[i] = templ;
char tempr = right5[4-i];
right5[4-i] = right5[i];
right5[i] = tempr;
}
printf("Post- (outside for loop): ");
for(i=0;i<5;i++)
printf("%c",left5[i]);
for(i=0;i<5;i++)
printf("%c",right5[i]);
printf("\n");
}
Your loop is not shifting values, it is reversing the array twice.
It swaps index 0 with index 4, then 1 with 3, then 2 with 2, then 3 with 1, and finally 4 with 0. At this point the array is exactly as when you started.
This code does an actual rotary left shift:
char tmp = left5[0];
for(i = 1; i < sizeof(left5); ++i){
left5[i-1] = left5[i]
}
left5[4] = tmp;
If you actually declare the arrays one element too large you can write:
char left5[6] = {P10[0],P10[1],P10[2],P10[3],P10[4]};
left5[5] = left5[0]
for(i=0; i < 5; ++i){
left5[i] = left5[i+1];
}
I am trying to create an mpi program that will run my bellard function to calculate pi to ten thousand decimal places. When i run the program i am presented with the following errors, I have done some searching online and on the openMpi website, the problem appears to be a null pointer but i have looked through the code and cant seem to find it.
The error is:
Signal :segmentation fault(11)
Signal :address not mapped(1)
Failing at address : (nil)
Can anyone see the null pointer ?
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <mpi/mpi.h>
#define PRECISION 10000
float minus_one,one,two,three,four,five,six,seven,eight,nine,ten,
thirty_two,sixty_four,two_five_six,one_zero_two_four,
two_pow_six,recip_two_pow_six;
float *pi;
int rank,size;
void init(){
printf("\nstarted init function");
minus_one = -1.0;
one = 1.0;
two = 2.0;
three = 3.0;
four = 4.0;
five = 5.0;
six = 6.0;
seven = 7.0;
eight = 8.0;
nine = 9.0;
ten = 10.0;
thirty_two = 32.0;
sixty_four = 64.0;
two_five_six = 256.0;
one_zero_two_four = 1024.0;
two_pow_six = pow(two,6);
recip_two_pow_six = one/two_pow_six;
pi = 0;
printf("\nended init function");
return;
}
float *bellard(int start, int end,int rank){
float *terms;
float t,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,
t13,t14,t15,t16,t17,tx,ty,tz;
int offset = rank;
double start_k = start;
double end_k = end;
start_k = offset * (PRECISION /size);
end_k = (offset+1) * (PRECISION/size);
terms=0;
int k = start_k;
while( (k<PRECISION) && (k<end_k)){
t1 = k;
t2 = t1*ten;
t3 = t2+one;
t4 = two_five_six/t3;
t5 = t2+nine;
t6 = one/t5;
t7 = t2+three;
t8 = sixty_four/t7;
t9 = four*t1;
t10 = t9+one;
t11 = thirty_two/t10;
t12 = t2+five;
t13 = four/t12;
t14 = t2+seven;
t15 = four/t14;
t16 = t9+three;
t17 = one+t16;
t = t4+t6;
t = t-t8;
t = t-t11;
t = t-t13;
t = t-t15;
t = t-t17;
tx = pow(minus_one,k);
ty = pow(one_zero_two_four,k);
tz = tx/ty;
*terms = tz*t;
//pi = pi+terms;
k = k+1;
}
return terms;
}
int main(int argc, char** argv){
int i;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int elementsCount = 10000/(size-1);
float *workerPi;
float *tmpPi=0;
init(); //initialise variables
printf("\nim here 1");
if(rank == 0)
{
for(i=1; i < size; i++){
printf("\nin recv loop");
MPI_Recv(tmpPi,PRECISION,MPI_FLOAT,i,1,MPI_COMM_WORLD,&status);
*pi=*pi+*tmpPi;
}
}else{
//int i;
int start,end,slice,workers;
workerPi = malloc(sizeof(int)*elementsCount);
workers = size-1;
slice = 10000/workers;
start = (rank-1)*slice;
end = start+slice;
printf("\nWorker %d processing data %d to %d\n",rank,start,end);
workerPi = bellard(start,end,rank);
printf("\nworker finished pi");
MPI_Send(workerPi,slice,MPI_FLOAT,0,1,MPI_COMM_WORLD);
printf("\nworker sent stuff");
}
MPI_Finalize();
return 0;
}
In the bellard function, terms is declared as a pointer to float
float *terms;
and initialized to zero (aka null) a few lines down
terms=0;
Towards the end of the while loop, it is dereferenced:
*terms = tz*t;
The statement *terms is a null pointer dereference and will crash. It is essentially asking to store the result of tz*t into memory address zero, which is not a valid memory address.
The fix may be to declare and use terms as a float, not a pointer to a float (float*).
I have filled a dynamic allocated float multi array in a function.
A second function has to get the values of the array exploiting the pointer to the first element of the array defined in the former function.
The second function do not access to the correct memory location so it doesn't work but it does if the multy array is defined in a static way.
Does somebody know why?
eval_cell should get values defined in div_int
float f_imp(float x, float y){
return pow(x,2)+pow(y,2)-1;
}
int eval_cell(float* p){
int s[4];
s[0] = f_imp(*p, *(p+1)) <= 0;
printf("%f %f\n",*p, *(p+1));
s[1] = f_imp(*(p+3), *(p+4)) <= 0;
printf("%f %f\n",*(p+3), *(p+4));
s[2] = f_imp(*(p+9), *(p+10)) <= 0;
printf("%f %f\n",*(p+9), *(p+10));
s[3] = f_imp(*(p+6), *(p+7)) <= 0;
printf("%f %f\n",*(p+6), *(p+7));
printf("%d%d%d%d\n",s[0],s[1],s[2],s[3]);
return s[0];
}
void div_int(float* x1, float* y1,float* x2,float* y2,
float* f0, float* f2,float* f6,float* f8){
int i,j,m;
float* p;
float** a_cell; // array 9x3 contente coordinate vertici e valore funzione
*a_cell = (float**) malloc(9*sizeof(float*));
for (i=0;i<9;i++){
a_cell[i] = (float*) malloc(3*sizeof(float));
}
a_cell[0][0] = *x1;
a_cell[0][1] = *y1;
a_cell[0][2] = *f0;
a_cell[2][0] = *x2;
a_cell[2][1] = *y1;
a_cell[2][2] = *f2;
a_cell[6][0] = *x1;
a_cell[6][1] = *y2;
a_cell[6][2] = *f6;
a_cell[8][0] = *x2;
a_cell[8][1] = *y2;
a_cell[8][2] = *f8;
/*** calcolo dei valori incogniti di a_cell ***/
a_cell[1][0] = (*x1+*x2)/2;
a_cell[1][1] = *y1;
a_cell[1][2] = f_imp(a_cell[1][0], a_cell[1][1]);
a_cell[3][0] = *x1;
a_cell[3][1] = (*y1+*y2)/2;
a_cell[3][2] = f_imp(a_cell[3][0], a_cell[3][1]);;
a_cell[4][0] = (*x2+*x1)/2;
a_cell[4][1] = (*y2+*y1)/2;
a_cell[4][2] = f_imp(a_cell[4][0], a_cell[4][1]);
a_cell[5][0] = *x2;
a_cell[5][1] = (*y2+*y1)/2;
a_cell[5][2] = f_imp(a_cell[5][0], a_cell[5][1]);
a_cell[7][0] = (*x1+*x2)/2;
a_cell[7][1] = *y2;
a_cell[7][2] = f_imp(a_cell[7][0], a_cell[7][1]);
for (j=0;j<2;j++){
m = j*3;
for(i=0;i<2;i++){
m += i;
eval_cell(&a_cell[m][0]);
}
}
p = *a_cell;
for (i=0;i<9;i++){
for (j=0;j<3;j++){
printf("%f \n",*(p+3*i+j));
printf("%f \n",a_cell[i][j]);
printf("\n");
}
}
free(a_cell);
return;
}
It's because you using pointer in incorrect way:
See a_cell is pointer to dynamic array of 9 pointers to dynamic array of 3 floats.
So when you do eval_cell(&a_cell[m][0]) (or just eval_cell(a_cell[m]) this is actually the same) you actually get pointer to array of 3 floats. And after that you do:
int eval_cell(float* p){
...
s[2] = f_imp(*(p+9), *(p+10)) <= 0;
*(p+9) will get 9th element in array of 3 floats, so this is incorrect.
It works in static way, because static multi dimension array in memory is just one dimension array for which you was given multi indexing (by compiler). That's why in static you will probably address valid memory area.
See picture for more explanation:
If you want a completely dynamic matrix (2d array), you have to make your own element access function:
double *
make_array (unsigned int rows, unsigned int cols)
{
return malloc (rows * cols * sizeof (double));
}
double *
array_element (double *a, unsigned int cols, unsigned int i, unsigned int j)
{
return a + i * cols + j;
}
#define A(i,j) (*array_element ((a), (cols), (i), (j)))
double *a;
unsigned int rows, cols;
a = make_array (rows, cols);
A(3,4) = 3.14;
printf ("%f\n:" A(3,4));
EDIT:
In your program
*a_cell = (float**) malloc(9*sizeof(float*));
should be
a_cell = (float**) malloc(9*sizeof(float*));
And likewise for
p = *a_cell;