Dealing with big sized array in c programming - c

I am working on nonlinear differential equation.
What I was doing is to average up the positions over 100 different values of initial conditions.
I used odeiv in gsl. For each initial values, the time range is 4*10^7. However, the program kills, once ever I set 10 different initial conditions and the time range 10^6. This is kind of limit.
My computer has 8 cores and 16GB memory. I don't think this is that much big.
I'll put a part of the coding. Anybody help me on this?
Thank you.
long long int i, j, k;
double const y_i = 0, dydt_i = 0;
double n = 10;
long long int tmax = 1000000;
double A[tmax];
for (j=0; j < n; j++)
{
double y_j = y_i + 0.001*j;
double dydt_j = dydt_i;
t = 0.0;
double y[2] = {y_j, dydt_j};
gsl_odeiv2_system sys = {func, jac, 2, &params};
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new (&sys, gsl_odeiv2_step_rk8pd, 1e-6, 1e-6, 0.0);
for (i=0; i< tmax; i++)
{
double ti = (double) i;
int status = gsl_odeiv2_driver_apply (d, &t, ti, y);
if (status != GSL_SUCCESS)
{
printf("error, return value%d\n", status);
break;
}
A[i] = A[i] +y[0];
}
gsl_odeiv2_driver_free (d);
}
for (k=0; k < tmax; k++)
{
A[k] = A[k]/n;
printf("%lld %e\n", k, A[k]);
}
return 0;
}
}

Local variables are allocated on the stack; the stack is not particularly huge, which means it's a bad place to allocate very large arrays. You need to make A a pointer and allocate it dynamically (or better, make it std::vector<double> if C++ is an option).

Related

Why am I getting runtime errors on this code? (C code ran by makefile thru linux)

First time coding in C, coming from C++. I was trying to make a program that solves the K-Neighbors problem. Assuming all locations are points in a 2D plane, it should return the closest k cities when given a list of n cities. After much debugging, it finally complied and ran, but returned a runtime error. I couldn't read the error code, so I don't understand what happened. What did I do wrong?
#include <stdio.h> //for printf
#include <stdlib.h> //for malloc, free
#include <math.h> //for sqrt, pow
struct City {
double x;
double y;
double distance;
};
double get_distance(double x1, double y1, double x2, double y2){
return sqrt(pow(x2 - x1, 2) + pow(y2- y1, 2));
}
void make_list(struct City arr[]){
arr[0].x = 0; arr[0].y = 0; arr[0].distance = 0;
arr[1].x = 110; arr[1].y = 150; arr[1].distance = 0;
arr[2].x = 140; arr[2].y = 30; arr[2].distance = 0;
arr[3].x = 91; arr[3].y = 70; arr[3].distance = 0;
arr[4].x = 172; arr[4].y = 161; arr[4].distance = 0;
arr[5].x = 62; arr[5].y = 160; arr[5].distance = 0;
arr[6].x = 16; arr[6].y = 163; arr[6].distance = 0;
arr[7].x = 161; arr[7].y = 40; arr[7].distance = 0;
arr[8].x = 162; arr[8].y = 20; arr[8].distance = 0;
arr[9].x = 61; arr[9].y = 117; arr[9].distance = 0;
}
//time complexity O(n^2)
void insertion_sort(double arr[], int n){
int i, key, j;
for(i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while(j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
int main() {
int array_size = 10;
struct City arr[array_size];
double distances[array_size];
make_list(arr);
//Find distance from me and add to sorted distances
for(int i = 0; i < array_size; i++){
arr[i].distance = get_distance(arr[0].x, arr[0].y, arr[i].x, arr[i].y);
insertion_sort(distances, array_size);
}
//Print the distances
int k = 5;
double temp = 0;
printf("\nThe %d closest distances are:\n", k);
if(k < array_size){
for(int i = 1; i < k; i++){
temp = distances[i];
printf("%f\n", temp);
}
}
return 0;
}
Transitioning from C++ to C I think is probably harder than the other way around (which is what I did).
This next paragraph has been slightly edited from original answer. Credit to John Bode for correcting me about C99 introducing variable-length arrays
Originally, arrays in C using [ ] could not be declared using a variable as the size like you can in C++. As someone pointed out in a comment, "Since C99, arrays can be declared with a runtime variable, although support is spotty and the feature was made optional in C11. They’re called variable-length arrays and can be useful." So, this implies that it's not working for you since you're current programming environment setup doesn't support it.
If you wanted to try to figure out how to get your programming environment to support this, go ahead. I personally don't know off the top of my head. For you in the context of this problem I think that's a bit of overkill. The easiest thing is just to use macros. Delete int array_size = 10; and define it as a macro right above main like #define array_size 10. (On a side note, I always like to make macros all caps like ARRAY_SIZE but you don't have to). For your purposes, the readers digest explanation of macros in this context is that here it will act as text replacement. So, everywhere array_size is written, it's equivalent to you literally manually typing in the number 10, or whatever arbitrary size you give it.

Mean function using values from double array displaying wrong values

Very new to C, anyways been coding a program where you enter pairs of doubles which are stored in separate arrays. I have created a function to get the mean of the numbers but when I call it inside main the values are different. Any ideas?
MEAN FUNCTION:
mean(double *arr)
{
double sum = 0.0;
double meanValue = 0.0;
int i;
for (i = 0; i < arr[i]; i++)
{
sum += arr[i];
meanValue = sum / i;
}
printf("\nmean: %.3lf", meanValue);
}
MAIN:
double num1[1001];
mean(num1);
And, I am getting the num1 and num2 values using:
for (k = 0; (scanf_s("%lf,%lf", &num1[k], &num2[k] ) == 2); k++)
The function needs to know how many of the array elements it should process.
mean(double *arr, int size)
{
double sum = 0.0;
double meanValue = 0.0;
int i;
for (i = 0; i < size; i++)
{
sum += arr[i];
}
meanValue = size > 0 ? sum / size : 0;
printf("\nmean: %.3lf", meanValue);
}
The size is the value of k after the input loop is done, so you call it:
mean(num1, k);
Your function needs to pieces of information:
the pointer to the data array;
the size of the array (number of elements).
However, the way you are computing the mean is subjected to bad numeric conditioning (floating point overflow). Here I suggest using the Incremental Averaging instead. Please consider this code:
double mean(double *arr, int num)
{
double res = arr[0];
for (int i = 1; i < num; ++i)
res += (arr[i] - res) / (i+1.0);
return res;
}
Note that I'm assuming you are using a C99 compliant compiler for the integer declaration inside the for loop.

2-D Array of structures -> unable to fix a segmentation fault :(

SO (pun intended) I want to solve this question from HackerEarth: https://www.hackerearth.com/practice/data-structures/arrays/multi-dimensional/practice-problems/algorithm/the-wealthy-landlord/
This is my code:
#include <stdio.h>
#define ll long long
int main () {
ll int N;
scanf("%d", &N);
ll int i, j, a, b;
ll int TOTAL;
typedef struct {
ll int flag;
ll int count;
// int fc[N]; // farmer cost OR cost for farmer i
ll int *fc;
} land;
// check whether all of them have been
// initialised to 0
// printf("%d ", arr[2][2].count);
// yes
land arr[1000][1000];
for(i=0; i<1000; i++) {
for(j=0; j<1000; j++) {
arr[i][j].fc = (ll int *)calloc(N, sizeof(ll int));
}
}
ll int x1, y1, x2, y2, c;
ll int ta, tb; // temp a // temp b
for(i=0; i<N; i++) {
scanf("%lld %lld %lld %lld %lld", &x1, &y1, &x2, &y2, &c);
// the array index starts from 0
// so to match the inputs to the correct indices
// the inputs must be reduced by one
for(a=x1; a<=x2; a++) {
for (b=y1; b<=y2; b++) {
ta = a-1;
tb = b-1;
arr[ta][tb].count++;
if(arr[ta][tb].count >= 2)
arr[ta][tb].flag = 1;
arr[ta][tb].fc[i] = c;
}
}
}
ll int k;
for(i=0; i<1000; i++) {
for(j=0; j<1000; j++) {
if (arr[i][j].flag == 1) {
for(k=0; k<N; k++)
TOTAL += arr[i][j].fc[k];
}
}
}
printf("%lld", TOTAL);
return 0;
}
RESULT: Runtime Error (SIGSEGV)
Compilation Log:
Compiled Successfully
Execution Log: Execution failed.Segmentation Fault : This occurs
because of an out-of-scope array index that is causing a buffer
overflow, an incorrectly initialized pointer, etc. A signal is
generated when a program either tries to read or write outside the
memory that is allocated for it or to write memory that can only be
read. For example, you are accessing a[-1] in a language that does not
support negative indices for an array.
I've edited this code multiple times and fixed various issues by looking at various SO questions. Now it is so close to working, but it just makes a straight face and says segmentation fault. The worst kind of fault that gives you little to no hints on how it should be fixed. I am out of ideas!
ALSO - There probably is a better method to solve this problem which does not involve arrays inside a 2-D array of structures, but I would love to learn how to fix this segmentation fault.
Your line: land arr[1000][1000]; declares arr as an automatic variable, which means that space is allocated to it from the stack. Put simply, this stack is memory assigned for local use when a function is called (and main is really just a function called by the operating system when you run the program).
Typically, the amount of space available on the stack is limited - typically 16 - 64 kilobytes. However, your arr variable (assuming 8 bytes for a long long int and 8 bytes for a pointer) will require more than 24 megabytes. This is almost certainly what is causing your "Stack Overflow!"
A 'quick fix' to this problem is to declare the variable static. This means that space is allocated at compile time (or, more likely, at link time) and is 'locked' into memory while the program is running. (You may notice that the size of your executable file increases by 24 MB after you do this - depending on your platform!)
Here is a slightly modified version of your code, with this correction, along with a couple of other suggested improvements (all marked with the "///" comment delimiter:
#include <stdio.h>
#include <stdlib.h>
#define ll long long
int main() {
ll int N;
scanf("%lld", &N); /// The plain "%d" format expects an "int" argument - use "%lld" for "long long int"
ll int i, j, a, b;
ll int TOTAL = 0; /// If you don't INITIALIZE "TOTAL" it could start off with ANY value whatsoever!
typedef struct {
ll int flag;
ll int count;
// int fc[N]; // farmer cost OR cost for farmer i
ll int* fc;
} land;
// check whether all of them have been
// initialised to 0
// printf("%d ", arr[2][2].count);
// yes
static land arr[1000][1000]; /// Without "static" this array (~ 24 Megabytes) will overflow the stack!
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
arr[i][j].fc = (ll int*)calloc(N, sizeof(ll int));
}
}
ll int x1, y1, x2, y2, c;
ll int ta, tb; // temp a // temp b
for (i = 0; i < N; i++) {
scanf("%lld %lld %lld %lld %lld", &x1, &y1, &x2, &y2, &c);
// the array index starts from 0
// so to match the inputs to the correct indices
// the inputs must be reduced by one
for (a = x1; a <= x2; a++) {
for (b = y1; b <= y2; b++) {
ta = a - 1;
tb = b - 1;
arr[ta][tb].count++;
if (arr[ta][tb].count >= 2)
arr[ta][tb].flag = 1;
arr[ta][tb].fc[i] = c;
}
}
}
ll int k;
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
if (arr[i][j].flag == 1) {
for (k = 0; k < N; k++)
TOTAL += arr[i][j].fc[k];
}
}
}
printf("%lld", TOTAL);
return 0;
}
Feel free to ask for further clarification and/or explanation.

OpenMP segmentation fault

recently I am working on a c OpenMP code which carrying out the affinity scheduling. Basically, after a thread has finished its assigned iterations, it will start looking for other threads which has the most work load and steal some jobs from them.
Everything works fine, I can compile the file using icc. However, when I try to run it, it gives me the segmentation fault(core dumped). But the funny thing is, the error is not always happen, that is, even I get an error when I first run the code, when I try to run again, sometimes it works. This is so weird to me. I wonder what I did wrong in my code and how to fix the problem. Thank you. I did only modified the method runloop and affinity, others are given at the beginning which works fine.
#include <stdio.h>
#include <math.h>
#define N 729
#define reps 1000
#include <omp.h>
double a[N][N], b[N][N], c[N];
int jmax[N];
void init1(void);
void init2(void);
void runloop(int);
void loop1chunk(int, int);
void loop2chunk(int, int);
void valid1(void);
void valid2(void);
int affinity(int*, int*, int, int, float, int*, int*);
int main(int argc, char *argv[]) {
double start1,start2,end1,end2;
int r;
init1();
start1 = omp_get_wtime();
for (r=0; r<reps; r++){
runloop(1);
}
end1 = omp_get_wtime();
valid1();
printf("Total time for %d reps of loop 1 = %f\n",reps, (float)(end1-start1));
init2();
start2 = omp_get_wtime();
for (r=0; r<reps; r++){
runloop(2);
}
end2 = omp_get_wtime();
valid2();
printf("Total time for %d reps of loop 2 = %f\n",reps, (float)(end2-start2));
}
void init1(void){
int i,j;
for (i=0; i<N; i++){
for (j=0; j<N; j++){
a[i][j] = 0.0;
b[i][j] = 3.142*(i+j);
}
}
}
void init2(void){
int i,j, expr;
for (i=0; i<N; i++){
expr = i%( 3*(i/30) + 1);
if ( expr == 0) {
jmax[i] = N;
}
else {
jmax[i] = 1;
}
c[i] = 0.0;
}
for (i=0; i<N; i++){
for (j=0; j<N; j++){
b[i][j] = (double) (i*j+1) / (double) (N*N);
}
}
}
void runloop(int loopid)
{
int nthreads = omp_get_max_threads(); // we set it before the parallel region, using opm_get_num_threads() will always return 1 otherwise
int ipt = (int) ceil((double)N/(double)nthreads);
float chunks_fraction = 1.0 / nthreads;
int threads_lo_bound[nthreads];
int threads_hi_bound[nthreads];
#pragma omp parallel default(none) shared(threads_lo_bound, threads_hi_bound, nthreads, loopid, ipt, chunks_fraction)
{
int myid = omp_get_thread_num();
int lo = myid * ipt;
int hi = (myid+1)*ipt;
if (hi > N) hi = N;
threads_lo_bound[myid] = lo;
threads_hi_bound[myid] = hi;
int current_lower_bound = 0;
int current_higher_bound = 0;
int affinity_steal = 0;
while(affinity_steal != -1)
{
switch(loopid)
{
case 1: loop1chunk(current_lower_bound, current_higher_bound); break;
case 2: loop2chunk(current_lower_bound, current_higher_bound); break;
}
#pragma omp critical
{
affinity_steal = affinity(threads_lo_bound, threads_hi_bound, nthreads, myid, chunks_fraction, &current_lower_bound, &current_higher_bound);
}
}
}
}
int affinity(int* threads_lo_bound, int* threads_hi_bound, int num_of_thread, int thread_num, float chunks_fraction, int *current_lower_bound, int *current_higher_bound)
{
int current_pos;
if (threads_hi_bound[thread_num] - threads_lo_bound[thread_num] > 0)
{
current_pos = thread_num;
}
else
{
int new_pos = -1;
int jobs_remain = 0;
int i;
for (i = 0; i < num_of_thread; i++)
{
int diff = threads_hi_bound[i] - threads_lo_bound[i];
if (diff > jobs_remain)
{
new_pos = i;
jobs_remain = diff;
}
}
current_pos = new_pos;
}
if (current_pos == -1) return -1;
int remaining_iterations = threads_hi_bound[current_pos] - threads_lo_bound[current_pos];
int iter_size_fractions = (int)ceil(chunks_fraction * remaining_iterations);
*current_lower_bound = threads_lo_bound[current_pos];
*current_higher_bound = threads_lo_bound[current_pos] + iter_size_fractions;
threads_lo_bound[current_pos] = threads_lo_bound[current_pos] + iter_size_fractions;
return current_pos;
}
void loop1chunk(int lo, int hi) {
int i,j;
for (i=lo; i<hi; i++){
for (j=N-1; j>i; j--){
a[i][j] += cos(b[i][j]);
}
}
}
void loop2chunk(int lo, int hi) {
int i,j,k;
double rN2;
rN2 = 1.0 / (double) (N*N);
for (i=lo; i<hi; i++){
for (j=0; j < jmax[i]; j++){
for (k=0; k<j; k++){
c[i] += (k+1) * log (b[i][j]) * rN2;
}
}
}
}
void valid1(void) {
int i,j;
double suma;
suma= 0.0;
for (i=0; i<N; i++){
for (j=0; j<N; j++){
suma += a[i][j];
}
}
printf("Loop 1 check: Sum of a is %lf\n", suma);
}
void valid2(void) {
int i;
double sumc;
sumc= 0.0;
for (i=0; i<N; i++){
sumc += c[i];
}
printf("Loop 2 check: Sum of c is %f\n", sumc);
}
You don't initialise the arrays threads_lo_bound and threads_hi_bound, so they initially contain some completely random values (this is source of randomness number 1).
You then enter the parallel region, where it is imperative to realise not all threads will be moving through the code in sync, the actual speed of each threads is quite random as it shares the CPU with many other programs, even if they only use 1%, that will still show (this is source of randomness number 2, I'd argue this one is more relevant to why you see it working every now and then).
So what happens when the code crashes?
One of the threads (most likely the master) reaches the critical region before at least one of the other threads has reached the line where you set threads_lo_bound[myid] and threads_hi_bound[myid].
After that, depending on what those random values stored in there were (you can generally assume they were out of bounds, your array is fairly small, the odds of those values being valid indices are pretty slim), the thread will try to steal some of the jobs (that don't exist) by setting current_lower_bound and/or current_upper_bound to some value that is out of range of your initial arrays a, b, c.
It will then enter the second iteration of your while(affinity_steal != -1) loop and access memory that is out of bounds inevitably leading to a segmentation fault (eventually, in principle it's undefined behaviour and the crash can occur at any point after an invalid memory access, or in some cases never, leading you to believe everything is in order, when it is most definitely not).
The fix of course is simple, add
#pragma omp barrier
just before the while(affinity_steal != -1) loop to ensure all threads have reached that point (i.e. synchronise the threads at that point) and the bounds are properly set before you proceed into the loop. The overhead of this is minimal, but if for some reason you wish to avoid using barriers, you can simply set the values of the array before entering the parallel region.
That said, bugs like this can usually be located using a good debugger, I strongly suggest learning how to use one, they make life much easier.

What's wrong with my Mandelbrot set code?

I'm trying to implement the Mandelbrot set in C, but I'm having a weird problem. My code is as follows:
#include <stdio.h>
#include <math.h>
#include <complex.h>
int iterate_pt(complex c);
int main() {
FILE *fp;
fp = fopen("mand.ppm", "w+");
double crmin = -.75;
double crmax = -.74;
double cimin = -.138;
double cimax = -.75; //Changing this value to -.127 fixed my problem.
int ncols = 256;
int nrows = 256;
int mand[ncols][nrows];
int x, y, color;
double complex c;
double dx = (crmax-crmin)/ncols;
double dy = (cimax-cimin)/nrows;
for (x = 0; x < ncols; x++){
for (y = 0; y < nrows; y++){
double complex imaginary = 0+1.0i;
c = crmin+(x*dx) + (cimin+(y*dy)) * imaginary;
mand[x][y] = iterate_pt(c);
}
}
printf("Printing ppm header.");
fprintf(fp, "P3\n");
fprintf(fp, "%d %d\n255\n\n", ncols, nrows);
for (x = 0; x < ncols; x++) {
for (y = 0; y < nrows; y++){
color = mand[x][y];
fprintf(fp, "%d\n", color);
fprintf(fp, "%d\n", color);
fprintf(fp, "%d\n\n", color); //Extra new line added, telling the ppm to go to next pixel.
}
}
fclose(fp);
return 0;
}
int iterate_pt(double complex c){
double complex z = 0+0.0i;
int iterations = 0;
int k;
for (k = 1; k <= 255; k++) {
z = z*z + c;
if (sqrt( z*conj(z) ) > 50){
break;
}
else
++iterations;
}
return iterations;
}
However, the output of this program, which is stored as a ppm file looks like this:
Thanks for your help!
Try setting cimax to -0.127, I'm also working on this project and it seems to do the trick ;)
The code looks good.
But your starting rectangle doesn't look right!
you are using
Real ranage [ -.75 , -.74 ]
Imag range [ -.138 , -.75 ]
are you sure this is what you intended? It seems like an awfully stretched y-scale to me.
Also, standard mandelbrot algorithms tend to use
magnitude > 2
rather than 50.
as an escape check. Though this shouldn't affect the actual shape of the set.
BTW, there's no point in computing the sqrt of z*conj(z). Simply square the expressions on both sides of the inequality, giving if (z*conj(z) > 2500) and you've boosted the performance.

Resources