I've been trying to get this solved but without luck.
All I want to do is to differentiate a polynomial like P(x) = 3x^3 + 2x^2 + 4x + 5
At the end of the code, the program should evaluate this function and gives me just the answer.
The derivative of P(x) is P'(x) = 3*3x^2 + 2*2x + 4*1. If x = 1, the answer is 17.
I just don't get that answer no matter how I alter my loop.
/*
x: value of x in the polynomial
c: array of coefficients
n: number of coefficients
*/
double derivePolynomial(double x, double c[], int n) {
double result = 0;
double p = 1;
int counter = 1;
for(int i=n-1; i>=0; i--) //backward loop
{
result = result + c[i]*p*counter;
counter++; // number of power
p = p*x;
}
return result;
}
//Output in main() looks like this
double x=1.5;
double coeffs[4]={3,2.2,-1,0.5};
int numCoeffs=4;
cout << " = " << derivePolynomial(x,coeffs,numCoeffs) << endl;
The derivative of x ^ n is n * x ^ (n - 1), but you are calculating something completely different.
double der(double x, double c[], int n)
{
double d = 0;
for (int i = 0; i < n; i++)
d += pow(x, i) * c[i];
return d;
}
This would work, assuming that your polinomial is in the form c0 + c1x + c2x ^ 2 + ...
Demonstration, with another function that does the derivation as well.
Edit: alternative solution avoiding the use of the pow() function, with simple summation and repeated multiplication:
double der2(double x, double c[], int n)
{
double d = 0;
for (int i = 0; i < n - 1; i++) {
d *= x;
d += (n - i - 1) * c[i];
}
return d;
}
This works too. Note that the functions that take the iterative approach (those which don't use pow()) expect their arguments (the coefficients) in reverse order.
You need to reverse the direction of the loop. Start at 0 and go to n.
At the moment when you compute the partial sum for the n-th power p is 1. For the last one x^0 you your p will contain x^n-1 th power.
double derivePolynomial(double x, double c[], int n) {
double result = 0;
double p = 1;
int counter = 1;
for(int i=1; i<n; i++) //start with 1 because the first element is constant.
{
result = result + c[i]*p*counter;
counter++; // number of power
p = p*x;
}
return result;
}
double x=1;
double coeffs[4]={5,4,2,3};
int numCoeffs=4;
cout << " = " << derivePolynomial(x,coeffs,numCoeffs) << endl;
Related
I am trying to compute the Anderson-Darling test found here. I followed the steps on Wikipedia and made sure that when I calculate the average and standard deviation of the data I am testing denoted X by using MATLAB. Also, I used a function called phi for computing the standard normal CDF, I have also tested this function to make sure it is correct which it is. Now I seem to have a problem when I actually compute the A-squared (denoted in Wikipedia, I denote it as A in C++).
Here is my function I made for Anderson-Darling Test:
void Anderson_Darling(int n, double X[]){
sort(X,X + n);
// Find the mean of X
double X_avg = 0.0;
double sum = 0.0;
for(int i = 0; i < n; i++){
sum += X[i];
}
X_avg = ((double)sum)/n;
// Find the variance of X
double X_sig = 0.0;
for(int i = 0; i < n; i++){
X_sig += (X[i] - X_avg)*(X[i] - X_avg);
}
X_sig /= n;
// The values X_i are standardized to create new values Y_i
double Y[n];
for(int i = 0; i < n; i++){
Y[i] = (X[i] - X_avg)/(sqrt(X_sig));
//cout << Y[i] << endl;
}
// With a standard normal CDF, we calculate the Anderson_Darling Statistic
double A = 0.0;
for(int i = 0; i < n; i++){
A += -n - 1/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i])));
}
cout << A << endl;
}
Note, I know that the formula for Anderson-Darling (A-squared) starts with i = 1 to i = n, although when I changed the index to make it work in C++, I still get the same result without changing the index.
The value I get in C++ is:
-4e+006
The value I should get, received in MATLAB is:
0.2330
Any suggestions are greatly appreciated.
Here is my whole code:
#include <iostream>
#include <math.h>
#include <cmath>
#include <random>
#include <algorithm>
#include <chrono>
using namespace std;
double *Box_Muller(int n, double u[]);
double *Beasley_Springer_Moro(int n, double u[]);
void Anderson_Darling(int n, double X[]);
double phi(double x);
int main(){
int n = 2000;
double Mersenne[n];
random_device rd;
mt19937 e2(1);
uniform_real_distribution<double> dist(0, 1);
for(int i = 0; i < n; i++){
Mersenne[i] = dist(e2);
}
// Print Anderson Statistic for Mersenne 6a
double *result = new double[n];
result = Box_Muller(n,Mersenne);
Anderson_Darling(n,result);
return 0;
}
double *Box_Muller(int n, double u[]){
double *X = new double[n];
double Y[n];
double R_2[n];
double theta[n];
for(int i = 0; i < n; i++){
R_2[i] = -2.0*log(u[i]);
theta[i] = 2.0*M_PI*u[i+1];
}
for(int i = 0; i < n; i++){
X[i] = sqrt(-2.0*log(u[i]))*cos(2.0*M_PI*u[i+1]);
Y[i] = sqrt(-2.0*log(u[i]))*sin(2.0*M_PI*u[i+1]);
}
return X;
}
double *Beasley_Springer_Moro(int n, double u[]){
double y[n];
double r[n+1];
double *x = new double(n);
// Constants needed for algo
double a_0 = 2.50662823884; double b_0 = -8.47351093090;
double a_1 = -18.61500062529; double b_1 = 23.08336743743;
double a_2 = 41.39119773534; double b_2 = -21.06224101826;
double a_3 = -25.44106049637; double b_3 = 3.13082909833;
double c_0 = 0.3374754822726147; double c_5 = 0.0003951896511919;
double c_1 = 0.9761690190917186; double c_6 = 0.0000321767881768;
double c_2 = 0.1607979714918209; double c_7 = 0.0000002888167364;
double c_3 = 0.0276438810333863; double c_8 = 0.0000003960315187;
double c_4 = 0.0038405729373609;
// Set r and x to empty for now
for(int i = 0; i <= n; i++){
r[i] = 0.0;
x[i] = 0.0;
}
for(int i = 1; i <= n; i++){
y[i] = u[i] - 0.5;
if(fabs(y[i]) < 0.42){
r[i] = pow(y[i],2.0);
x[i] = y[i]*(((a_3*r[i] + a_2)*r[i] + a_1)*r[i] + a_0)/((((b_3*r[i] + b_2)*r[i] + b_1)*r[i] + b_0)*r[i] + 1);
}else{
r[i] = u[i];
if(y[i] > 0.0){
r[i] = 1.0 - u[i];
r[i] = log(-log(r[i]));
x[i] = c_0 + r[i]*(c_1 + r[i]*(c_2 + r[i]*(c_3 + r[i]*(c_4 + r[i]*(c_5 + r[i]*(c_6 + r[i]*(c_7 + r[i]*c_8)))))));
}
if(y[i] < 0){
x[i] = -x[i];
}
}
}
return x;
}
double phi(double x){
return 0.5 * erfc(-x * M_SQRT1_2);
}
void Anderson_Darling(int n, double X[]){
sort(X,X + n);
// Find the mean of X
double X_avg = 0.0;
double sum = 0.0;
for(int i = 0; i < n; i++){
sum += X[i];
}
X_avg = ((double)sum)/n;
// Find the variance of X
double X_sig = 0.0;
for(int i = 0; i < n; i++){
X_sig += (X[i] - X_avg)*(X[i] - X_avg);
}
X_sig /= (n-1);
// The values X_i are standardized to create new values Y_i
double Y[n];
for(int i = 0; i < n; i++){
Y[i] = (X[i] - X_avg)/(sqrt(X_sig));
//cout << Y[i] << endl;
}
// With a standard normal CDF, we calculate the Anderson_Darling Statistic
double A = -n;
for(int i = 0; i < n; i++){
A += -1.0/(double)n *(2*(i+1) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n - i])));
}
cout << A << endl;
}
Let me guess, your n was 2000. Right?
The major issue here is when you do 1/n in the last expression. 1 is an int and ao is n. When you divide 1 by n it performs integer division. Now 1 divided by any number > 1 is 0 under integer division (think if it as only keeping only integer part of the quotient. What you need to do is cast n as double by writing 1/(double)n.
Rest all should work fine.
Summary from discussions -
Indexes to Y[] should be i and n-1-i respectively.
n should not be added in the loop but only once.
Minor fixes like changing divisor to n instead of n-1 while calculating Variance.
You have integer division here:
A += -n - 1/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i])));
^^^
1/n is zero when n > 1 - you need to change this to, e.g.: 1.0/n:
A += -n - 1.0/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i])));
^^^^^
I've tried to implement Newton's method for polynomials. Like:
double xn=x0;
double gxn=g(w, n, xn);
int i=0;
while(abs(gxn)>e && i<100){
xn=xn-(gxn/dg(w, n, xn));
gxn=g(w, n, xn);
i++;
}
where g(w, n, xn) computes the value of the function and dg(w, n, xn) computes the derivative.
As x0 I use starting point M which I found using Sturm's theorem.
My problem is that this method is divergent for some polynomials like x^4+2x^3+2x^2+2x+1. Maybe it's not regular, but I noticed that it happens when the solution of the equation is a negative number. Where can I look for an explanation?
Edit:
dg
double result=0;
for(int i=0; i<n+1; i++)
result+=w[i]*(n-i)*pow(x, n-i-1);
where n is the degree of polynomial
I'm not sure why would you say it's divergent.
I implemented Newton's method similarly to yours:
double g(int w[], int n, double x) {
double result = 0;
for (int i = 0; i < n + 1; i++)
result += w[i] * pow(x, n - i);
return result;
}
double dg_dx(int w[], int n, double x) {
double result = 0;
for (int i = 0; i < n ; i++)
result += w[i] * (n - i) * pow(x, n - i - 1);
return result;
}
int main() {
double xn = 0; // Choose initial value. I chose 0.
double gx;
double dg_dx_x;
int w[] = { 1, 2, 2, 2, 1 };
int i = 0;
int n = 4;
do {
gx = g(w, n, xn);
dg_dx_x = dg_dx(w, n, xn);
xn = xn - (gx / dg_dx_x);
i++;
} while (abs(gx) > 10e-5 && i < 100);
std::cout << xn << '\n';
}
And it yields -0.997576, which is close to the solution -1.
Here is my code so far. There seems to be soemthing wrong since I keep getting an incorrect answer. I am writing in a text file that is formatted:
2
3.0 1.0
2 being the size of the array and then 3.0 and 1.0 being the coefficients. Hopefully I didnt miss much in my explanation. Any help would be greatly appreciated.
Thanks
double polyeval(double* polyarray, double x, int arraySize)
{
//int result = 0;
if(arraySize == 0)
{
return polyarray[arraySize];
}
//result += x*(polyarray[arraySize]+polyeval(polyarray,x,arraySize-1));
return polyarray[arraySize-1]+ (x* (polyeval(polyarray,x,arraySize-1)));
//return result;
}
int main ()
{
int arraySize;
double x;
double *polyarray;
ifstream input;
input.open("polynomial.txt");
input >> arraySize;
polyarray = new double [arraySize];
for (int a = arraySize - 1; a >= 0; a--)
{
input >> polyarray[a];
}
cout << "For what value x would you like to evaluate?" << endl;
cin >> x;
cout << "Polynomial Evaluation: " << polyeval(polyarray, x, arraySize);
delete [] polyarray;
}
the idea that if i read in a text file of that format varying in size that it will solve for any value x given by the user
Jut taking a wild guess
for (int a = arraySize - 1; a >= 0; a--)
// ^^
{
input >> polyarray[a];
}
One error is here:
for (int a = arraySize - 1; a > 0; a--)
{ //^^should be a >=0
input >> polyarray[a];
}
You are missing some entry this way.
The recursive function should look like the following:
int polyeval(double* polyarray, double x, int arraySize)
{
if(arraySize == 1)
{
return polyarray[arraySize-1];
}
return x*(polyarray[arraySize-1]+polyeval(polyarray,x,arraySize-1));
}
The problem is mainly with the definition of the polynomial coefficients.
Your code assumes a polynomial on the form:
x( p(n) + x( p(n-1) + x( p(n-2) + ... x(p(1) + p(0)))..))
This line:
result += x*(polyarray[arraySize]+polyeval(polyarray,x,arraySize-1));
Should become:
result += pow(x,arraySize)*polyarray[arraySize]+polyeval(polyarray,x,arraySize-1);
This way the polynomial is defined correctly as p(n)x^n + p(n-1)x^(n-1) ... + p1 x + p0
Couldn't work out exactly what you were trying to do, or why you were using recursion. So I whipped up a non-recursive version that seems to give the right results.
#include <iostream>
using namespace std;
double polyeval(const double* polyarray, double x, int arraySize) {
if(arraySize <= 0) { return 0; }
double value = 0;
const double * p = polyarray + (arraySize-1);
for(int i=0; i<arraySize; ++i) {
value *= x;
value += *p;
p--;
}
return value;
}
int main () {
const int arraySize = 3;
const double polyarrayA[3] = {0.0,0.0,1.0}; // 0 + 0 x + 1 x^2
const double polyarrayB[3] = {0.0,1.0,0.0}; // 0 + 1 x + 0 x^2
const double polyarrayC[3] = {1.0,0.0,0.0}; // 1 + 0 x + 0 x^2
cout << "Polynomial Evaluation A f(x) = " << polyeval(polyarrayA, 0.5, arraySize)<<std::endl;
cout << "Polynomial Evaluation B f(x) = " << polyeval(polyarrayB, 0.5, arraySize)<<std::endl;
cout << "Polynomial Evaluation C f(x) = " << polyeval(polyarrayC, 0.5, arraySize)<<std::endl;
}
You can see it running here:
http://ideone.com/HE4r6x
I have this equation
and
then find the polynomial from
I am trying to implement it like this:
for (int n=0;n<order;n++){
df[n][0]=y[n];
for (int i=0;i<N;i++){ //N number of points
df[n][i]+=factorial(n,i)*y[i+n-1];
}
}
for (int i=0;i<N;i++){
term=factorial(s,i);
result*=df[0][i]*term;
sum+=result;
}
return sum;
1) I am not sure how to implement the sign of every argument in the function.As you can see it goes 'positive' , 'negative', 'positive' ...
2) I am not sure for any mistakes...
Thanks!
----------------------factorial-----------------------------
int fact(int n){
//3!=1*2*3
if (n==0) return 1;
else
return n*fact(n-1);
}
double factorial(double s,int n){
//(s 3)=s*(s-1)*(s-2)/6
if ((n==0) &&(s==0)) return 1;
else
return fact(s)/fact(n);
}
The simplest solution is probably to just keep the sign in
a variable, and multiply it in each time through the loop.
Something like:
sign = 1.0;
for ( int i = 0; i < N; ++ i ) {
term = factorial( s, i );
result *= df[0][i] * term;
sum += sign * result;
sign = - sign;
}
You cannot do pow( -1, m ).
You can write your own:
inline int minusOnePower( unsigned int m )
{
return (m & 1) ? -1 : 1;
}
You may want to build up some tables of calculated values.
Well, I understand you want to approximately calculate the value f(x) for a given x=X, using Newton Interpolation polynomial with equidistant points (more specifically Newton-Gregory forward difference interpolation polynomial).
Assuming s=(X-x0)/h, where x0 is the first x, and h the step to obtain the rest of the x for which you know the exact value of f :
Considere:
double coef (double s, int k)
{
double c(1);
for (int i=1; i<=k ; ++i)
c *= (s-i+1)/i ;
return c;
}
double P_interp_value(double s, int Num_of_intervals , double f[] /* values of f in these points */) // P_n_s
{
int N=Num_of_intervals ;
double *df0= new double[N+1]; // calculing df only for point 0
for (int n=0 ; n<=N ; ++n) // n here is the order
{
df0[n]=0;
for (int k=0, sig=-1; k<=n; ++k, sig=-sig) // k here is the "x point"
{
df0[n] += sig * coef(n,k) * f[n-k];
}
}
double P_n_s = 0;
for (int k=0; k<=N ; ++k ) // here k is the order
{
P_n_s += coef(s,k)* df0[k];
}
delete []df0;
return P_n_s;
}
int main()
{
double s=0.415, f[]={0.0 , 1.0986 , 1.6094 , 1.9459 , 2.1972 };
int n=1; // Num of interval to use during aproximacion. Max = 4 in these example
while (true)
{
std::cin >> n;
std::cout << std::endl << "P(n=" << n <<", s=" << s << ")= " << P_interp_value(s, n, f) << std::endl ;
}
}
it print:
1
P(n=1, s=0.415)= 0.455919
2
P(n=2, s=0.415)= 0.527271
3
P(n=3, s=0.415)= 0.55379
4
P(n=4, s=0.415)= 0.567235
compare with:
http://ecourses.vtu.ac.in/nptel/courses/Webcourse-contents/IIT-KANPUR/Numerical%20Analysis/numerical-analysis/Rathish-kumar/rathish-oct31/fratnode8.html
It works. Now we can start to optimize these code.
just for the sign ;-)
inline signed int minusOnePower( unsigned int m )
{
return 1-( (m & 1)<<1 );
}
I can't figure out why I keep getting the result 1.#INF from my_exp() when I give it 1 as input. Here is the code:
double factorial(const int k)
{
int prod = 1;
for(int i=1; i<=k; i++)
prod = i * prod;
return prod;
}
double power(const double base, const int exponent)
{
double result = 1;
for(int i=1; i<=exponent; i++)
result = result * base;
return result;
}
double my_exp(double x)
{
double sum = 1 + x;
for(int k=2; k<50; k++)
sum = sum + power(x,k) / factorial(k);
return sum;
}
You have an integer overflow in your factorial function. This causes it to output zero. 49! is divisible by 2^32, so your factorial function will return zero.
Then you divide by it causing it to go infinity. So the solution is to change prod to double:
double prod = 1;
Instead of completely evaluating the power and the factorial terms for each term in your expansion, you should consider how the k'th term is related to the k-1'th term and just update each term based on this relationship. That will avoid the nasty overflows in your power and factorial functions (which you will no longer need). E.g.
double my_exp(double x)
{
double sum = 1.0 + x;
double term = x; // term for k = 1 is just x
for (int k = 2; k < 50; k++)
{
term = term * x / (double)k; // term[k] = term[k-1] * x / k
sum = sum + term;
}
return sum;
}
you should just reduce max of k form 50 to like 30 it will work;
and one question your code work just near 0 ?