Newton's method is divergent for some polynomials - c++

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.

Related

Using Eigen class to sum certain numbers in a vector

I am new to C++ and I am using the Eigen library. I was wondering if there was a way to sum certain elements in a vector. For example, say I have a vector that is a 100 by 1 and I just want to sum the first 10 elements. Is there a way of doing that using the Eigen library?
What I am trying to do is this: say I have a vector that is 1000 by 1 and I want to take the mean of the first 10 elements, then the next 10 elements, and so on and store that in some vector. Hence I will have a vector of size 100 of the averages. Any thoughts or suggestions are greatly appreciated.
Here is the beginning steps I have in my code. I have a S_temp4vector that is 1000 by 1. Now I intialize a new vector S_A that I want to have as the vector of the means. Here is my messy sloppy code so far: (Note that my question resides in the crudeMonteCarlo function)
#include <iostream>
#include <cmath>
#include <math.h>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <random>
#include <time.h>
using namespace Eigen;
using namespace std;
void crudeMonteCarlo(int N,double K, double r, double S0, double sigma, double T, int n);
VectorXd time_vector(double min, double max, int n);
VectorXd call_payoff(VectorXd S, double K);
int main(){
int N = 100;
double K = 100;
double r = 0.2;
double S0 = 100;
double sigma = 0.4;
double T = 0.1;
int n = 10;
crudeMonteCarlo(N,K,r,S0,sigma,T,n);
return 0;
}
VectorXd time_vector(double min, double max, int n){
VectorXd m(n + 1);
double delta = (max-min)/n;
for(int i = 0; i <= n; i++){
m(i) = min + i*delta;
}
return m;
}
MatrixXd generateGaussianNoise(int M, int N){
MatrixXd Z(M,N);
static random_device rd;
static mt19937 e2(time(0));
normal_distribution<double> dist(0.0, 1.0);
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
Z(i,j) = dist(e2);
}
}
return Z;
}
VectorXd call_payoff(VectorXd S, double K){
VectorXd C(S.size());
for(int i = 0; i < S.size(); i++){
if(S(i) - K > 0){
C(i) = S(i) - K;
}else{
C(i) = 0.0;
}
}
return C;
}
void crudeMonteCarlo(int N,double K, double r, double S0, double sigma, double T, int n){
// Create time vector
VectorXd tt = time_vector(0.0,T,n);
VectorXd t(n);
double dt = T/n;
for(int i = 0; i < n; i++){
t(i) = tt(i+1);
}
// Generate standard normal Z matrix
//MatrixXd Z = generateGaussianNoise(N,n);
// Generate the log normal stock process N times to get S_A for crude Monte Carlo
MatrixXd SS(N,n+1);
MatrixXd Z = generateGaussianNoise(N,n);
for(int i = 0; i < N; i++){
SS(i,0) = S0;
for(int j = 1; j <= n; j++){
SS(i,j) = SS(i,j-1)*exp((double) (r - pow(sigma,2.0))*dt + sigma*sqrt(dt)*(double)Z(i,j-1));
}
}
// This long bit of code gives me my S_A.....
Map<RowVectorXd> S_temp1(SS.data(), SS.size());
VectorXd S_temp2(S_temp1.size());
for(int i = 0; i < S_temp2.size(); i++){
S_temp2(i) = S_temp1(i);
}
VectorXd S_temp3(S_temp2.size() - N);
int count = 0;
for(int i = N; i < S_temp2.size(); i++){
S_temp3(count) = S_temp2(i);
count++;
}
VectorXd S_temp4(S_temp3.size());
for(int i = 0; i < S_temp4.size(); i++){
S_temp4(i) = S_temp3(i);
}
VectorXd S_A(N);
S_A(0) = (S_temp4(0) + S_temp4(1) + S_temp4(2) + S_temp4(3) + S_temp4(4) + S_temp4(5) + S_temp4(6) + S_temp4(7) + S_temp4(8) + S_temp4(9))/(n);
S_A(1) = (S_temp4(10) + S_temp4(11) + S_temp4(12) + S_temp4(13) + S_temp4(14) + S_temp4(15) + S_temp4(16) + S_temp4(17) + S_temp4(18) + S_temp4(19))/(n);
int count1 = 0;
for(int i = 0; i < S_temp4.size(); i++){
S_A(count1) =
}
// Calculate payoff of Asian option
//VectorXd call_fun = call_payoff(S_A,K);
}
This question includes a lot of code, which makes it hard to understand the question you're trying to ask. Consider including only the code specific to your question.
In any case, you can use Eigen directly to do all of these things quite simply. In Eigen, Vectors are just matrices with 1 column, so all of the reasoning here is directly applicable to what you've written.
const Eigen::Matrix<double, 100, 1> v = Eigen::Matrix<double, 100, 1>::Random();
const int num_rows = 10;
const int num_cols = 1;
const int starting_row = 0;
const int starting_col = 0;
const double sum_of_first_ten = v.block(starting_row, starting_col, num_rows, num_cols).sum();
const double mean_of_first_ten = sum_of_first_ten / num_rows;
In summary: You can use .block to get a block object, .sum() to sum that block, and then conventional division to get the mean.
You can reshape the input using Map and then do all sub-summations at once without any loop:
VectorXd A(1000); // input
Map<MatrixXd> B(A.data(), 10, A.size()/10); // reshaped version, no copy
VectorXd res = B.colwise().mean(); // partial reduction, you can also use .sum(), .minCoeff(), etc.
The Eigen documentation at https://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html says an Eigen block is a rectangular part of a matrix or array accessed by matrix.block(i,j,p,q) where i and j are the starting values (eg 0 and 0) and p and q are the block size (eg 10 and 1). Presumably you would then iterate i in steps of 10, and use std::accumulate or perhaps an explicit summation to find the mean of matrix.block(i,0,10,1).

Unknown error using the c++ eigen library

I am a graduate student at Florida State University studying financial mathematics. I am still a bit of a novice with C++ but I am trying to implement the Longstaff-Schwartz method for pricing of American options. Although, the algorithm in the journal is a bit daunting thus I am trying to convert the code that was written in Matlab and change it into C++. Essentially I am using the Matlab code as a guide.
I was referred by some stackexchange users to use the Eigen library which contains a good matrix class. Unfortunately the website here does not show me how to make my own function from the class. What I am stuck on is making a C++ function for the function in Matlab that does this:
Say t = 0:1/2:1 then in Matlab the output will be t = 0 0.500 1
So using the Eigen class I created a function called range to achieve the latter above. The function looks like this:
MatrixXd range(double min, double max, double N){
MatrixXd m(N,1);
double delta = (max-min)/N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
m(i,j) = min + i*delta;
}
}
return m;
}
I do not have any errors on my IDE (Ecclipse) but when I run my code and test this function I get this error message:
c:\mingw\include\c++\6.2.0\eigen\src/Core/PlainObjectBase.h:736:7:
error: static assertion failed:
FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED
I am not sure what is wrong. Any suggestions on achieving what I am trying to do or any suggestions at all are greatly appreciated.
Taking the suggestion by Martijn Courteaux, I changed $N$ into an int now but I now receive a new error that I do not understand:
c:\mingw\include\c++\6.2.0\eigen\src/Core/Matrix.h:350:7: error: static
assertion failed: THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3)
For sake of completeness I will post my whole code below:
#include <iostream>
#include <cmath>
#include <limits>
#include <algorithm>
#include <Eigen/Dense>
#include <Eigen/Geometry>
using namespace Eigen;
using namespace std;
double LaguerreExplicit(int R, double x); // Generates the (weighted) laguerre value
double payoff_Call(double S, double K); // Pay off of a call option
double generateGaussianNoise(double mu, double sigma); // Generates Normally distributed random numbers
double LSM(int T, double r, double sigma, double K, double S0, int N, int M, int R);
// T Expiration time
// r Riskless interest rate
// sigma Volatility
// K Strike price
// S0 Initial asset price
// N Number of time steps
// M Number of paths
// R Number of basis functions
MatrixXd range(double min, double max, int N);
int main(){
MatrixXd range(0, 1, 2);
}
double payoff_Call(double S, double K){
double payoff;
if((S - K) > 0)
{
payoff = S - K;
}else
{
payoff = 0.0;
}
return payoff;
}
double LaguerreExplicit(int R, double x){
double value;
if(R==0)
{
value = 1;
}
else if(R==1)
{
value = 0.5*(pow(x,2) - 4.0*x + 2);
}
else if(R==3)
{
value = (1.0/6.0)*(-1*pow(x,3) + 9*pow(x,2) - 18*x + 6);
}
else if(R==4)
{
value = (1.0/24.0)*(pow(x,4) - 16*pow(x,3) + 72*pow(x,2) - 96*x + 24);
}
else if(R==5)
{
value = (1.0/120.0)*(-1*pow(x,5) + 25*pow(x,4) - 200*pow(x,3) + 600*pow(x,2) - 600*x + 120);
}
else if (R==6)
{
value = (1.0/720.0)*(pow(x,6) - 36*pow(x,5) + 450*pow(x,4) - 2400*pow(x,3) + 5400*pow(x,2) - 4320*x + 720);
}
else{
cout << "Error!, R is out of range" << endl;
value = 0;
}
value = exp(-0.5*x)*value; // Weighted used in Longstaff-Scwartz
return value;
}
double generateGaussianNoise(double mu, double sigma)
{
const double epsilon = std::numeric_limits<double>::min();
const double two_pi = 2.0*M_PI;
static double z0, z1;
static bool generate;
generate = !generate;
if (!generate)
return z1 * sigma + mu;
double u1, u2;
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
}
while ( u1 <= epsilon );
z0 = sqrt(-2.0 * log(u1)) * cos(two_pi * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(two_pi * u2);
return z0 * sigma + mu;
}
MatrixXd range(double min, double max, int N){
MatrixXd m(N,1);
double delta = (max-min)/N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
m(i,j) = min + i*delta;
}
}
return m;
}
double LSM(int T, double r, double sigma, double K, double S0, int N, int M, int R){
double dt = T/N;
MatrixXd m(T,1);
return 0;
}
Here is the corrected function code that I fixed:
VectorXd range(double min, double max, int N){
VectorXd m(N + 1);
double delta = (max-min)/N;
for(int i = 0; i <= N; i++){
m(i) = min + i*delta;
}
return m;
}
Mistake is here:
MatrixXd range(double min, double max, double N){
MatrixXd m(N,1);
N is a double. The arguments of MatrixXd::MatrixXd(int, int) are int.
You presumably want to make N an int.
In regard to your edit:
Second mistake is here:
MatrixXd range(0, 1, 2);
in the main() function. Not sure what you are trying to do here, but that constructor is not valid. EDIT: Ah I believe I have an idea. You are trying to call your function named range. Do this like this:
MatrixXd result = range(0.0, 1.0, 2);

Polynomial Fit force first degree to zero

i found good code to do some polynomial least squares fitting based on GSL.
i am using it with 3 degrees: y = Cx² + Bx + A.
In my application i know that A must be zero. Is it possible to change the algorithm so that A alway will be zero?
bool polynomialfit(int obs, int degree,
double *dx, double *dy, double *store) /* n, p */
{
gsl_multifit_linear_workspace *ws;
gsl_matrix *cov, *X;
gsl_vector *y, *c;
double chisq;
int i, j;
X = gsl_matrix_alloc(obs, degree);
y = gsl_vector_alloc(obs);
c = gsl_vector_alloc(degree);
cov = gsl_matrix_alloc(degree, degree);
for(i=0; i < obs; i++) {
gsl_matrix_set(X, i, 0, 1.0);
for(j=0; j < degree; j++) {
gsl_matrix_set(X, i, j, pow(dx[i], j));
}
gsl_vector_set(y, i, dy[i]);
}
ws = gsl_multifit_linear_alloc(obs, degree);
gsl_multifit_linear(X, y, c, cov, &chisq, ws);
/* store result ... */
for(i=0; i < degree; i++)
{
store[i] = gsl_vector_get(c, i);
}
gsl_multifit_linear_free(ws);
gsl_matrix_free(X);
gsl_matrix_free(cov);
gsl_vector_free(y);
gsl_vector_free(c);
return true; /* we do not "analyse" the result (cov matrix mainly)
to know if the fit is "good" */
}
You can replace y by y' = y/x and then perform fitting of a 1. degree polynomial y'= Cx + B?
(if point x = 0 is present in your data set you have to remove it but this point does not improve fit in case you want to apply the A = 0 constraint, you can still use it to re-compute goodness of fit)
In the code you posted there is this loop:
for(j=0; j < degree; j++) {
gsl_matrix_set(X, i, j, pow(dx[i], j));
}
and the function pow computes the x^j terms, you have to "ignore" the term where j==0.
I have no access to GSL and so the following is just off the top of my head and it is untested:
bool polynomialfit(int obs, int polynom_degree,
double *dx, double *dy, double *store) /* n, p */
{
gsl_multifit_linear_workspace *ws;
gsl_matrix *cov, *X;
gsl_vector *y, *c;
double chisq;
int i, j;
int degree = polynom_degree - 1;
X = gsl_matrix_alloc(obs, degree);
y = gsl_vector_alloc(obs);
c = gsl_vector_alloc(degree);
cov = gsl_matrix_alloc(degree, degree);
for(i=0; i < obs; i++) {
gsl_matrix_set(X, i, 0, 1.0);
for(j=0; j < degree; j++) {
gsl_matrix_set(X, i, j, pow(dx[i], j+1));
}
gsl_vector_set(y, i, dy[i]);
}
ws = gsl_multifit_linear_alloc(obs, degree);
gsl_multifit_linear(X, y, c, cov, &chisq, ws);
/* store result ... */
for(i=0; i < degree; i++)
{
store[i] = gsl_vector_get(c, i);
}
gsl_multifit_linear_free(ws);
gsl_matrix_free(X);
gsl_matrix_free(cov);
gsl_vector_free(y);
gsl_vector_free(c);
return true; /* we do not "analyse" the result (cov matrix mainly)
to know if the fit is "good" */
}
In order to fit to y=c*x*x+b*x you have to call it with polynom_degree set to 3.
You also may have a look at the theory:
Weisstein, Eric W. "Least Squares Fitting--Polynomial." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html

Function to differentiate a polynomial in C++

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;

numerical analysis equation

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 );
}