What's wrong with my durand-kerner implementation? - c++

Implementing this simple root-finding algorithm.
http://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method
I cannot for the life of me figure out what's wrong with my implementation. The roots keep blowing up and no sign of convergence. Any suggestions?
Thanks.
#include <iostream>
#include <complex>
using namespace std;
typedef complex<double> dcmplx;
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 3;
double a3 = -3;
double a2 = 1;
double a1 = 0;
double a0 = 100;
return a4 * pow(x,4) + a3 * pow(x,3) + a2 * pow(x,2) + a1 * x + a0;
}
int main()
{
dcmplx p(.9,2);
dcmplx q(.1, .5);
dcmplx r(.7,1);
dcmplx s(.3, .5);
dcmplx p0, q0, r0, s0;
int max_iterations = 20;
bool done = false;
int i=0;
while (i<max_iterations && done == false)
{
p0 = p;
q0 = q;
r0 = r;
s0 = s;
p = p0 - f(p0)/((p0-q0)*(p0-r0)*(p0-s0));
q = q0 - f(q0)/((q0-p)*(q0-r0)*(q0-s0));
r = r0 - f(r0)/((r0-p)*(r0-q)*(r0-s0));
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
// if convergence within small epsilon, declare done
if (abs(p-p0)<1e-5 && abs(q-q0)<1e-5 && abs(r-r0)<1e-5 && abs(s-s0)<1e-5)
done = true;
i++;
}
cout<<"roots are :\n";
cout << p << "\n";
cout << q << "\n";
cout << r << "\n";
cout << s << "\n";
cout << "number steps taken: "<< i << endl;
return 0;
}

A half year late: The solution to the enigma is that the denominator should be an approximation of the derivative of the polynomial, and thus needs to contain the leading coefficient a4 as factor.
Alternatively, one can divide the polynomial value by a4 in the return statement, so that the polynomial is effectively normed, i.e., has leading coefficient 1.
Note that the example code in wikipedia by Bo Jacoby is the Seidel-type variant of the method, the classical formulation is the Jordan-like method where all new approximations are simultaneously computed from the old approximation. Seidel can have faster convergence than the order 2 that the formulation as a multidimensional Newton method provides for Jacobi.
However, for large degrees Jacobi can be accelerated using fast polynomial multiplication algorithms for the required multi-point evaluations of polynomial values and the products in the denominators.

Ah, the problem was that the coefficients of an N-degree polynomial have to be specified as
1*x^N + a*x^(N-1) + b*x^(N-2) ... etc + z;
where 1 is the coefficient of the largest degree term. Otherwise the first root will never converge.

You haven't implemented for formulae correctly. For instance
s = s0 - f(s0)/((s0-p0)*(s0-q0)*(s0-r0));
should be
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
Look again at the wiki article

Related

Rational approximation of double using int numerator and denominator in C++

A real world third party API takes a parameter of type fraction which is a struct of an int numerator and denominator. The value that I need to pass is known to me as a decimal string that is converted to a double.
The range of possible values are, let's say 10K to 300M but if there is a fraction part after the decimal point, it's significant.
I have here code for two approximation approaches, one uses the extended euclidean algorithm while the other is brute-force. Both methods find a rational approximation using int types for a given double.
The brute-force is of course the more accurate of the two and is actually faster when the converted numbers are large. My questions is, can I say anything clever about the quality of the approximation using the euclidean algorithm.
More formally, can I put a bound on the approximation using the euclidean algorithm vs. the approximation of the brute-force algorithm (which I believe to be optimal).
An example for a bound:
If the error of the optimal approximation is r, then the euclidean algorithm approximation would produce an error that is less than 2*r.
(I'm not claiming this is the bound and I certainly can't prove it, it's just an example for what a good bound may look like).
Here's the code an a test program:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
#include <chrono>
#include <random>
// extended euclidian algorithm
// finds the coefficients that produce the gcd
// in u, we store m,n the coefficients that produce m*a - n*b == gcd.
// in v, we store m,n the coefficients that produce m*a - n*b == 0.
// breaks early if the coefficients become larger than INT_MAX
int gcd_e(uint64_t a, int b, int u[2], int v[2])
{
auto w = lldiv(a, b);
// u[0] * a' - u[1] * b' == a
// v[0] * a' - v[1] * b' == b
// a - w.quot * b == w.rem
// (u[0] * a' - u[1] * b') - w.quot * (v[0] * a' - v[1] * b') == w.rem
// (u[0] - w.quot * v[0]) * a' - u[1] * b' + w.quot * v[1] * b' == w.rem
// (u[0] - w.quot * v[0]) * a' + (w.quot * v[1] - u[1]) * b' == w.rem
// (u[0] - w.quot * v[0]) * a' - (u[1] - w.quot * v[1]) * b' == w.rem
auto m = u[0] - w.quot * v[0];
auto n = u[1] - w.quot * v[1];
u[0] = v[0];
u[1] = v[1];
constexpr auto L = std::numeric_limits<int>::max();
if (m > L || n > L)
throw 0; // break early
if (m < -L || n < -L)
throw 0; // break early
v[0] = int(m);
v[1] = int(n);
if (w.rem == 0)
return b;
return gcd_e(b, int(w.rem), u, v);
}
inline double helper_pre(double d, bool* negative, bool* inverse)
{
bool v = (d < 0);
*negative = v;
if (v)
d = -d;
v = (d < 1);
*inverse = v;
if (v)
d = 1 / d;
return d;
}
inline void helper_post(int* m, int* n, bool negative, bool inverse)
{
if (inverse)
std::swap(*n, *m);
if (negative)
*n = -(*n);
}
// gets a rational approximation for double d
// numerator is stored in n
// denominator is stored in m
void approx(double d, int* n, int *m)
{
int u[] = { 1, 0 }; // 1*a - 0*b == a
int v[] = { 0, -1 }; // 0*a - (-1)*b == b
bool negative, inverse;
d = helper_pre(d, &negative, &inverse);
constexpr int q = 1 << 30;
auto round_d = std::round(d);
if (d == round_d)
{
// nothing to do, it's an integer.
v[1] = int(d);
v[0] = 1;
}
else try
{
uint64_t k = uint64_t(std::round(d*q));
gcd_e(k, q, u, v);
}
catch (...)
{
// OK if we got here.
// int limits
}
// get the approximate numerator and denominator
auto nn = v[1];
auto mm = v[0];
// make them positive
if (mm < 0)
{
mm = -mm;
nn = -nn;
}
helper_post(&mm, &nn, negative, inverse);
*m = mm;
*n = nn;
}
// helper to test a denominator
// returns the magnitude of the error
double helper_rattest(double x, int tryDenom, int* numerator)
{
double r = x * tryDenom;
double rr = std::round(r);
auto num = int(rr);
auto err = std::abs(r - rr) / tryDenom;
*numerator = num;
return err;
}
// helper to reduce the rational number
int gcd(int a, int b)
{
auto c = a % b;
if (c == 0)
return b;
return gcd(b, int(c));
}
// gets a rational approximation for double d
// numerator is stored in n
// denominator is stored in m
// uses brute force by scanning denominator range
void approx_brute(double d, int* n, int* m)
{
bool negative, inverse;
d = helper_pre(d, &negative, &inverse);
int upto = int(std::numeric_limits<int>::max() / d);
int bestNumerator;
int bestDenominator = 1;
auto bestErr = helper_rattest(d, 1, &bestNumerator);
for (int kk = 2; kk < upto; ++kk)
{
int n;
auto e = helper_rattest(d, kk, &n);
if (e < bestErr)
{
bestErr = e;
bestNumerator = n;
bestDenominator = kk;
}
if (bestErr == 0)
break;
}
// reduce, just in case
auto g = gcd(bestNumerator, bestDenominator);
bestNumerator /= g;
bestDenominator /= g;
helper_post(&bestDenominator, &bestNumerator, negative, inverse);
*n = bestNumerator;
*m = bestDenominator;
}
int main()
{
int n, m;
auto re = std::default_random_engine();
std::random_device rd;
re.seed(rd());
for (auto& u : {
std::uniform_real_distribution<double>(10000, 15000),
std::uniform_real_distribution<double>(100000, 150000),
std::uniform_real_distribution<double>(200000, 250000),
std::uniform_real_distribution<double>(400000, 450000),
std::uniform_real_distribution<double>(800000, 850000),
std::uniform_real_distribution<double>(1000000, 1500000),
std::uniform_real_distribution<double>(2000000, 2500000),
std::uniform_real_distribution<double>(4000000, 4500000),
std::uniform_real_distribution<double>(8000000, 8500000),
std::uniform_real_distribution<double>(10000000, 15000000)
})
{
auto dd = u(re);
std::cout << "approx: " << std::setprecision(14) << dd << std::endl;
auto before = std::chrono::steady_clock::now();
approx_brute(dd, &n, &m);
auto after = std::chrono::steady_clock::now();
std::cout << n << " / " << m << " dur: " << (after - before).count() << std::endl;
before = std::chrono::steady_clock::now();
approx(dd, &n, &m);
after = std::chrono::steady_clock::now();
std::cout << n << " / " << m << " dur: " << (after - before).count()
<< std::endl
<< std::endl;
}
}
Here's some sample output:
approx: 13581.807792679
374722077 / 27590 dur: 3131300
374722077 / 27590 dur: 15000
approx: 103190.31976517
263651267 / 2555 dur: 418700
263651267 / 2555 dur: 6300
approx: 223753.78683426
1726707973 / 7717 dur: 190100
1726707973 / 7717 dur: 5800
approx: 416934.79214075
1941665327 / 4657 dur: 102100
403175944 / 967 dur: 5700
approx: 824300.61241502
1088901109 / 1321 dur: 51900
1088901109 / 1321 dur: 5900
approx: 1077460.29557
1483662827 / 1377 dur: 39600
1483662827 / 1377 dur: 5600
approx: 2414781.364653
1079407270 / 447 dur: 17900
1079407270 / 447 dur: 7300
approx: 4189869.294816
1776504581 / 424 dur: 10600
1051657193 / 251 dur: 9900
approx: 8330270.2432111
308219999 / 37 dur: 5400
308219999 / 37 dur: 10300
approx: 11809264.006453
1830435921 / 155 dur: 4000
1830435921 / 155 dur: 10500
Thanks to all who commented and drew my attention to the concept of continued fractions.
According to this paper by (William F. Hammond)
There is equivalence between the euclidean algorithm and the continued fractions method.
The sub-optimal results are due to the fact that the numerator is constrained as well as the denominator so if the non brute force algorithm only produces "convergents" it means that it neglects the range of denominators between the first convergent to violate the constraints and the one just before it.
The denominators after the returned convergent and the one that follows may approximate close to the latter convergent and the difference between subsequent convergents can be shown to be:
So I suppose this would be the bound on the difference between the brute-force and the euclidean algorithm. The ratio of the error between them can be practically anything.
(can find examples of error ratios of more than 100 easily)
I hope I read everything correctly. I'm no authority on this.

sum of Maclaurin series c++

I am struggling to make this equation equals to each other because of a bad understanding of mathematics.
The problem is that the equation does not equal to each other
here is my code for better understand
#include <iostream>
#include <ccomplex>
using std::cout;
int main() {
int n = 8;
double sum = 0.0;
unsigned long long fact =1;
for (int i = 1; i <= n; i++)
{
fact *= 2*i*(2*i-1);
sum += 1.0 / fact;
}
std::cout << "first equation " << sum << std::endl;
double e = M_E;
double st = 1.0/2.0*(e + (1.0/e));
std::cout <<"second equation " << st << std::endl;
return 0;
}
the output
first equation 0.543081
second equation 1.54308
The result it nearly It must be at least equal before the comma,
You don't account for n = 0, which yields 0! and thus 1. Therefore, you need to add 1 to sum.

Cube root of a number, C++

I would like to ask a very short question, and it is as follows: in finding the cube root of a number (both neg. and pos.) in C++, how does one restrict the output to real solutions only?
I am currently writing a program to solve a cubic with Cardano's formula, and one of the intermediate variables I am using randomly outputs the complex and real cube roots - and I only need the real roots.
(E.g. in evaluating the cube root of -0.0127378, the three roots would be 0.11677095+0.202253218i, −0.2335419, 0.11677095−0.202253218i - I wish to ignore the complex ones for substitution into a later formula)
Thank you!
EDIT: Solved it! :) I created a signum function and tweaked the sign after taking the power of the absolute value of SPrime and TPrime, so now it carries forward only the real cube root.
/* ... */
#include <iostream>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cassert>
using namespace std;
int signum(std::complex<double> z)
{
if (z.real() < 0 || z.imag() < 0) return -1;
else if (z.real() >= 0 || z.imag() >= 0) return 1;
}
// POST: The function is intended to solve a cubic equation with coefficients a, b, c and d., such that
// ax^3 + bx^2 + cx + d = 0. If there exist infinitely many solutions, we output -1, i.e. if a=b=c=d=0
// (trivial solution).
void solve(std::complex<double> a, std::complex<double> b, std::complex<double> c, std::complex<double> d, std::complex<double>& x1, std::complex<double>& x2, std::complex<double>& x3)
{
complex<double> i = complex<double> (0, 1.0);
// Consider implementing Cardano's method for obtaining the solution of a degree 3 polynomial, as suggested
// We must hence define the discriminant D of such an equation through complex doubles Q and R
std::complex<double> Q;
Q = (3.0*a*c - pow(b, 2)) / (9.0*pow(a, 2));
cout << "Q=" << Q << endl;
std::complex<double> R;
R = (9.0*a*b*c - 27.0*d*pow(a, 2) - 2.0*pow(b, 3)) / (54.0*pow(a, 3));
cout << "R=" << R << endl;
std::complex<double> D;
D = pow(Q, 3) + pow(R, 2);
// Possible types of output for discriminant
if (abs(D) < 0.0)
{
cout << "The cubic has three distinct, real roots." << endl;
}
else if (abs(D) == 0.0)
{
cout << "The cubic has three real roots, at least two of which are equal." << endl;
}
else if (abs(D) > 0.0)
{
cout << "The cubic has one real root and two complex conjugate roots." << endl;
}
// Defining two further complex double variables S and T, which are required to obtain the final solution for x1, x2 and x3
std::complex<double> S;
std::complex<double> SPrime;
SPrime = R+sqrt(Q*Q*Q + R*R);
cout << "SPrime=" << SPrime << endl;
if (signum(SPrime) == -1)
{
S = (-1)*pow(abs(SPrime), 0.3333333333333);
}
else if (signum(SPrime) == 1)
{
S = pow(abs(SPrime), 0.3333333333333);
}
cout << "S=" << S << endl;
std::complex<double> T;
std::complex<double> TPrime;
TPrime = (R-sqrt(Q*Q*Q + R*R));
if (signum(TPrime) == -1)
{
T = (-1)*pow(abs(TPrime), 0.3333333333333);
}
else if (signum(TPrime) == 1)
{
T = pow(abs(TPrime), 0.3333333333333);
}
cout << "T=" << T << endl;
cout << "TPrime= " << TPrime << endl;
// Expressions for the solutions
x1 = S + T - (b/(3.0*a));
x2 = (-0.5)*(S + T) - (b/(3.0*a)) + (sqrt(3.0)*0.5)*(S - T)*i;
x3 = conj(x2);
if (abs(x1) < 0.000000000001)
{
x1 = 0;
}
}
// Driver code
int main ()
{
// Taking user input for a, b, c and d
std::complex<double> a, b, c, d, x1, x2, x3;
cout << "Please enter the coefficients of the polynomial in successive order." << endl;
cin >> a >> b >> c >> d;
solve (a, b, c, d, x1, x2, x3);
cout << x1 << ", " << x2 << ", " << x3 << "." << endl;
return 0;
}
The problem as you're stating it can be solved trivially (with real numbers the cubic root of -x is the opposite of the cubic root of x):
double cuberoot(double x) {
if (x < 0) {
return -pow(-x, 1.0/3.0);
} else if (x > 0) {
return pow(x, 1.0/3.0);
} else {
return 0;
}
}
If the input is instead in general complex z and you're looking for the "most real" (principal) cubic root the same reasoning can be applied using complex pow version to either z or -z depending on the sign of the real part:
std::complex<double> cuberoot(std::complex<double> z) {
if (z.real() < 0) {
return -pow(-z, 1.0/3.0);
} else {
return pow(z, 1.0/3.0);
}
}
Problems with your code:
As you allow complex coefficients, the discussion of the discriminant becomes slightly meaningless, it is only of value for real coefficients.
abs(D) is always non-negative. If D==0, then there is a double root, more can not be said in the case of complex coefficients.
You can avoid a lot of code by utilizing that S*T=-Q. One would have to care that the computation of u=T^3 returns the larger of the roots of 0==u^2 - 2*R*u - Q^3 or (u-R)^2 = D = R^2+Q^3
rtD = sqrt(D);
T = cuberoot( R + (abs(R+rtD)>=abs(R-rtD)) ? rtD : -rtD );
S = (abs(T)<epsilon) ? 0 : -Q/T;
Because of abs(R)<=abs(T)^3 and abs(D)<=abs(T)^6
one gets also abs(Q)<=2^(1/3)*abs(T)^2 resulting in
abs(S)=abs(Q/T) <= 2^(1/3)*abs(T)
For S=-Q/T to fail one would thus need a serious case
of extremely small floating point numbers in R, Q
and thus T. Quantitatively, for double even
the threshold epsilon=1e-150 should be safe.
On cube root variants:
For esthetic reasons one might want T as close to a coordinate axis as possible. A cube root function achieving this would be
std::complex<double> cuberoot(std::complex<double> z) {
double r=abs(z), phi=arg(z);
double k = round(2*phi/pi);
// closest multiple of pi/2
// an equivalent angle is (phi-k*pi/2) - k*3*pi/2
return std::polar( pow(r,1.0/3), (phi-k*pi/2)/3 - k*pi/2 );
}
so that abs(phi-k*pi/2)<=pi/4, and thus the angle to the next coordinate axis of the cube root is smaller than pi/12=15°. cuberoot(i) returns -i, cuberoot(-1) returns -1, a point at 60° returns a cube root at (60°-90°)/3-90°=-100°, etc.

Moving from (bad) array[size] to array = new float[size]

I was writing a program for finding roots for a class, and had finished and got it working perfectly. As I go to turn it in, I see the document requires the .cpp to compile using Visual Studio 2012 - so I try that out. I normally use Dev C++ - and I've come to find it allows me to compile "funky things" such as dynamically declaring arrays without using malloc or new operators.
So, after finding the error associated with how I wrongly defined my arrays - I tried to fix the problem using malloc, calloc, and new/delete and well - it kept giving me memory allocation errors. The whole 46981239487532-byte error.
Now, I tried to "return" the program to the way it used to be and now I can't even get that to work. I'm not even entirely sure how I set up the arrays to work in Dev C++ in the first place. Here the code:
#include <iostream>
#include <stdlib.h>
#include <math.h>
using namespace std;
float newton(float a, float b, float poly[],float n, float *fx, float *derfx);
float horner(float poly[], int n, float x, float *derx);
float bisection(float a, float b, float poly[], float n, float *fx);
int main(int argc, char *argv[])
{
float a, b, derr1 = 0, dummyvar = 0, fr1 = 0, fr0;
float constants[argc-3];
//float* constants = NULL;
//constants = new float[argc-3];
//constants = (float*)calloc(argc-3,sizeof(float));
//In order to get a and b from being a char to floating point, the following lines are used.
//The indexes are set relative to the size of argv array in order to allow for dynamically sized inputs. atof is a char to float converter.
a = atof(argv[argc-2]);
b = atof(argv[argc-1]);
//In order to get a easy to work with array for horners method,
//all of the values excluding the last two are put into a new floating point array
for (int i = 0; i <= argc - 3; i++){
constants[i] = atof(argv[i+1]);
}
bisection(a, b, constants, argc - 3, &fr0);
newton(a, b, constants, argc - 3, &fr1, &derr1);
cout << "f(a) = " << horner(constants,argc-3,a,&dummyvar);
cout << ", f(b) = " << horner(constants,argc-3,b,&dummyvar);
cout << ", f(Bisection Root) = " << fr0;
cout << ", f(Newton Root) = "<<fr1<<", f'(Newton Root) = "<<derr1<<endl;
return 0;
}
// Poly[] is the polynomial constants, n is the number of degrees of the polynomial (the size of poly[]), x is the value of the function we want the solution for.
float horner(float poly[], int n, float x, float *derx)
{
float fx[2] = {0, 0};
fx[0] = poly[0]; // Initialize fx to the largest degree constant.
float derconstant[n];
//float* derconstant = NULL;
//derconstant = new float[n];
//derconstant = (float*)calloc(n,sizeof(float));
derconstant[0] = poly[0];
// Each term is multiplied by the last by X, then you add the next poly constant. The end result is the function at X.
for (int i = 1; i < n; i++){
fx[0] = fx[0]*x + poly[i];
// Each itteration has the constant saved to form the derivative function, which is evaluated in the next for loop.
derconstant[i]=fx[0];
}
// The same method is used to calculate the derivative at X, only using n-1 instead of n.
fx[1] = derconstant[0]; // Initialize fx[1] to the largest derivative degree constant.
for (int i = 1; i < n - 1; i++){
fx[1] = fx[1]*x + derconstant[i];
}
*derx = fx[1];
return fx[0];
}
float bisection(float a, float b, float poly[], float n, float *fx)
{
float r0 =0, count0 = 0;
float c = (a + b)/2; // c is the midpoint from a to b
float fc, fa, fb;
int rootfound = 0;
float *derx;
derx = 0; // Needs to be defined so that my method for horner's method will work for bisection.
fa = horner(poly, n, a, derx); // The following three lines use horner's method to get fa,fb, and fc.
fb = horner(poly, n, b, derx);
fc = horner(poly, n, c, derx);
while ((count0 <= 100000) || (rootfound == 0)) { // The algorithm has a limit of 1000 itterations to solve the root.
if (count0 <= 100000) {
count0++;
if ((c == r0) && (fabs(fc) <= 0.0001)) {
rootfound=1;
cout << "Bisection Root: " << r0 << endl;
cout << "Iterations: " << count0+1 << endl;
*fx = fc;
break;
}
else
{
if (((fc > 0) && (fb > 0)) || ((fc < 0) && (fb < 0))) { // Checks if fb and fc are the same sign.
b = c; // If fc and fb have the same sign, thenb "moves" to c.
r0 = c; // Sets the current root approximation to the last c value.
c = (a + b)/2; // c is recalculated.
}
else
{
a=c; // Shift a to c for next itteration.
r0=c; // Sets the current root approximation to the last c value.
c=(a+b)/2; // Calculate next c for next itteration.
}
fa = horner(poly, n, a, derx); // The following three send the new a,b,and c values to horner's method for recalculation.
fb = horner(poly, n, b, derx);
fc = horner(poly, n, c, derx);
}
}
else
{
cout << "Bisection Method could not find root within 100000 itterations" << endl;
break;
}
}
return 0;
}
float newton(float a, float b, float poly[],float n, float *fx, float *derfx){
float x0, x1;
int rootfound1 = 1, count1 = 0;
x0 = (a + b)/2;
x1 = x0;
float fx0, derfx0;
fx0 = horner(poly, n, x0, &derfx0);
while ((count1 <= 100000) || (rootfound1 == 0)) {
count1++;
if (count1 <= 100000) {
if ((fabs(fx0) <= 0.0001)) {
rootfound1 = 1;
cout << "Newtons Root: " << x1 << endl;
cout << "Iterations: " << count1 << endl;
break;
}
else
{
x1 = x0 - (fx0/derfx0);
x0 = x1;
fx0 = horner(poly, n, x0, &derfx0);
*derfx = derfx0;
*fx = fx0;
}
}
else
{
cout << "Newtons Method could not find a root within 100000 itterations" << endl;
break;
}
}
return 0;
}
So I've spent the past several hours trying to sort this out, and ultimately, I've given in to asking.Everywhere I look has just said to define as
float* constants = NULL;
constants = new float[size];
but this keeps crashing my programs - presumably from allocating too much memory somehow. I've commented out the things I've tried in various ways and combonations. If you want a more tl;dr to the "trouble spots", they are at the very beginning of the main and horner functions.
Here is one issue, in main you allocate space for argc-3 floats (in various ways) for constants but your code in the loop writes past the end of the array.
Change:
for( int i = 0; i<=argc-3; i++){
to
for( int i = 0; i<argc-3; i++){
That alone could be enough to cause your allocation errors.
Edit: Also note if you allocate space for something using new, you need to delete it with delete, otherwise you will continue to use up memory and possibly run out (especially if you do it in a loop of 100,000).
Edit 2: As Galik mentions below, because you are using derconstant = new float[n] to allocate the memory, you need to use delete [] derconstant to free the memory. This is important when you start allocating space for class objects as the delete [] form will call the destructor of each element in the array.

Durand-Kerner method to find roots of nonlinear equation

I am being asked to find the roots of f(x) = 5x(e^-mod(x))cos(x) + 1 . I have previously used the Durand-Kerner method to find the roots of the function x^4 -3x^3 + x^2 + x + 1 with the code shown below. I thought I could simply reuse the code to find the roots of f(x) but whenever I replace x^4 -3x^3 + x^2 + x + 1 with f(x) the program outputs nan for all the roots. What is wrong with my Durand-Kerner implementation and how do I go about modifying it to work for f(x)? I would be very grateful for any help.
#include <iostream>
#include <complex>
#include <math.h>
using namespace std;
typedef complex<double> dcmplx;
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 1;
double a3 = -3;
double a2 = 1;
double a1 = 1;
double a0 = 1;
return (a4 * pow(x,4) + a3 * pow(x,3) + a2 * pow(x,2) + a1 * x + a0);
}
int main()
{
dcmplx p(.9,2);
dcmplx q(.1, .5);
dcmplx r(.7,1);
dcmplx s(.3, .5);
dcmplx p0, q0, r0, s0;
int max_iterations = 100;
bool done = false;
int i=0;
while (i<max_iterations && done == false)
{
p0 = p;
q0 = q;
r0 = r;
s0 = s;
p = p0 - f(p0)/((p0-q)*(p0-r)*(p0-s));
q = q0 - f(q0)/((q0-p)*(q0-r)*(q0-s));
r = r0 - f(r0)/((r0-p)*(r0-q)*(r0-s0));
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
// if convergence within small epsilon, declare done
if (abs(p-p0)<1e-5 && abs(q-q0)<1e-5 && abs(r-r0)<1e-5 && abs(s-s0)<1e-5)
done = true;
i++;
}
cout<<"roots are :\n";
cout << p << "\n";
cout << q << "\n";
cout << r << "\n";
cout << s << "\n";
cout << "number steps taken: "<< i << endl;
return 0;
}
The only thing I have been changing so far is the dcmplx f function. I have been changing it to
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 5;
double a0 = 1;
return (a4 * x * exp(-x) * cos(x) )+ a0;
}
The Durand-Kerner method that you're using requires the function to be continuous on the interval you are working.
Here we ahve a discrepancy between the mathematical view and the limits of the numeric applications. I'd propose you to plot your function (typing the formula in google will give you a quick overview of course for the real part). You'll notice that:
there are an infinity of roots due to the periodicity of the cosinus.
due to the x*exp(-x) the absolute value quickly rises up beyond the maximum precision that a floating point number can hold.
To understand the consequences on your code, I invite you to trace the different iteration. You'll notice that p, r and s are converging very quicky while q is diverging (apparently on the track of one of the huge peak):
At the 2nd iteration q is already at 1e74
At 3rd iteration already beyond what a double can store.
As q is used in the calculation of p,r and s, the error is propagated to the other terms
At 5th iteration, all terms are at NAN
It then continues bravely through the 100 iterations
Perhap's you could make it work by choosing different starting points. If not, you'll have to use some other method and carefully select the interwall on which you're working.
You should have noted in your documentation of the Durand-Kerner method (invented by Karl Weierstrass around 1850) that it only applies to polynomials. Your second function is far from being a polynomial.
Indeed, because of the mod function it has to be declared as a nasty function for numerical methods. Most of them rely on the continuity of the given function, i.e., if the value is close to zero, there is a good chance that there is a root nearby and if the sign changes on an interval then there is a root in the interval. Even the most basic derivate-free methods as the bisection method or Brents method on the sophisticated end of that class pre-suppose these properties.