Numerical derivative with C++ - c++

This question appeared a thousand times on different platforms. However I still need to understand something.
Here is a complete example:
#include <iostream>
#include <iomanip>
#include <cmath>
// function to derivative
double f (double var, void * params){
(void)(params);
return pow (var, 1.5);
}
// Naive central step derivative
double derivative1(double var, double f(double,void*), double h){
return (f(var+h,NULL) - f(var-h,NULL) )/2.0/h;
}
// Richardson 5-point rule
double gderivative(double var, double f(double,void*), double h0){
return(4.0*derivative1(var,f,h0) - derivative1(var,f,2.0*h0))/3.0;
}
int main (void){
for (int i=10;i>0;i--){
double h0=pow(10,-i);
double x=2.0;
double exact = 1.5 * sqrt(x);
double test1=derivative1(x,f,h0);
double gtest=gderivative(x,f,h0);
std::cout << "h0 = " << h0 << std::endl;
std::cout << "Exact = " << std::scientific<<std::setprecision(15) << exact << std::endl;
std::cout << "Naive step = " << std::setprecision(15) << test1 <<", diff = " << std::setprecision(15)<< exact-test1 << ", percent error = " << (exact-test1)/exact*100.0 << std::endl;
std::cout << "Richardson = " << std::setprecision(15) << gtest <<", diff = " << std::setprecision(15)<< exact-gtest << ", percent error = " << (exact-gtest)/exact*100.0 << std::endl;
}
return 0;
}
The output is
h0 = 1e-10
Exact = 2.121320343559643e+00
Naive step = 2.121318676273631e+00, diff = 1.667286011475255e-06, percent error = 7.859661632610832e-05
Richardson = 2.121318306199290e+00, diff = 2.037360352868944e-06, percent error = 9.604208808228318e-05
h0 = 1.000000000000000e-09
Exact = 2.121320343559643e+00
Naive step = 2.121320674675076e+00, diff = -3.311154328500265e-07, percent error = -1.560893119491818e-05
Richardson = 2.121320748689944e+00, diff = -4.051303013064000e-07, percent error = -1.909802555452698e-05
h0 = 1.000000000000000e-08
Exact = 2.121320343559643e+00
Naive step = 2.121320341608168e+00, diff = 1.951474537520426e-09, percent error = 9.199339191957163e-08
Richardson = 2.121320341608168e+00, diff = 1.951474537520426e-09, percent error = 9.199339191957163e-08
h0 = 1.000000000000000e-07
Exact = 2.121320343559643e+00
Naive step = 2.121320341608168e+00, diff = 1.951474537520426e-09, percent error = 9.199339191957163e-08
Richardson = 2.121320340868019e+00, diff = 2.691623368633600e-09, percent error = 1.268843424240664e-07
h0 = 1.000000000000000e-06
Exact = 2.121320343559643e+00
Naive step = 2.121320343606570e+00, diff = -4.692690680485612e-11, percent error = -2.212155601454860e-09
Richardson = 2.121320343643577e+00, diff = -8.393419292929138e-11, percent error = -3.956695799581460e-09
h0 = 1.000000000000000e-05
Exact = 2.121320343559643e+00
Naive step = 2.121320343584365e+00, diff = -2.472244631235299e-11, percent error = -1.165427295665677e-09
Richardson = 2.121320343595468e+00, diff = -3.582467655860455e-11, percent error = -1.688791448560268e-09
h0 = 1.000000000000000e-04
Exact = 2.121320343559643e+00
Naive step = 2.121320343340116e+00, diff = 2.195266191051815e-10, percent error = 1.034858406801534e-08
Richardson = 2.121320343561791e+00, diff = -2.148059508044753e-12, percent error = -1.012604963020456e-10
h0 = 1.000000000000000e-03
Exact = 2.121320343559643e+00
Naive step = 2.121320321462283e+00, diff = 2.209735949776359e-08, percent error = 1.041679516479040e-06
Richardson = 2.121320343559311e+00, diff = 3.317346397579968e-13, percent error = 1.563812088849040e-11
h0 = 1.000000000000000e-02
Exact = 2.121320343559643e+00
Naive step = 2.121318133840577e+00, diff = 2.209719065504601e-06, percent error = 1.041671557157002e-04
Richardson = 2.121320343601055e+00, diff = -4.141265108614789e-11, percent error = -1.952211093995174e-09
h0 = 1.000000000000000e-01
Exact = 2.121320343559643e+00
Naive step = 2.121099269013200e+00, diff = 2.210745464426012e-04, percent error = 1.042155406248691e-02
Richardson = 2.121320759832334e+00, diff = -4.162726914280768e-07, percent error = -1.962328286210455e-05
I believe the standard GSL gsl_deriv_central employs the Richardson procedure.
Now the common agument that is given to choose h0 is that theoretically it should be chosen as small as possible to improve the precision of derivative however numerically it should not be too small so that we hit floating point round off thus ruining the precision. So often it is said that the optimal choice should be somewhat around 1e-6 - 1e-8. My question is :
What is the optimal choice for h0 in a generic derivative?
Should I have to check case by case? Often it might not be possible to have an exact result to check with. What should one do in that case?
Now in this particular case it seems like the best choice for Naive step is h0 = 1.000000000000000e-05 whereas for Richardson h0 = 1.000000000000000e-03. This confuses me since these are not small.
Any suggestion on any other good options (easy algorithm/library) which is efficient as well as precise(double)?

This is quite as expected. The central difference has a second order error O(h^2) to the exact derivative. The function evaluation has an error of magnitude mu, the machine constant (for mildly scaled test examples). Thus the evaluation error of the central difference is of magnitude mu/h. The overall error is smallest if these two influences are about equal, thus h=mu^(1/3) gives h=1e-5, with an error of about 1e-10.
The same calculation for the Richardson extrapolation gives error order O(h^4) towards the exact derivative, resulting in h=mu^(1/5)=1e-3 as optimal step size, with an error of about 1e-12.
loglog plot of the errors of both methods over a larger sample of step sizes
In practical applications you would want to scale h so that the indicated sizes are relative to the size of x. The exact optimum depends also on the magnitudes of the derivatives of the function, if they grow too wildly.
To get more precise values for the derivatives, you would need a higher or multi-precision data type, or employ automatic/algorithmic differentiation, where the first and second derivatives can be evaluated with the same precision as the function values.

Personal opinion warning
In my experience i find it better to use a stepsize that is small compared to the variable it affects.
For example, I usually use something like this:
auto dfdx(std::function<double (double)> f, double x, double h0=1e-5){
h0=std::abs(x)*h0+h0; // this is 1e-5 if x<<1e-5, and |x|*1e-5 otherwise
return ( f(x+h0) - f(x-h0) )/2/h0;
}
This should work, since finite differences are motivated by Taylor expansion. That is, as long as x<<h0, the finite difference should be an good approximation.

Related

Function for Newton's Method in C++

I am getting back into programming after twenty years. I was a good C programmer then, so I am jumping in with C++. For my first project, I am writing a function to calculate a cube root using Newton's Method.
Instead of converging on the answer, it just keeps approaching zero. Since it was so small, I figured it was easier to print out step by step values rather than use the debugger.
I am using Visual C++, with Visual Studio.
Here is the entire function:
double CalcCube(double xx, double guess)
{
int ii = 0;
double result, resbuff;
for (ii = 0; ii < 10; ii++)
{
resbuff = guess - (pow(guess,3) / (3*guess*guess));
cout << "Resbuff = " << resbuff << endl;
cout << "Guess = " << guess << endl;
guess = resbuff;
}
result = guess;
return result;
}`
`
Wrong equation used
Newton's Method finds the value of x such that f(x) = 0.
Code is solving 0 = x*x*x, which the answer is x = 0.
// x*x*x
// resbuff = guess - (pow(guess,3) / (3*guess*guess));
The zero being sought is the solution to 0 = y - x*x*x
resbuff = guess - (xx - pow(guess,3) / (3*guess*guess));
// y - x*x*x
The problem is the math:
pow(guess,3) / (3*guess*guess) = guess^3 / 3*guess^2 = guess/3
=> resbuf= guess - guess/3
So in each iteration you get an smaller value, tending to 0
The equation for computing cube root using the Newton Raphson method is (from https://socratic.org/questions/how-do-you-use-newton-s-method-to-approximate-the-value-of-cube-root)
xn1 = xn - (x - xn^3)/3*xn^2
By using
resbuff = guess - (pow(guess,3) / (3*guess*guess));
you are computing the cube root of zero. That's why you are getting zero as your answer.
Change that line to
resbuff = guess - (xx - pow(guess,3)) / (3*guess*guess));
to get the correct answer.

comparing equal calculation outputs for floating point numbers

The outputs of two calculations are supposed to be same as described below but even after taking machine precision into account, they come out to be unequal. What would be way around it to get them equal?
#include <iostream>
#include <limits>
#include <math.h>
bool definitelyGreaterThan(double a, double b, double epsilon)
{
return (a - b) > ( (std::fabs(a) < std::fabs(b) ? std::fabs(b) : std::fabs(a)) * epsilon);
}
bool definitelyLessThan(double a, double b, double epsilon)
{
return (b - a) > ( (std::fabs(a) < std::fabs(b) ? std::fabs(b) : std::fabs(a)) * epsilon);
}
int main ()
{
double fig1, fig2;
double m1 = 235.60242, m2 = 126.734781;
double n1 = 4.2222, n2 = 2.1111;
double p1 = 1.245, p2 = 2.394;
fig1 = (m1/m2) * (n1/n2) - p1 * 6.0 / p2;
m1 = 1.2*m1, m2 = 1.2*m2; // both scaled equally, numerator and denominator
n1 = 2.0*n1, n2 = 2.0*n2;
p1 = 3.0*p1, p2 = 3.0*p2;
fig2 = (m1/m2) * (n1/n2) - p1 * 6.0 / p2; // same as above
double epsilon = std::numeric_limits<double>::epsilon();
std::cout << "\n fig1 " << fig1 << " fig2 " << fig2 << " difference " << fig1 - fig2 << " epl " << epsilon;
std::cout << "\n if(fig1 < fig2) " << definitelyLessThan(fig1, fig2, epsilon)
<< "\n if(fig1 > fig2) " << definitelyGreaterThan(fig1, fig2, epsilon) << "\n";
}
with output as -
fig1 0.597738 fig2 0.597738 difference 8.88178e-16 epl 2.22045e-16
if(fig1 < fig2) 0
if(fig1 > fig2) 1
The difference between two numbers is greater than machine precision.
The key question is whether there is any universal method to deal with such aspects or solution has to be application dependent?
There are two things to consider:
First, the possible rounding error (introduced by limited machine precision) scales with the number of operations that were used to calculate the value. For example, storing the result of m1/m2 might introduce some rounding error (depending on the actual value), and multiplying this value with something also multiplies that rounding error, and adds another possiblie rounding error on top of that (by storing that result).
Second, floating point values are not stored linearly (instead, they use an exponent-and-mantissa format): The bigger a values actually is, the bigger is the difference between that value and the next representable value (and therefore also the possible rounding error). std::numeric_limits<T>::epsilon() only states the difference between 1.0 and the next representable value, so if your value is not exactly 1.0, then this epsilon does not exactly represent the machine precision (meaning: The difference between this value and the next representable one) for that value.
So, to answer your question: The solution is to select an application-dependend, reasonable maximum rounding error that is allowed for two values to still be considered equal. Since this allowed rounding error depends both on expected values and number of operations (as well as what's acceptable for the application itself, of course), a truly universal solution is not possible.

Fastest way to find complex roots

Using a + i b = sqrt(a*a + b*b) * exp(i arctan2(a,b)) I arrive at the following way to compute complex roots. However, I heard that trigonometric functions rather use up performance so I wonder if there is a better way in vanilla c++ (no external libaries).
Example: Let u+iv = sqrt(a+i b)
#include <math.h>
#include <iostream>
int main(){
double a = -1.;
double b = 0;
double r = sqrt(sqrt(a*a+b*b));
double phi = 0.5 * atan2(b, a);
double u = r * cos(phi);
double v = r * sin(phi);
std::cout << u << std::endl;
std::cout << v << "i" << std::endl;
}
This is just meant as a MWE, so it's not written in a class or method.
Yes there is! I'm going to link a good explanation of the process here, but it looks like this can be accomplished by only calculating the magnitude of the original number and subtracting out the real portion of the original number and finally taking the square root of that to find the imaginary part of the square root. The real part can be found by dividing the imaginary part of the original number by 2 * the imaginary part of the root to get your final answer.
https://www.qc.edu.hk/math/Advanced%20Level/Finding%20the%20square%20root%20of%20a%20complex%20number.htm
Let me know if you need more help with the code but this requires no trig functions.

C/C++ compare to Nan (different behaviors on different floating point model)

here a little test code:
float zeroF = 0.f;
float naNF = 0.f / zeroF;
float minimumF = std::min(1.0f, naNF);
std::cout << "MinimumF " << minimumF << std::endl;
double zeroD = 0.0;
double naND = 0.0 / zeroD;
double minimumD = std::min(1.0, naND);
std::cout << "MinimumD " << minimumD << std::endl;
I executed the code on VS2013.
On precise model (/fp:precise) the outputs are always "1";
On fast model (/fp:fast) the outputs will be "Nan" (-1.#IND) if optimization is enabled (/O2) and "1" if optimization is disabled (/Od).
First, what should be the right output according to IEEE754 ?
(I read the docs and googled different articles like: What is the rationale for all comparisons returning false for IEEE754 NaN values?, and it seems that the right output should by Nan and not 1 but maybe I am wrong.
Secondly, how the fast model optimization here changes so drastically the output?

trouble using an equation in a function

Write a program that determines how far and for how long a time a rock will travel when you throw it off a cliff. Click here to copy the file toss.txt to your desktop (right click the file name and choose Save as). The file contains the height of the cliff in meters.
The program will then:
Open the file toss.txt and read the cliff height into a double-precision variable, then echo print the value of the cliff height to the screen with an appropriate label.
Ask the user for the angle at which the rock is thrown (90 degrees is straight up, and 0 degrees is straight forward), and the velocity at which the rock is thrown (in miles per hour).
Check to make sure the angle is greater than or equal to 0 and less than or equal to 90. If it is not, the program terminates and prints an appropriate error message to the screen.
Check to make sure the velocity is less than or equal to 100 mph and greater than or equal to 0 mph. If it is not, the program terminates and prints an appropriate error message to the screen.
If the angle and velocity are valid, the program completes the calculations as follows:
Converts miles per hour to meters per second.
Converts the angle to radians.
Calculates the time traveled using the following equations:
where
Calculates the distance traveled in the horizontal direction using:
Outputs the time and distance traveled in the horizontal direction to the screen with appropriate labels.
Prints an appropriate message telling the user if the distance traveled in the horizontal direction was greater than, less than, or equal to the height of the cliff.
/* This program */
using namespace std;
#include<iostream>
#include<cmath>
#include<iomanip>
#include<fstream>
int readit ();
int calcit (double, double, double);
int main()
{
readit ();
system ("pause");
return 0;
}
int readit ()
{
double hite, angl, v;
ifstream datain ( "toss.txt" );
datain >> hite;
cout << "The cliff height is " << hite << " meters"<< endl;
cout << "Enter the angle in degrees (from horizontal) the rock is thrown: "
<< endl;
cin >> angl;
if (angl>=0 && angl<=90)
{
cout << endl << "The angle you have entered is "<<angl<< endl <<endl;
}
else
{
cout << "The angle you have entered is not acceptable" << endl;
return 0;
}
cout << "Enter the velocity in mph the rock is thrown: " << endl;
cin >> v;
if (v>=0 && v<=100)
{
cout << endl << "The velocity at which the rock is thrown is "<<v<<
" mph" << endl << endl;
}
else
{
cout << "The velocity you have entered is not acceptable" << endl;
return 0;
}
calcit (hite, angl, v);
}
int calcit (double hite, double angl, double v)
{
double tyme, dist;
v = v * (1609.344/3600);
angl = angl*(M_PI/180);
tyme = -v*sin(angl) + (sqrt((v*sin(angl)*v*sin(angl)) + 2*9.8*hite)/9.8) + (2*(v*sin(angl))/9.8);
dist = (tyme * v) * cos(angl);
cout << tyme << " " << dist <<endl;
}
I am trying to get the correct time the rock is traveling before it hits the ground but i keep getting incorrect answers. I am not sure if i am turning the equation to figure out the time the rock will be in the air until impact into c++ language right. any have any ideas??? i really need to finish this damn project.
Starting from the equation for the y (height above 0) for the rock we have
y = h + v*sin(a)*t - g/2*t^2
which transforms into
g/2 T^2 - v*sin(a)*T - h == 0
when we solve for the final condition y(T)=0.
This yields
T = v*sin(a)/g + sqrt(v*sin(a)*v*sin(a) + 2*g*h)/g
I just can't figure out where the first part -v*sin(angl) in your equation comes from. Everything else looks just fine. So it seems not to be with your code but with the equation you started.
The equation you want is:
s =ut + 1/2 at^2
s = Total distance traveled. (Height of the cliff)
u = Starting velocity (In your case negative as you are throwing
away from the target. And take into account
that not all the starting velocity is away
from the target (eg angle 0 mean u = 0))
a = acceleration (9.81 m/s2)
t = time (The value you want to calculate).
Rearrange the formula to solve for t
To find the solution for t where s = 0...
This formula is you basic quadratic:
y = a.x^2 + b.x + c
Where:
x/y are variables.
a/b/c are constants.
The solution for a quadratic equation where y is 0 is:
x = [ -b ± sqrt(b^2 - 4ac) ] / 2a
Notice the ± symbol. There are actually two solutions to the problem.
You should be able to deduce which one is correct for you as the other
is probably negative.
In your particular case the map is:
x ==> t
y ==> 0
a ==> 1/2.g
b ==> u
c ==> -s
I would suggest a few things to "clean up" the code a bit:
If functions return int ensure that they do really return something. (main doesn't have to but other functions do).
Calculate v * sin(ang1) once then use it in your formula thereafter. Not only more efficient but will make your code clearer.
Like you have given Pi a "constant", do that with other numbers you are using like 9.8 (gravitational force?)
If you have a confusing formula in the code, just introduce more variable names until the meaning becomes obvious. So long as you don't reassign different values to the same variables, this will not make the program confusing.
int calcit (double hite_meters, double angl_deg, double v_mph)
{
double const gravity = 9.8;
double v_ms = v_mph * (1609.344/3600);
double angl_rad = angl_deg * (M_PI/180);
double v_vertical = v_ms * sin( angl_rad );
double time_up = v_vertical / gravity; // [m/s] / [m/s^2] = [s]
double time_down_over_cliff = time_up;
// use quadratic formula t = ( -v - ( v^2 - 4gd )^1/2 ) / 2g:
double time_under_cliff = ( - v_vertical
- sqrt( ( v_vertical * v_vertical )
- ( 4 * - gravity * hite_meters ) ) // negative gravity = down
) / ( 2 * - gravity ); // ( [m/s] + ([m/s]^2 - [m/s^2]*[m])^1/2 ) / [m/s^2]
// = [m/s] / [m/s^2] = [s]
double time_total = time_up + time_down_over_cliff + time_under_cliff;
double v_horizontal = v_ms * cos( angl_rad );
double dist_horizontal = v_ms * time_total;
cout << time_total << " " << dist_horizontal <<endl;
}
Every line of code produces a new, relevant piece of information. When converting to a new unit, I introduce a new variable with a new name. Formulas involving more than one unit get the unit types explained in a comment. This should help turn up unit conversion errors which otherwise I can't help you catch.
Writing this kind of code involves more typing, but the time saved on head-scratching and asking for help more than makes up for it.
The program itself is not any less efficient. More importantly, it may be easily modified, so it won't turn into an inefficient mess after a few revisions.