Math Equation not outputting result I want - c

The purpose of the program is to calculate the volume at each depth. The inputs are the radius and length and in this test case they are 2.1 and 5.6 respectively. I keep getting 0, 1, 2, 3, and 4 for my volume but that's not the right volume, the depth/height is correct so perhaps someone can shed light on whats wrong with my equation below?
This is the function that calculates the volume
int getVolume(double arrplotptr[][col], double *arr2ptr, char *nameptr)
{
double vol, h, diam, ctr, rad, len, x;
int i, j;
rad = arr2ptr[radius];
len = arr2ptr[length];
diam = (rad * 2);
ctr = diam / 100;
h = 0;
for (j = 0; j < 100; j++) {
h = h + ctr;
arrplotptr[0][j] = h;
}
h = 0;
for (i = 0; i < 100; i++) {
h = h + ctr;
x = (rad - h) / rad;
vol = ((rad * rad) * acos(x) - (rad - h) * (sqrt((2 * rad * h) - (h * h)))) * len;
arrplotptr[1][i] = vol;
}
}

I see several issues in your code:
Why do you use ctr = diam / 100; instead of ctr = rad / 100;?
You do not return a value from getVolume, if the caller function relies on the return value, you invoke undefined behavior.
You store the volume of each slice but do not compute the total volume. You did not post the code that does that, maybe there are problems there too.

As written by chqrlie, I think you should change
ctr = diam / 100;
with
ctr = rad / 100;
And, as written by EOF, the function is defined as "int" but returns no value; You should redefine it as "void" or return an integer value.
I add that it doesn't seem necessary to double loop: in each iteration you can calculate "h", "x", "vol" and save the two values of "arrplotptr".
I propose to simplify the function as follows
void getVolume (double arrplotptr[][col], double arr2ptr[])
{
double const rad = arr2ptr[radius];
double const len = arr2ptr[length];
double const ctr = rad / 100;
int i;
double h;
for ( i = 0, h = ctr ; i < 100 ; ++i, h+=ctr )
{
arrplotptr[0][i] = h;
arrplotptr[1][i] = ((rad * rad) * acos((rad - h) / rad)
- (rad - h) * (sqrt((2 * rad * h) - (h * h)))) * len;
}
}

Related

Miscalculation of Lagrange interpolation formula for higher degree

I am approximating Runge’s function using Lagrange’s interpolation formula for 50 interpolation points. I have written the following program to do this, but I am getting the wrong value for x= -0.992008. That wrong value is 4817543.091313, but it should be 5197172.55933613. I have got this value from the following link: Link The code used are as follows:
#include <stdio.h>
#include <math.h>
double
runge(double x)
{
return (1 / (1 + (25 * x * x)));
}
double
ab(double x)
{
if (x < 0)
return -1 * x;
return x;
}
double
lag_func(double x, double *y_i, double *x_i, int n)
{
double ex = 0.0;
for (int i = 0; i <= n; i++) {
double numer = 1.0,
denom = 1.0,
prod = 1.0;
for (int j = 0; j <= n; j++) {
if (i != j) {
numer = (x - x_i[j]);
denom = (x_i[i] - x_i[j]);
prod *= numer / denom;
}
}
ex += (prod) * y_i[i];
}
return ex;
}
int
main()
{
int n;
scanf("%d", &n);
double y_i[n + 1],
x_i[n + 1];
for (int i = 0; i < n + 1; i++) {
x_i[i] = ((2 * (double) i) / (double) n) - 1;
y_i[i] = runge(x_i[i]);
}
printf("%lf\n", lag_func(-0.992008, y_i, x_i, n));
return 0;
}
The web site is rounding its Runge coefficients to six digits. Given the magnitudes of the terms involved, up to 3.9978•1011, this introduces multiple errors up to around 2•105.
This can be seen by inserting y_i[i] = round(y_i[i] * 1e6) / 1e6; after y_i[i] = runge(x_i[i]);. Then the output of the program is 5197172.558199, matching the web site’s inaccurate result.
The web site is wrong; the result of the code in the question is better.

Gradient descent returning nan

I need to write a function to get a curve fit of a dataset. The code below is what I have. It attempts to use gradient descent to find polynomial coefficients which best fit the data.
//solves for y using the form y = a + bx + cx^2 ...
double calc_polynomial(int degree, double x, double* coeffs) {
double y = 0;
for (int i = 0; i <= degree; i++)
y += coeffs[i] * pow(x, i);
return y;
}
//find polynomial fit
//returns an array of coefficients degree + 1 long
double* poly_fit(double* x, double* y, int count, int degree, double learningRate, int iterations) {
double* coeffs = malloc(sizeof(double) * (degree + 1));
double* sums = malloc(sizeof(double) * (degree + 1));
for (int i = 0; i <= degree; i++)
coeffs[i] = 0;
for (int i = 0; i < iterations; i++) {
//reset sums each iteration
for (int j = 0; j <= degree; j++)
sums[j] = 0;
//update weights
for (int j = 0; j < count; j++) {
double error = calc_polynomial(degree, x[j], coeffs) - y[j];
//update sums
for (int k = 0; k <= degree; k++)
sums[k] += error * pow(x[j], k);
}
//subtract sums
for (int j = 0; j <= degree; j++)
coeffs[j] -= sums[j] * learningRate;
}
free(sums);
return coeffs;
}
And my testing code:
double x[] = { 0, 1, 2, 3, 4 };
double y[] = { 5, 3, 2, 3, 5 };
int size = sizeof(x) / sizeof(*x);
int degree = 1;
double* coeffs = poly_fit(x, y, size, degree, 0.01, 1000);
for (int i = 0; i <= degree; i++)
printf("%lf\n", coeffs[i]);
The code above works when degree = 1, but anything higher causes the coefficients to come back as nan.
I've also tried replacing
coeffs[j] -= sums[j] * learningRate;
with
coeffs[j] -= (1/count) * sums[j] * learningRate;
but then I get back 0s instead of nan.
Anyone know what I'm doing wrong?
I tried degree = 2, iteration = 10 and got results other than nan (values around a few thousands) Adding one to iteration seems making magnitude of the results larger by about 3 times after that.
From this observation, I guessed that the results are being multiplied by count.
In the expression
coeffs[j] -= (1/count) * sums[j] * learningRate;
Both of 1 and count are integers, so integer division is done in 1/count and it will become zero if count is larger than 1.
Instead of that, you can divide the result of multiplication by count.
coeffs[j] -= sums[j] * learningRate / count;
Another way is using 1.0 (double value) instead of 1.
coeffs[j] -= (1.0/count) * sums[j] * learningRate;
Aside:
A candidate NAN source is adding opposite signed values where one is an infinity. Given OP is using pow(x, k), which grows rapidly, using other techniques help.
Consider a chained multiplication rather than pow(). The result is usually more numerically stable. calc_polynomial() for example:
double calc_polynomial(int degree, double x, double* coeffs) {
double y = 0;
// for (int i = 0; i <= degree; i++)
for (int i = degree; i >= 0; i--)
//y += coeffs[i] * pow(x, i);
y = y*x + coeffs[i];
}
return y;
}
Similar code could be used for the main() body.

Exception thrown, Dynamic memory allocation in C

Hi I'm trying to do dynamic memory allocation of a large matrix in C but I'm running into the following error:
Exception thrown at 0x00007FF63A248571 in cdempd.exe: 0xC0000005: Access violation writing location 0x0000000000000000. occurred
sometimes it's Access violation writing location 0xFFFFFFFFB412E2A0.
double ndivx, ndivy, ndivz, nt, r, box, dx, totnode;
int main()
{
ndivx = 19.0;
ndivy = 19.0;
ndivz = 19.0;
int totnode = ndivx * ndivy * ndivz;
r = 0.005; //diameter of sphere
dx = 0.0025 / ndivx;
double dx = r / ndivx; // distance between points
int cols = 3;
int** coords;
coords = malloc(totnode * sizeof(int*));
for (int i = 0; i < totnode; i++) {
coords[i] = malloc(cols * sizeof(int));
}
//int* coord = (int*)malloc(totnode * cols * sizeof(int));
// int offset = i * cols + j;
// now mat[offset] corresponds to m(i, j)
//create a cube of equidistant points
int numm = 0;
for (int i = 1; i <= ndivx; i++)
{
for (int j = 1; j <= ndivy; j++)
{
for (int k = 1; k <= ndivz; k++)
{
coords[numm][0] = -1.0 / 2.0 * (r)+(dx / 2.0) + (i - 1.0) * dx;
coords[numm][1] = -1.0 / 2.0 * (r)+(dx / 2.0) + (j - 1.0) * dx;
coords[numm][2] = -1.0 / 2.0 * (r)+(dx / 2.0) + (k - 1.0) * dx;
numm = numm + 1;
}
}
}
}
pd.r is a double 0.005, dx is a double about 0.00026315, totnode is 6859.
I've tried two methods, the one that is there and the one commented out with //. Both give me the same error. I'm using visual studio 2019. I'm not so familiar with c and visual studio so forgive me if the question is silly. Any help would be appreciated thank you.
Aside from some of the other errors [after correction], all values of coords are set to zero. This is because coords is a pointer to int and not (e.g.) double and your equation uses -1.0 / ... which will always produce a fraction.
Also, as David pointed out, you're indexing from 1 [vs. 0] in the for loops. This could cause access violations/segfaults.
I've changed the for loops to start from 0. And, I've adjusted the equation accordingly (using a macro).
You were defining some things like index variables or size variables as double instead of int (e.g.) ndivx
Also, I introduced a typedef for the coordinate values.
Here's some cleaned up code that may help get you further:
#include <stdio.h>
#include <stdlib.h>
#if 0
double ndivx, ndivy, ndivz, nt, r, box, dx, totnode;
#endif
#if 0
typedef int coord_t;
#else
typedef double coord_t;
#endif
#define SETCOORD(_xidx,_var) \
do { \
coords[numm][_xidx] = -1.0 / 2.0 * r + (dx / 2.0) + (_var * dx); \
printf("coords[%d][%d]=%g\n",numm,_xidx,(double) coords[numm][_xidx]); \
} while (0)
int
main(void)
{
#if 1
int ndivx;
int ndivy;
int ndivz;
double r;
double dx;
#endif
ndivx = 19;
ndivy = 19;
ndivz = 19;
int totnode = ndivx * ndivy * ndivz;
r = 0.005; // diameter of sphere
dx = 0.0025 / ndivx;
#if 0
double dx = r / ndivx; // distance between points
#else
dx = r / ndivx; // distance between points
#endif
int cols = 3;
#if 0
int **coords;
#else
coord_t **coords;
#endif
coords = malloc(totnode * sizeof(coord_t *));
for (int i = 0; i < totnode; i++) {
coords[i] = malloc(cols * sizeof(coord_t));
}
// int* coord = (int*)malloc(totnode * cols * sizeof(int));
// int offset = i * cols + j;
// now mat[offset] corresponds to m(i, j)
// create a cube of equidistant points
int numm = 0;
for (int i = 0; i < ndivx; i++) {
for (int j = 0; j < ndivy; j++) {
for (int k = 0; k < ndivz; k++) {
SETCOORD(0,i);
SETCOORD(1,j);
SETCOORD(2,k);
numm = numm + 1;
}
}
}
return 0;
}

Why is the numerical solution coming same as analytical solution in C language?

I have coded a 1 dimension cfd problem but my numerical solution is coming same as to the analytical solution (up to 6 decimal places).
I am using TDMA method for numerical solution and for the analytical solution I am directly substituting the x value in the function T(x).
Analytical solution T(x) comes out to be T(x) = -(x^2)/2 +11/21(x);
E. g. 4 grid points then ;
x0 = 0.000000, x1 = 0.333333 , x2 = 0.666666 , x3 = 0.999999 .
T(x0) = 0.000000 , T(x1) = 0.119048 , T(x2) = 0.126984 , T(x3) = 0.023810.
And for numerical solution I have used TDMA technique, please refer the code below.
Enter n = 4 for the results.
#include<stdio.h>
void temp_matrix(int n, double *a, double *b, double *c, double *d, double *T);
int main() {
int Bi = 20.0;
int n;
printf("%s ", "Enter the Number of total Grid Points");
scanf("%d", &n);
float t = (n - 1);
double dx = 1.0 / t;
int i;
printf("\n");
double q; // analytical solution below
double z[n];
for (i = 0; i <= n - 1; i++) {
q = (dx) * i;
z[i] = -(q * q) / 2 + q * (11.0 / 21);
printf("\nT analytical %lf ", z[i]);
}
double b[n - 1];
b[n - 2] = -2.0 * Bi * dx - 2.0;
for (i = 0; i <= n - 3; i++) {
b[i] = -2.0;
}
double a[n - 1];
a[n - 2] = 2.0;
a[0] = 0;
for (i = 1; i < n - 2; i++) {
a[i] = 1.0;
}
double c[n - 1];
for (i = 0; i <= n - 2; i++) {
c[i] = 1.0;
}
double d[n - 1];
for (i = 0; i <= n - 2; i++) {
d[i] = -(dx * dx);
}
double T[n];
temp_matrix(n, a, b, c, d, T);
return 0;
}
void temp_matrix(int n, double *a, double *b, double *c, double *d, double *T) {
int i;
double beta[n - 1];
double gama[n - 1];
beta[0] = b[0];
gama[0] = d[0] / beta[0];
for (i = 1; i <= n - 2; i++) {
beta[i] = b[i] - a[i] * (c[i - 1] / beta[i - 1]);
gama[i] = (d[i] - a[i] * gama[i - 1]) / beta[i];
}
int loop;
for (loop = 0; loop < n - 1; loop++)
for (loop = 0; loop < n - 1; loop++)
T[0] = 0;
T[n - 1] = gama[n - 2];
for (i = n - 2; i >= 1; i--) {
T[i] = gama[i - 1] - (c[i - 1] * (T[i + 1])) / beta[i - 1];
}
printf("\n");
for (i = 0; i < n; i++) {
printf("\nT numerical %lf", T[i]);
}
}
Why is the numerical solution coming same as analytical solution in C language?
They differ, by about 3 bits.
Print with enough precision to see the difference.
Using the below, we see a a difference in the last hexdigit of the significand of x620 vs x619 of T[3]. This is only 1 part in 1015 difference.
#include<float.h>
printf("T analytical %.*e\t%a\n", DBL_DECIMAL_DIG - 1, z[i], z[i]);
printf("T numerical %.*e\t%a\n", DBL_DECIMAL_DIG - 1, T[i], T[i]);
C allows double math to be performed at long double math when FLT_EVAL_METHOD == 2 and then the same analytical/numerical results. Your results may differ from mine due to that as well as other subtle FP nuances.
printf("FLT_EVAL_METHOD %d\n", FLT_EVAL_METHOD);
Output
T analytical 0.0000000000000000e+00 0x0p+0
T analytical 1.1904761904761907e-01 0x1.e79e79e79e7ap-4
T analytical 1.2698412698412700e-01 0x1.0410410410411p-3
T analytical 2.3809523809523836e-02 0x1.861861861862p-6
T numerical 0.0000000000000000e+00 0x0p+0
T numerical 1.1904761904761904e-01 0x1.e79e79e79e79ep-4
T numerical 1.2698412698412698e-01 0x1.041041041041p-3
T numerical 2.3809523809523812e-02 0x1.8618618618619p-6
FLT_EVAL_METHOD 0

Sobel Operator C - Edge detection gone wrong

I ve been trying hard to calculate the gradient (and dips) of a binary image in C using the Sobel operator. I ve already checked the operators several times and went through tons of internet sites. Nevertheless, I have to admit that I have no experience with image processing and I am quite a rookie in C coding. I dont get any error messages, but the result does not show the desired gradients on the edges.
Somehow the gradient in the x-direction is not calculated - but why?
Thanks for the help!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
FILE *infile, *outfile;
int main(int argc, char *argv[])
{
int nx,nz,k,i,nu;
int j,m,l;
int km, kp, im, ip, kpp, ipp;
float Gx, Gz, G, Gmax, Gmin;
float T;
float **dip;
float pi;
float *tmp;
float *bufz;
float **temp1;
char *velfile_in = "vel";//"vel_315_273";
char *velfile_out = "dip";
void *alloc1 (size_t n1, size_t size);
void **alloc2(size_t n1, size_t n2, size_t size);
void ***alloc3(size_t n1, size_t n2, size_t n3, size_t size);
pi = 4. * atan(1.);
// Initiate constants
T = atof(argv[1]);
nx = atoi(argv[2]);
nz = atoi(argv[3]);
Gmax = 0.;
Gmin = 10e8;
// border handling (cyclic)
km = (k+nz-1) % nz;
kp = (k+1) % nz;
kpp = (k+2) % nz;
im = (i+nx-1) % nx;
ip = (i+1) % nx;
ipp = (i+2) % nx;
// allocate 1D, 2D and 3D arrays
tmp = (float *)alloc1(nz,sizeof(float));
bufz = (float *)alloc1(nz,sizeof(float));
temp1 = (float **)alloc2(nx,nz,sizeof(float));
dip = (float **)alloc2(nx,nz,sizeof(float));
//READ FILE
//***********************************************************
infile = fopen(velfile_in, "r");
if (infile == NULL) err("Error: could not open file.");
for (i=0; i<nx; i++) {
nu = fread(tmp,sizeof(float),nz,infile);
for (k=0; k<nz; k++) {
temp1[k][i] = tmp[k];
}
}
fclose(infile);
// APPLY SOBEL****************************************
for (i = 0; i < nx; i++)
{
for (k = 0; k < nz; k++)
{
Gx = (temp1[km][im] - temp1[km][ip] + 2 * temp1[k][im] - 2 * temp1[k][ip] + temp1[kp][im] - temp1[kp][ip]);
Gz = (temp1[km][im] - temp1[kp][im] + 2 * temp1[km][i] - 2 * temp1[kp][i] + temp1[km][ip] - temp1[kp][ip]);
G = sqrtf(Gx * Gx + Gz * Gz);
Gmax = (Gmax > G ? Gmax : G);
Gmin = (Gmin < G ? Gmin : G);
dip[k][i] = abs(atan(Gz/Gx) * 180. / pi);
printf("(%d,%d)\tGx:%5.3f\tGz%5.3f\tG%5.3f\n",i,k,Gx,Gz,G);
}
}
printf("Gmax:%5.3f\tGmin:%5.3f\n",Gmax,Gmin);
// write file ********************************************************
outfile = fopen(velfile_out,"w");
for (i=0; i<nx; i++) {
for (k=0; k<nz; k++) bufz[k] = dip[k][i];
fwrite(bufz,sizeof(float),nz,outfile);
}
fclose(outfile);
return 0;
}
The obvious problem is that your convolution kernel isn't moving - the array indices are all separate variables and need updating to stay in sync with i and j. Moving the assignments inside the loops should fix that:
...
for (i = 0; i < nx; i++)
{
im = (i+nx-1) % nx;
ip = (i+1) % nx;
ipp = (i+2) % nx;
for (k = 0; k < nz; k++)
{
km = (k+nz-1) % nz;
kp = (k+1) % nz;
kpp = (k+2) % nz;
...

Resources