Problem finding the local maximum of a function in C - c

I'm designing an algorithm to define a simple method able to find the local maximum of a function f (x) given in an interval [a, b]
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.141592653
float funtion_(float a, float x){
float result=0;
result = a * (sin (PI*x));
return result;
}
int main (){
double A = 4.875; //average of the digits of the identification card
double a = 0.0, b =1.0; //maximum and minimum values of the interval [a, b]
double h=0;
double N;
double Max, x;
double sin_;
double inf;
printf ("input the minux value: ");
scanf ("%lf", &inf);
printf ("input the N value: ");
scanf ("%lf", &N);
h= (b-a)/N;
printf("h = %lf\n", h);
x=a-h;
Max = -inf;
do {
x = x+h;
sin_ = funtion_(A, x);
if (sin_>=Max){
Max = sin_;
}
}while (x==b);
printf ("Maximum value: %lf.5", Max);
return 0;
}
The algorithm implements the function f (x) = A * sin (pi * x), where A is the average of the digits of my ID, and inf variable is assigned a number sufficiently greater than the values ​​reached by the function in the interval [a, b] = [0.1].
The algorithm must find the local maximum of the function but it is the maximum returns always zero. do not understand why. What problem may be the logic of my solution?, this problem can be solved by this simple algorithm or some optimization by backtracking is necessary ? Thanks for your responses.

Several problems with this code; probably the most glaring is:
int a = 0, b = 1;
float Max, x;
/* ... */
do {
/* ... */
} while (x == b);
You cannot compare an int and a float for equality. It might work once in a great while due to dumb luck :) but you cannot expect this code to function reliably.
I strongly recommend changing all your int variables to double, all your float variables to double, and all the scanf(3) and printf(3) calls to match. While you can combine different primitive number types in one program, and even in one expression or statement, subtle differences in execution will take you hours to discover.
Furthermore, comparing floating point formats for equality is almost never a good idea. Instead, compare the difference between two numbers to a epsilon value:
if (fabs(a-b) < 0.001)
/* consider them equal */
You might want to scale your epsilon so that it matches the scale of your problem; since float really only supports about seven digits of precision, this comparison wouldn't work well:
if (fabsf(123456789 - 123456789.1) < 0.5)
/* oops! fabsf(3) used to force float */
/* and float can't tell the difference */
You might want to find a good introduction to numerical analysis. (Incidentally, one of my favorite classes back in school. :)
update
The core of the problem is your while(x == b). I fixed that and a few smaller problems, and this code seems to work:
#include
#include
#include
#define PI 3.141592653
float funtion_(float a, float x)
{
float result = 0;
result = a * (sin(PI * x));
return result;
}
int main()
{
float A = 4.875; //average of the digits of the identification card
float a = 0.0, b = 1.0; //maximum and minimum values of the interval [a, b]
float h = 0;
float N;
float Max, x;
float sin_;
float inf;
printf("\ninput the inf value: ");
scanf("%f", &inf);
printf("\ninput the N value: ");
scanf("%f", &N);
h = (b - a) / N;
x = a - h;
Max = -inf;
do {
x = x + h;
sin_ = funtion_(A, x);
if (sin_ >= Max) {
Max = sin_;
printf("\n new Max: %f found at A: %f x: %f\n", Max, A, x);
}
} while (x < b);
printf("Maximum value: %.5f\n", Max);
return 0;
}
Running this program with some small inputs:
$ ./localmax
input the inf value: 1
input the N value: 10
new Max: 0.000000 found at A: 4.875000 x: 0.000000
new Max: 1.506458 found at A: 4.875000 x: 0.100000
new Max: 2.865453 found at A: 4.875000 x: 0.200000
new Max: 3.943958 found at A: 4.875000 x: 0.300000
new Max: 4.636401 found at A: 4.875000 x: 0.400000
new Max: 4.875000 found at A: 4.875000 x: 0.500000
Maximum value: 4.87500
$

You are doing your calculations, in particular the initialisation of h, with integer arithmetic. So in the statement:
h = (b-a) / N;
a, b, and N are all integers so the expression is evaluated as an integer expression, and then converted to a float for assignment to h. You will probably find that the value of h is zero. Try adding the following line after the calculation of h:
printf("h = %f\n", h);
After you've fixed that by doing the calculations with floating point, you need to fix your while loop. The condition x = b is definitely not what you want (I noticed it was originally x == b before your formatting edit, but that's not right either).

Should the while condition be: while(x <= b)

while (x = b);
There is no way to exit the loop. b is always 1.

Related

Why does this code not work for all inputs (Cosine of an angle using Taylor series). Specifically for angles greater than 90 degrees?

This was a homework problem to find cosine of an angle without using the inbuilt cos function
I wrote the following code:
// Program to find cos x using loop.
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
double cosine(double);
int main()
{
double x;
printf("Enter angle in degrees: ");
scanf("%lf", &x);
x = x*M_PI/180.0;
printf("The value of cos(%lf) is %lf", x, cosine(x));
}
double cosine(double x)
{
double previous, current = 1;
double denominator = 1*2, numerator = x*x;
double sign = -1;
while(1)
{
previous = current;
current = current + ((numerator)/(denominator))*sign;
denominator = denominator * (denominator+1) * (denominator+2);
numerator = numerator*x*x;
sign = -sign;
if (fabs(previous - current)<=0.0001)
{
break;
}
}
return current;
}
For x = 180 the answer isn't -1 (which is the correct one)
I have no clue what is going wrong here. Please help I am relatively new at programming.
I tested out your code and found an error in the derivation of the factorial value for your denominator. The following line of code was actually not providing a proper factorial value.
denominator = denominator * (denominator+1) * (denominator+2);
It actually was increasing the denominator value too fast.
With that in mind, I did a bit of refactoring including revising the "while" loop test for previous and current to a simple "for" loop with enough iterations to provide the precision you most likely need. Following is a refactored version of your program.
// Program to find cos x using loop.
#include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
double cosine(double);
int main()
{
double x;
printf("Enter angle in degrees: ");
scanf("%lf", &x);
x = x * M_PI / 180.0;
printf("The value of cos(%lf) is %lf\n", x, cosine(x));
}
double cosine(double x)
{
double current = 1.00;
double denominator = 2.00, numerator = x*x;
double factor = 2.00;
double sign = -1;
for(int i = 0; i < 16; i++)
{
current = current + ((numerator)/(denominator))*sign;
denominator = denominator * (factor+1.00) * (factor+2.00); /* Derives the proper factorial increase */
numerator = numerator * x * x;
sign = -sign;
factor = factor + 2.00;
}
return current;
}
Some points to note.
Instead of the previous formula for calculating the needed factorial, a work field for keeping track of the ascending factorial values is added and incremented as needed and utilized in the denominator calculation.
Instead of testing for smaller and smaller differences with the "while" loop, a "for" loop is utilized with enough iterations to provide a desired precision for the cosine value.
With those tweaks, following were some tests listed at the terminal.
#Vera:~/C_Programs/Console/Taylor/bin/Release$ ./Taylor
Enter angle in degrees: 0
The value of cos(0.000000) is 1.000000
#Vera:~/C_Programs/Console/Taylor/bin/Release$ ./Taylor
Enter angle in degrees: 90
The value of cos(1.570796) is 0.000000
#Vera:~/C_Programs/Console/Taylor/bin/Release$ ./Taylor
Enter angle in degrees: 180
The value of cos(3.141593) is -1.000000
#Vera:~/C_Programs/Console/Taylor/bin/Release$ ./Taylor
Enter angle in degrees: 270
The value of cos(4.712389) is 0.000000
#Vera:~/C_Programs/Console/Taylor/bin/Release$ ./Taylor
Enter angle in degrees: 360
The value of cos(6.283185) is 1.000000
Give those tweaks a try and see if it meets the spirit of your project.

Why is my Taylor series for calculating cosine inaccurate for some inputs?

I am evaluating value of cos(x) using the Taylor's series which calculates the series up to n terms where n is entered by user.
I am getting correct output for some values (correct up to 4 decimal places, which is very nice) but I am also getting hugely erroneous outputs for some values of x.
Please see my code and tell me what is exactly going wrong here.
input x=0.5 n=10, output cos(x) = 0.877583, which is correct.
input x=-0.8 n=7, output cos(x) = 0.696707, again correct.
input x=5 n=10, output cos(x) = 0.283625, correct.
input: x=10 n=10 output: cos(x) = -34.438612 huge inaccuracy
double x, t=1,s=1;
int i,n;
printf("Enter x\n");
scanf("%lf",&x);
printf("Enter n");
scanf("%d",&n);
for(i=1;i<n;i++){
t*=(-x*x)/((2*(i-1)+2)*(2*(i-1)+1));
s+=t;
}
printf("\n %lf \n", s);
Why is my Taylor series for calculating cosine inaccurate for some inputs?
It has been a while, but I am pretty sure that the domain of x is {0..2} for this calculation, as x is in radians.
A test you can add inside your loop is:
if (s < -1 || s > 1) {
fprintf(stderr, "Range error!: %le\n", s);
exit(1);
}
Also, if you have a unix-y system, here is your program in bc, which does not rely on float point approximation:
scale=20
define t(x,n) {
auto i, s, t
s = 1
t = 1
for (i=1; i<n; i++) {
t*=(-x*x)/((2*(i-1)+2)*(2*(i-1)+1))
s+=t
if (s < -1 || s > 1) {
"range error!\n"; return s
}
}
return s
}
You can run this interactively with bc filename, then type in your examples like t(8, 10).
As for whether the sequences converge for all values of x; my math is probably not good enough to answer that. That is why I chose programming, math is hard.
However, here is a cosine definition from an old systems bclib.b:
define c(x) {
auto a, b, c, d, e, g, y;
y = - x*x;
a = 1;
b = 1;
c = b;
d = 1;
e = 1;
for (a=2; 1 == 1; a += 2) {
b *= y;
c = c*a*(a-1) +b;
d *= a*(a-1);
g = c/d;
if (g == e) return (g);
e = g;
}
}
Which is slightly different from yours, yet does seem to work for any range of input. So, you might want to take a look at what is different....
(note that in bc, the variable scale holds the precision the calculator is working in; so c(8,10) is scale=10; c(8)

How to use exp and sqrt properties correctly

-use double precision
-use sqrt() and exponential function exp()
-use * to compute the square
-do not use pow()
I am getting values they are just not anything as to what I expected. I tried making them all signed but it didn't change anything and I've tried printing out with 12 decimal places and nothing seems to be working.I have linked the math library and defined it as well.
double normal(double x, double sigma, double mu)
{
double func = 1.0/(sigma * sqrt(2.0*M_PI));
double raise = 1.0/2.0*((x-mu)/sigma);
double func1 = func * exp(raise);
double comp_func = (func1 * func1);
return comp_func;
}
int main(void)
{
// create two constant variables for μ and σ
const double sigma, mu;
//create a variable for x - only dynamic variable in equation
unsigned int x;
//create a variable for N values of x to use for loop
int no_x;
//scaniing value into mu
printf("Enter mean u: ");
scanf("%lf", &mu);
//scanning value into sigma
printf("Enter standard deviation: ");
scanf("%lf", &sigma);
//if sigma = 0 then exit
if(sigma == 0)
{
printf("error you entered: 0");
exit(0);
}
//storing number of x values in no_x
printf("Number of x values: ");
scanf("%d", &no_x);
//the for loop where i am calling function normal N times
for(int i = 1; i <= no_x; i++)
{
//printing i for the counter in prompted x values
printf("x value %d : ", i);
// scanning in x
scanf("%lf", &x);
x = normal(x,sigma,mu);
printf("f(x) = : %lf.12", x);
printf("\n");
}
return 0;
}
C:>.\a.exe
Enter mean u: 3.489
Enter std dev s: 1.203
Number of x values: 3
x value 1: 3.4
f(X) = 0.330716549275
x value 2: -3.4
f(X) = 0.000000025104
x value 3: 4
f(X) = 0.303015189801
But this is what I am receiving
C:\Csource>a.exe
Enter mean u: 3.489
Enter standard deviation: 1.203
Number of x values: 3
x value 1 : 3.4
f(x) = : 15086080.000000
x value 2 : -3.4
f(x) = : 15086080.000000
x value 3 : 4
f(x) = : 1610612736.000000
Insert these lines:
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
Change:
const double sigma, mu;
to:
double sigma, mu;
Change:
unsigned int x;
to:
double x;
Replace the definition of the normal function with:
double normal(double x, double sigma, double mu)
{
double func = 1.0/(sigma * sqrt(2.0*M_PI));
double t = (x-mu)/sigma;
return func * exp(-t*t/2);
}
#define _CRT_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
#include<math.h>
#include<stdio.h>
#include <stdlib.h>
double normal(double x, double sigma, double mu)
{
double func = 1.0/(sigma * sqrt(2.0*M_PI));
double t = (x-mu)/sigma;
return func * exp((-0.5*t)* t);
}
I Finally got this code above working after tweaking with it literally all day lol, C math can be rather tricky, thank you for the help above as well.

Numerical Differentiation

How can I calculate the numerical second derivative of a function involving an exponential and a singularity at infinity. Unfortunately, the numerical derivative by Ridder's methods provided in "Numerical Recipes in C" can only calculate the first derivative (It requires analytical expression of the function beforehand.) Furthermore I have tried Chebyshev approximation and differentiating the function afterwards but the values given were way off the actual values. I have also tried some finite difference algorithms provided in a mathematical paper yet they were error prone too. The function is e^(x/2) / x^2. I would appreciate any help on the matter.
Thanks in advance
Latest Edit: The issue was solved the FADBAD libraries available in C++ did an extremely good job. They are available via http://www.fadbad.com/fadbad.html
EDIT:
// The compilation command used is given below
// gcc Q3.c nrutil.c DFRIDR.c -lm -o Q3
#include <stdio.h>
#include <math.h>
#include "nr.h"
#define LIM1 20.0
#define a -5.0
#define b 5.0
#define pre 100.0 // This defines the pre
/* This file calculates the func at given points, makes a
* plot. It also calculates the maximum and minimum of the func
* at given points and its first and second numerical derivative.
*/
float func(float x)
{
return exp(x / 2) / pow(x, 2);
}
int main(void)
{
FILE *fp = fopen("Q3data.dat", "w+"), *fp2 = fopen("Q3results.dat", "w+");
int i; // Declaring our loop variable
float x, y, min, max, err, nd1, nd2;
// Define the initial value of the func to be the minimum
min = func(0);
for(i = 0; x < LIM1 ; i++)
{
x = i / pre; // There is a singularity at x = 0
y = func(x);
if(y < min)
min = y;
fprintf(fp, "%f \t %f \n", x, y);
}
fprintf(fp, "\n\n");
max = 0;
for(i = 0, x = a; x < b; i++)
{
x = a + i / pre;
y = func(x);
nd1 = dfridr(func, x, 0.1, &err);
//nd2 = dfridr((*func), x, 0.1, &err);
fprintf(fp, "%f \t %f \t %f \t %f \n", x, y, nd1);
if(y > max)
max = y;
}
fprintf(fp2, "The minimum value of f(x) is %f when x is between 0 and 20. \n", min);
fprintf(fp2, "The maximum value of f(x) is %f when x is between -5 and 5. \n", max);
fclose(fp);
fclose(fp2);
return 0;
}
EDIT: Chebyshev
// The compilation command used is given below
//gcc Q3.c nrutil.c CHEBEV.c CHEBFT.c CHDER.c -lm -o Q3
#include <stdio.h>
#include <math.h>
#include "nr.h"
#define NVAL 150 // Degree of Chebyshev polynomial
#define LIM1 20.0
#define a -5.0
#define b 5.0
#define pre 100.0 // This defines the pre
/* This file calculates the func at given points, makes a
* plot. It also calculates the maximum and minimum of the func
* at given points and its first and second numerical derivative.
*/
float func(float x)
{
return exp(x / 2) / pow(x, 2);
}
int main(void)
{
FILE *fp = fopen("Q3data.dat", "w+"), *fp2 = fopen("Q3results.dat", "w+");
int i; // Declaring our loop variable
float x, y, min, max;
float nd1, nd2, c[NVAL], cder[NVAL], cder2[NVAL];
// Define the initial value of the func to be the minimum
min = func(0);
for(i = 0; x < LIM1 ; i++)
{
x = i / pre; // There is a singularity at x = 0
y = func(x);
if(y < min)
min = y;
fprintf(fp, "%f \t %f \n", x, y);
}
fprintf(fp, "\n\n");
max = 0;
// We make a Chebyshev approximation to our function our interval of interest
// The purpose is to calculate the derivatives easily
chebft(a,b,c,NVAL,func);
//Evaluate the derivatives
chder(a,b,c,cder,NVAL); // First order derivative
chder(a,b,cder,cder2,NVAL); // Second order derivative
for(i = 0, x = a; x < b; i++)
{
x = a + i / pre;
y = func(x);
nd1 = chebev(a,b,cder,NVAL,x);
nd2 = chebev(a,b,cder2,NVAL,x);
fprintf(fp, "%f \t %f \t %f \t %f \n", x, y, nd1, nd2);
if(y > max)
max = y;
}
fprintf(fp2, "The minimum value of f(x) is %f when x is between 0 and 20. \n", min);
fprintf(fp2, "The maximum value of f(x) is %f when x is between -5 and 5. \n", max);
fclose(fp);
fclose(fp2);
return 0;
}
That function is differentiable so using a numeric method is likely not the best. The second derivative is:
6*exp(x/2)/(x^4)-2*exp(x/2)/x^3 + exp(x/2)/(4*x^2)
The above can be simplified of course to speed up computation. Edit: had original formula wrong the first time.
If you want a 100% numeric approach then look at the numerical recipes for a cublic spline interpolation (Charter 3.3). It will give you the 2rd derivative at any location.
call spline() with x and y values to return the 2nd derivatives in y2. The second derivative varies linearly within each interval. So if for example you have
x y y2
0 10 -30
2 5 -15
4 -5 -10
then the 2nd derivative at x=1 is y2=-22.5 which is in-between -30 and -15.
you can also make a new splint() function to return the 2nd derivative a*y2a[i]+b*y2a[i+1]

10k by 10k matrix malloc curiousity in c [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
how to sum a large number of float number?
I have a matrix 'x' that is 10,000 elements by 10,000 elements.
In the first case I declare the matrix like:
int n = 10000;
unsigned int size_M = n*n;
unsigned int mem_size_M = sizeof(int)*size_M;
int* x = (int*)malloc(mem_size_M);
Step (1) The matrix is initialized:
for(i=0;i<n;i++)
for(j=0;j<n;j++)
x[i*n+j] = 1;
Step (2) Sum the elements of the matrix and print the total:
for(i=0i<n;i++)
for(j=0j<n;j++)
sum +=x[i*n+j];
printf("sum: %d \n", sum);
As I would expect the above code prints 'sum: 100000000 '.
However if I declare the matrix like:
int n = 10000;
float size_M = n * n;
float mem_size_M = sizeof(float) * size_M;
float* x = (float*)malloc(mem_size_M);
And again perform the steps 1 and 2 the correct answer is not printed out, but '16777216' instead. Why is this?
ANSWER: To get the appropriate answer do a type conversion...
sum +=(int)x[i*n+j];
This happens because of the precision limitations of the float type. You can't just add 1.0 to float with value > 16777216 (2^24), but you can add 2.0, or 0.1:
#include <stdio.h>
int main(void)
{
float f = 16777220;
printf("f = %f\n", f + 1);
printf("f = %f\n", f + 2);
printf("f = %f\n", f + 0.1);
return 0;
}
The IEEE-754 standard floating-point numbers have have 4 bytes, consisting of a sign bit, an 8-bit excess-127 binary exponent, and a 23-bit mantissa. It's a bit complicated to explain precisely why it happens, but I can say that this is a extreme case when operation error reaches its maximum.

Resources