Cube root of a number, C++ - 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.

Related

C++ function inside function

/*I need to use the result from the (delta) function inside the (sol_ec_II) function for a school assignment.*/
#include <iostream>
#include <ctgmath>
using namespace std;
double delta(double a, double b, double c) {
return (b * b) - (4 * a * c);/* so I need to take this value [(b * b) - (4 * a * c)]
and use it in sol_ec_II in the places where I wrote "delta". */
}
void sol_ec_II(double a, double b, double c) {
if (delta < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
// I would also need to use the (delta) function inside the (sol_ec_II) so they use the same
a, b, c values like this:
void sol_ec_II(double a, double b, double c) {
delta(a, b, c);
if (delta < 0) {
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);
double x2 = -1 * b + sqrt(delta);
}
}
//so I don't understand how to get the value that results from delta(a, b, c) and use it inside the if statement and sqrt.
The result "comes out" of the function call at the time you call it. Look, you already know how sqrt works. sqrt is a function! You write sqrt(something) and that calls the function sqrt and it calls the function sqrt with the argument something and then the return value from sqrt gets used in the place where you wrote sqrt(something). e.g. 1 + sqrt(4) calculates 3.
Likewise the return value from delta gets used in the place where you wrote delta(a, b, c). If you want to call delta and then call sqrt (i.e. calculate the square root of the delta) you write sqrt(delta(a, b, c)).
Obviously, just calculating a number is pretty useless. You probably want to do something with the number, like saving it in a variable or printing it. Examples:
cout << "the square root of the delta is " << sqrt(delta(a,b,c)) << endl;
cout << "the delta plus one is " << (delta(a,b,c) + 1) << endl;
double the_delta = delta(a,b,c);
cout << "the delta is " << the_delta << " and the square root of the delta is " << sqrt(the_delta) << endl;
if (delta(a,b,c) < 0)
cout << "the delta is negative" << endl;
else
cout << "the delta isn't negative" << endl;
Note: Every time the computer runs delta(a,b,c) it calls the delta function. It doesn't remember the calculation from last time. You can see this because if you put cout instructions inside the delta function, they get printed every time the computer runs delta(a,b,c).
Of course I will not give you the solution for your program. I hope this helps you understand how functions work.
here you should pass parameters to deleta function in order to execute it:
void sol_ec_II(double a, double b, double c) {
if (delta(a,b,c) < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
or you could save the result in a new variable called result for example, and after that use it, like that:
void sol_ec_II(double a, double b, double c) {
double result = delta(a,b,c);
if (result < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
The Same thing for the second function, always to execute a function use parenthesis and pass between them the arguments that the function expects.
To reuse the value you get from calling a function multiple time use a variable:
double delta(double,double,double) { return 1.2; /*ignore this for now*/ }
void sol_ec_II(double a, double b, double c) {
const auto kDelta = delta(a, b, c);
if (kDelta < 0.0) {
// do stuff
} else {
const auto kRootD = sqrt(kDelta); // same idea
const auto x1 = -b - kRootD;
const auto x2 = -b + kRootD;
// use the variables
}
}
I use auto out of habit, you don't need to, double is fine.

sum of series in c++ using if Conditional

am trying to solve the equation in c++ sum of series and am getting the right result
but I just trying to use the if statement to get the same answer of this equation
but always am getting struggling with it
# include <math.h>
#include <iostream>
using namespace std;
int main()
{
double x = 1;
double som = 0;
double lim_nbr = pow(10.0, -6);
int n = 1;
do{
x = 1.0 / ((n*n*4.0 - 1) * n);
som += x;
n+=1;
}while (x >= lim_nbr);
double correctSum = 2.0*log(2.0) -1.0 ;
cout << "Sum = " << som << endl;
cout << "Sumcorrect = " << correctSum << endl;
}
In this case for you to calculate a loop shape using only if, an alternative is to use recursive functions, look at this example:
#include <math.h>
#include <iostream>
using namespace std;
double calc(double lim_nbr, double som, double x, int n)
{
if(x >= lim_nbr || som == 0)
{
x = 1.0 / ((n*n*4.0 - 1) * n);
som += x;
n+=1;
calc(lim_nbr, som, x, n);
}
else
{
return som;
}
}
int main()
{
double lim_nbr = pow(10.0, -6);
/* Call the function with the initial values */
double som = calc(lim_nbr, 0, 1, 1);
cout << "SumWithIf = " << som <<endl;
}
The result you are getting using the do while loop is an approximation to the exact value that you are getting in correctSum. correctSum is the result obtained by adding the series upto infinte terms, however your do while loop calculates only up to a finite number of terms. Therefore the difference of the two values shows up as the error.

What's wrong with my durand-kerner implementation?

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

The "infinite" increase/decrease in an angle

I need to increase/reduce phi angle by value d infinitely. (d can be negative or positive).
"Infinitely" means that cycling change can happen as much as long. But to avoid overflowing it is necessary "drop" value, relying on periodicity of sin () and cos (). (0 <=> 2*pi <=> 2*n*pi).
How it can be implemented in function? (e.g. double stepAngle(double phi, double d)).
The standard library functions just "do the right thing" for values > 2*pi, you don't have to do anything:
int main() {
double pi = 3.14159265359;
double x = 2.5;
cout << sin(x) << endl;
cout << sin(x + 2*pi) << endl;
cout << sin(x - 8*pi) << endl;
}
These will all print the same value; try it out.
This is possible with fmod fairly easily.
double stepAngle(double phi, double d)
{
double newPhi = phi += fmod(2*pi, d);
if(newPhi > 2*pi)
{
newPhi -= 2*pi;
}
if(newPhi < 0)
{
newPhi += 2*pi;
}
return newPhi;
One approach is to renormalize to the desired range:
while (d > 2*pi) d -= 2*pi;
while (d < 0) d += 2*pi;
That will be efficient as long as d is not extremely far outside the range of 0..2*pi.

Adaptive Quadrature (C++)

I'm having issues with my adaptive trapezoidal rule algorithm in C++ -- basically, regardless of the tolerance specified, I get the same exact approximation. The recursion is supposed to stop very early for large tolerances (since abs(coarse-fine) is going to be smaller than 3.0*large tolerance and minLevel of recursion is about 5).
However, what this function does is run the maximum number of times regardless of choice of tolerance. Where did I mess up?
EDIT: Perhaps there are issues in my helper functions?
double trap_rule(double a, double b, double (*f)(double),double tolerance, int count)
{
double coarse = coarse_helper(a,b, f); //getting the coarse and fine approximations from the helper functions
double fine = fine_helper(a,b,f);
if ((abs(coarse - fine) <= 3.0*tolerance) && (count >= minLevel))
//return fine if |c-f| <3*tol, (fine is "good") and if count above
//required minimum level
{
return fine;
}
else if (count >= maxLevel)
//maxLevel is the maximum number of recursion we can go through
{
return fine;
}
else
{
//if none of these conditions are satisfied, split [a,b] into [a,c] and [c,b] performing trap_rule
//on these intervals -- using recursion to adaptively approach a tolerable |coarse-fine| level
//here, (a+b)/2 = c
++count;
return (trap_rule(a, (a+b)/2.0, f, tolerance/2.0, count) + trap_rule((a+b)/2.0, b, f, tolerance/2.0, count));
}
}
EDIT: Helper and test functions:
//test function
double function_1(double a)
{
return pow(a,2);
}
//"true" integral for comparison and tolerances
//helper functions
double coarse_helper(double a, double b, double (*f)(double))
{
return 0.5*(b - a)*(f(a) + f(b)); //by definition of coarse approx
}
double fine_helper(double a, double b, double (*f)(double))
{
double c = (a+b)/2.0;
return 0.25*(b - a)*(f(a) + 2*f(c) + f(b)); //by definition of fine approx
}
double helper(double a, double b, double (*f)(double x), double tol)
{
return trap_rule(a, b, f, tol, 1);
}
And here's what's in main():
std::cout << "First we approximate the integral of f(x) = x^2 on [0,2]" << std::endl;
std::cout << "Enter a: ";
std::cin >> a;
std::cout << "Enter b: ";
std::cin >> b;
true_value1 = analytic_first(a,b);
for (int i = 0; i<=8; i++)
{
result1 [i] = helper(a, b, function_1, tolerance[i]);
error1 [i] = fabs(true_value1 - result1 [i]);
}
std::cout << "(Approximate integral of x^2, tolerance, error )" << std::endl;
for (int i = 0; i<=8; i++)
{
std::cout << "(" << result1 [i] << "," << tolerance[i] << "," << error1[i] << ")" << std::endl;
}
I find that exactly the opposite of what you suggest is happening --- the algorithm is terminating after only minLevel steps --- and the reason is due to your usage of abs, rather than fabs in the tolerance test. The abs is converting its argument to an int and thus any error less than 1 is getting rounded to zero.
With the abs in place I get this output from a very similar program:
(0.333496,0.001,0.00016276)
(0.333496,0.0001,0.00016276)
(0.333496,1e-05,0.00016276)
(0.333496,1e-06,0.00016276)
(0.333496,1e-07,0.00016276)
(0.333496,1e-08,0.00016276)
(0.333496,1e-09,0.00016276)
(0.333496,1e-10,0.00016276)
(0.333496,1e-11,0.00016276)
Replacing with fabs I get this:
(0.333496,0.001,0.00016276)
(0.333374,0.0001,4.06901e-05)
(0.333336,1e-05,2.54313e-06)
(0.333334,1e-06,6.35783e-07)
(0.333333,1e-07,3.97364e-08)
(0.333333,1e-08,9.93411e-09)
(0.333333,1e-09,6.20882e-10)
(0.333333,1e-10,3.88051e-11)
(0.333333,1e-11,9.7013e-12)