Restricted 3 body simulation not working correctly - c

I am currently trying to do an assignment where i have to write a simulation for the restricted 3 body gravitational problem, with two fixed masses and one test mass. The information i have been given on the problem is: Check out this link and here is my program so far:
#include<stdlib.h>
#include<stdio.h>
#include <math.h>
int main (int argc, char* argv[])
{
double dt=0.005, x[20000],y[20000],xv,yv,ax,ay,mneg,mpos,time,radius=0.01;
int n,validation=0;
FILE* output=fopen("proj1.out", "w");
printf("\n");
if((argv[1]==NULL) || (argv[2]==NULL) || (argv[3]==NULL) || (argv[4]==NULL) || (argv[5]==NULL) || (argv[6]==NULL))
{
printf("************************ ERROR! ***********************\n");
printf("** Not enough comand line arguments input. **\n");
printf("** Please run again with the correct amount (6). **\n");
printf("*******************************************************\n");
validation=1;
goto VALIDATIONFAIL;
}
if((sscanf(argv[1], "%lf", &mneg)==NULL) || (sscanf(argv[2], "%lf", &mpos)==NULL) || (sscanf(argv[3], "%lf", &x[0])==NULL) ||
(sscanf(argv[4], "%lf", &y[0])==NULL) || (sscanf(argv[5], "%lf", &xv)==NULL) || (sscanf(argv[6], "%lf", &yv)==NULL) )
{
printf("************************* ERROR! ************************\n");
printf("** Input values must be numbers. Please run again with **\n");
printf("** with numerical inputs (6). **\n");
printf("*********************************************************\n");
validation=1;
goto VALIDATIONFAIL;
}
sscanf(argv[1], "%lf", &mneg);
sscanf(argv[2], "%lf", &mpos);
sscanf(argv[3], "%lf", &x[0]);
sscanf(argv[4], "%lf", &y[0]);
sscanf(argv[5], "%lf", &xv);
sscanf(argv[6], "%lf", &yv);
x[1]=x[0]+(xv*dt);
y[1]=y[0]+(yv*dt);
for(n=1;n<10000;n++)
{
if(x[n-1]>=(1-radius) && x[n-1]<=(1+radius) && y[n-1]>=(0-radius) && y[n-1]<=(0+radius))
{
printf("Test mass has collided with M+ at (1,0), Exiting...\n");
goto EXIT;
}
else if(x[n-1]>=(-1-radius) && x[n-1]<=(-1+radius) && y[n-1]>=(0-radius) && y[n-1]<=(0+radius))
{
printf("Test mass has collided with M- at (-1,0), Exiting...\n");
goto EXIT;
}
else
{
double dxn = x[n] + 1;
double dxp = x[n] - 1;
double mnegdist = pow((dxn*dxn + (y[n]*y[n])), -1.5);
double mposdist = pow((dxp*dxp + (y[n]*y[n])), -1.5);
ax = -(mpos*dxp*mposdist+mneg*dxn*mnegdist);
ay = -(mpos*y[n]*mposdist+mneg*y[n]*mnegdist);
x[n+1]=((2*x[n])-x[n-1] +(dt*dt*ax));
y[n+1]=((2*y[n])-y[n-1]+(dt*dt*ay));
fprintf(output, "%lf %lf\n",x[n-1], y[n-1]);
}
}
VALIDATIONFAIL:
printf("\n");
return(EXIT_FAILURE);
EXIT:
return(EXIT_SUCCESS);
}
My program is working to certain extent but i am getting some weird problems that i hope someone can help me with.
The main issue is that when the test mass gets to a point in its trajectory when it should go off and start to orbit about the other mass it instead just shoots off on a straight line to infinity! at first i thought it was that the masses were colliding so i put in the radius check, but in some cases this does work, in some cases it doesn't, and in some cases the masses collide earlier on before the trajectory goes wrong anyway so this clearly isn't the issue. I am not sure if i have explained that all too well so here is a picture to show you what i mean. (the simulation on the right is from here)
However, this is not always the case, sometimes instead of going in a straight line, the trajectory just goes crazy when it should go over to the other mass, like this:
I really have absolutely no idea whats going on i have spent days trying to figure this out but just cant seem to get anywhere, so any help in identifying where my problem is would be very much appreciated.

This is just too long to fit in a comment and I also might be of use to future visitors.
The proper choice of timestep for a given computation is not an easy task. The family of Verlet integrators are symplectic, which means that they preserve the phase space volume and hence should preserve the total energy of the system given infinite precision and an infinitely small timestep, but unfortunately real computers operate with finite precision and the human life is too short in order for us to wait for an infinite number of timesteps.
The Verlet integrator, like the one that you have implemented and the velocity Verlet scheme, have global error which is O(Δt2). It means that the algorithm is only quadratically sensitive to the timestep and in order to greatly improve the precision, one has to decrease the timestep accordingly by as many times as the square root of the desired precision improvement factor. Click on the into button of the Flash applet that you compare your trajectories with and you'll see that it uses a completely different integrator - the Euler-Cromer algorithm (also known as semi-implicit Euler method). It has different precision given the same timestep (actually it is worse than that of the Verlet scheme given the same timestep) and hence you cannot and should not directly compare both trajectories, rather only their statistical properties (e.g. mean energy, mean velocity, etc.)
My point was that you have to decrease the timestep, because it is too large to handle the cases when the test body comes too close to one of the gravitational centres. There is another problem hidden here and it is the finite numerical precision. Observe this term:
double dxp = x[n] - 1;
double mposdist = pow((dxp*dxp + (y[n]*y[n])), -1.5);
Whenever you subtract two closely valued floating point numbers (x[n] and 1.0), a very unfortunate event happens, known as precision loss as most of the higher significant bits in their mantissas cancel each other and in the end, after the normalisation step, you get a number with much less significant bits than the original two numbers. This precision loss gets even bigger as the result is then squared and used as a denominator. Note that this mostly happens near the axis of symmetry of the system where y[n] comes close to 0. Otherwise y[n] might be big enough so that dxp*dxp is only a tiny correction to the value of y[n]*y[n]. The net result is that the force would come out totally wrong near each fixed mass and would usually be greater in magnitude than the actual force. This is prevented in your case as you test for the point being outside the prescribed radius.
Greater forces lead to greater displacements given a fixed timestep. This also leads to an artificial increase in the total energy of the system, i.e. the test mass would tend to move faster than in a finer simulation. It also might happen that the test body ends up so close to the gravitational centre, that the huge force times the square of the timestep might give so huge a displacement, that your test mass would end up much far away, but this time with the increased total energy it would result in high kinetic energy and the body would practically be ejected from the simulation volume. This could also happen even if you compute the force with infinite precision - simply the displacement between two timesteps might be so large (because of the large timestep) that the system would make an unrealistic jump in the phase space to a completely different energy isosurface. And with gravity (as well as with electrostatics) it is so easy to get to such a case as the force increases as 1/r^2 and near the radius it is many orders of magnitude stronger than in the initial state.
One might come up with different rules of a thumb to estimate the size of the timestep given the largest expected force value, but in general the higher the maximum force, the lower the timestep should be. These kind of things can usually be roughly estimated given the initial conditions, which saves a lot of failed simulations due to "ejection" effects.
Now as the Verlet schemes are symplectic, the best way to control the correctness of the simulation is to observe the total energy of the system. Note that the velocity Verlet integrator is a bit better as it is numerically more stable (but still it has the same dependence of the accuracy on the square of the timestep). With the standard Verlet scheme you can get an approximation of the speed v[i] by taking (x[i+1] - x[i-1])/(2*dt). With the velocity Verlet, the speed is included explicitly in the equations.
Either way, it would make sense to take the speed and to compute the total energy of the system at each timestep and to observe the value. If the timestep is Just Right (tm), then the total should be almost conserved with relatively small oscillations around the mean value. If it goes crazy upwards, then your timestep is too big and should be decreased.
Decreasing the timestep increases the run-time of the simulation accordingly. One could also observe that in the far field the forces are small, the point moves slowly and a long timestep is just fine. Shorter timestep would not improve the solution there but would only increase the run-time. That's why people have invented the multi-timestep algorithms and also the adaptive timestep algorithms that automatically refine the solutions in the near field. Also a different method to compute the forces might be applied there by transforming the equations so as to not include subtraction of closely valued variables.
(well, this came out way larger than even several comments)

I found it difficult to understand your code, so I will try to be as helpful as I can and apologize, if I am telling you things you already know.
The best way I have found to calculate the physics for simulations involving gravity is to use Newtons Law of Universal Gravitation. This is given by the formula:
F = ( ( -G * M1 * M2 ) / ( R * R ) ) * r_unit_vector;
Where:
G ~= 6.67e-11,
M1 is the mass of the first object,
M2 is the mass of the second object,
R is the distance between the two objects: sqrt(pow(X2 - X1, 2) + pow(Y2 - Y1, 2))
X1 is the X-coordinate of object 1,
X2 is the X-coordinate of object 2,
Y1 is the Y-coordinate of object 1,
Y2 is the Y-coordinate of object 2.
r_unit_vector is a unit vector pointing from object 2 to object 1
struct r_unit_vector_struct{
double x, y;
}r_unit_vector;
r_unit_vector has a x component which is object 2's x-coordinate - object 1's x-coordinate,
r_unit_vector has a y component which is object 2's y-coordinate - object 1's y-coordinate.
To make r_unit_vector a unit vector, you must divide (both the x aand y components separately) by its length, which is given by sqrt(pow(r_unit_vector.x, 2) + pow(r_unit_vector.y - Y1, 2))
And you should all be ready to go! Hopefully this makes sense. If not, I will write you a class to do this stuff or explain it further if I can!

Related

Algorithm for pool ball movement calcualtion

I need help or idea how to make an algorithm for a pool game/program.
I need this as a project for my collage so this needs to be written as simply as possible using only basic and loops,sadly I can't use arrays or functions.
The whole point of the program is to calculate how many steps/hits on the corner of the table will the ball need to reach its starting point (Assumed that ball has infinite velocity and that there are no other balls etc.. Simply we assume that its possible)
We need to look at the table as a coordinate system with (m x n) dimensions, and we need to input starting point of the ball (x1,y1) and the point where the ball will hit the table for the first time (x2,y2) based on that info we need to make an algorithm that will calculate how many hits/steps will the ball need to reach its starting point.
I had an idea to use the fact that ball will have same angle on impact which means that if the ball hits the table on 30 degrees angle it will repel off the table with same angle to the other side. So because the tables is set as a coordinate system I could use atan to calculate the angle and then with that info to calculate the distance from the other point. I made a program with the info I know but this won't work because this is only one calculation (I guess that I will need to use for loop(s) to calculate everything. And I have a big problem in understanding how to set the edge of the table because some of my calculations goes outside the (m x n) space.
I will attach 2 pictures that were given to us as examples and part of the code that I use. I hope that someone can help me and I'm sorry if I made a lot of grammar mistakes, English is not my primary language.
Thanks in advance.
PICTURES :
Orange dot is the starting point, orange line is the first hit that we input,everything else needs to be calculated:
Same as picture one but more complex example:
MY CODE:
#include <stdio.h>
#include <math.h>
#define PI 3.14159265359
int main() {
int i;
double x1,y1,x2,y2;
int n,m;
double angle;
double xPrime,yPrime;
double distance;
double m1;
printf("Enter the staring point (x1,y1) and first hit point(x2,y2) ");
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
printf("Enter the dimensions (n x m ) ");
scanf("%d %d",&n,&m);
m1=(y2-y1)/(x2-x1);
angle=atan(m1);
distance =sqrt( pow((x2-x1),2) + pow((y2-y1),2));
xPrim = x2 + (-distanca * cos(ugao));
yPrim = y2 + (distanca * sin(ugao));
return 0;
}
You should consider the X and Y axes separately. The discussion below assumes that the ball initially starts moving in the positive direction on both axes. If it doesn't then flip stuff around to the symmetrical situation so that it does.
Given the table size by M x N, the starting point (x0,y0), and the first hit (x1,y1):
Let T be the time it takes to get from (x0,y0) to (x1,y1), so the initial velocity (in units per T) is (vx,vy) = (x1-x0, y1-y0)
Considering the X axis, the ball will hit a wall at time (M-x0)/vx, measured in units of T. It will get back to the starting X coordinate at time (2M-2x0)/vx. It will hit the other wall at time (2M-x0)/vx and get back to the start position again at time 2M/vx. Then the cycle will repeat.
So, the times at which it will get back to the start position are (2aM - 2x0)/vx and 2aM/vx, for all integer a>0. The times it will hit a wall are (2aM - x0) and ((2a-1)M - x0).
Similarly, on the Y axis, the times it will get back to the start position are (2bN - 2y0)/vy and 2bN/vy, for all integer b>0. The times it will hit a wall are (2bN - y0) and ((2b-1)N - y0).
So, to find times when the ball gets back to the start, solve:
(2aM - 2x0)/vx = (2bN - 2y0)/vy or
(2aM - 2x0)/vx = 2bN/vy or
2aM/vx = (2bN - 2y0)/vy or
2aM/vx = 2bN/vy
for the smallest integers a>0 and b>0.
All of these reduce to linear Diophantine equations that are readily solved: https://en.wikipedia.org/wiki/Diophantine_equation
Once you know how long it takes to get back to the start, you can use the other equations above to calculate how many wall hits were made.

Led bar indicator flickering within adjacent values and how to avoid this (embedded-C)

I am designing a measurement instrument that has a visible user output on a 30-LEDs bar. The program logic acts in this fashion (pseudo-code)
while(1)
{
(1)Sensor_Read();
(2)Transform_counts_into_leds();
(3)Send_to_bar();
{
The relevant function (2) is a simple algorithm that transforms the counts from the I2C sensor to a value serially sent to shift-registers that control the single leds.
The variable sent to function (3) is simply the number of LEDs that have to stay on (0 for al LEDs off, 30 for all LEDs on)
uint8_t Transform_counts_into_leds(uint16_t counts)
{
float on_leds;
on_leds = (uint8_t)(counts * 0.134); /*0.134 is a dummy value*/
return on_leds;
}
using this program logic when counts value is on the threshold between two LEDs, the next led flickers
I think this is a bad user experience for my device and I want the LEDs, once lit, to stay stable in a small range of values.
QUESTION: How a solution to this problem could be implemented in my project?
Hysteresis is useful for a number of applications, but I would suggest not appropriate in this instance. The problem is that if the level genuinely falls from say 8 to 7 for example you would not see any change until at least one sample at 6 and it would jump to 6 and there would have to be a sample of 8 before it went back to 7.
A more appropriate solution in the case is a moving average, although it is simpler and more useful to use a moving sum and use the higher resolution that gives. For example a moving-sum of 16 effectively adds (almost) 4 bits of resolution, making a 8 bit sensor effectively 12 bit - at the cost of bandwidth of course; you don't get something for nothing. In this case lower bandwidth (i.e. less responsive to higher frequencies is exactly what you need)
Moving sum:
#define BUFFER_LEN 16 ;
#define SUM_MAX (255 * BUFFER_LEN)
#define LED_MAX 30
uint8_t buffer[BUFFER_LEN] = {0} ;
int index = 0 ;
uint16_t sum = 0 ;
for(;;)
{
uint8_t sample = Sensor_Read() ;
// Maintain sum of buffered values by
// subtracting oldest buffered value and
// adding the new sample
sum -= buffer[index] ;
sum += sample ;
// Replace oldest sample with new sample
// and increment index to next oldest sample
buffer[index] = sample ;
index = (index + 1) % BUFFER_LEN ;
// Transform to LED bar level
int led_level = (LED_MAX * sum) / SUM_MAX ;
// Show level
setLedBar( led_level ) ;
}
The underlying problem -- displaying sensor data in a human-friendly way -- is very interesting. Here's my approach in pseudocode:
Loop:
Read sensor
If sensor outside valid range:
Enable warning LED
Sleep in a low-power state for a while
Restart loop
Else:
Disable warning LED
Filter sensor value
Compute display value from sensor value with extra precision:
If new display value differs sufficiently from current value:
Update current displayed value
Update display with scaled-down display value
Filtering deals with noise in the measurements. Filtering smoothes out any sudden changes in the measurement, removing sudden spikes. It is like erosion, turning sharp and jagged mountains into rolling fells and hills.
Hysteresis hides small changes, but does not otherwise filter the results. Hysteresis won't affect noisy or jagged data, it only hides small changes.
Thus, the two are separate, but complementary methods, that affect the readout in different ways.
Below, I shall describe two different filters, and two variants of simple hysteresis implementation suitable for numeric and bar graph displays.
If possible, I'd recommend you write some scripts or test programs that output the input data and the variously filtered output data, and plot it in your favourite plotting program (mine is Gnuplot). Or, better yet, experiment! Nothing beats practical experiments for human interface stuff (at least if you use existing suggestions and known theory as your basis, and leap forward from there).
Moving average:
You create an array of N sensor readings, updating them in a round-robin fashion, and using their average as the current reading. This produces very nice (as in human-friendly, intuitive) results, as only the N latest sensor readings affect the average.
When the application is first started, you should copy the very first reading into all N entries in the averaging array. For example:
#define SENSOR_READINGS 32
int sensor_reading[SENSOR_READINGS];
int sensor_reading_index;
void sensor_init(const int reading)
{
int i;
for (i = 0; i < SENSOR_READINGS; i++)
sensor_reading[i] = reading;
sensor_reading_index = 0;
}
int sensor_update(const int reading)
{
int i, sum;
sensor_reading_index = (sensor_reading_index + 1) % SENSOR_READINGS;
sensor_reading[sensor_reading_index] = reading;
sum = sensor_reading[0];
for (i = 1; i < SENSOR_READINGS; i++)
sum += sensor_reading[i];
return sum / SENSOR_READINGS;
}
At start-up, you call sensor_init() with the very first valid sensor reading, and sensor_update() with the following sensor readings. The sensor_update() will return the filtered result.
The above works best when the sensor is regularly polled, and SENSOR_READINGS can be chosen large enough to properly filter out any unwanted noise in the sensor readings. Of course, the array requires RAM, which may be on short supply in some microcontrollers.
Exponential smoothing:
When there is not enough RAM to use a moving average to filter data, an exponential smoothing filter is often applied.
The idea is that we keep an average value, and recalculate the average using each new sensor reading using (A * average + B * reading) / (A + B). The effect of each sensor reading on the average decays exponentially: the weight of the most current sensor reading is always B/(A+B), the weight of the previous one is A*B/(A+B)^2, the weight of the one before that is A^2*B/(A+B)^3, and so on (^ indicating exponentiation); the weight of the n'th sensor reading in the past (with current one being n=0) is A^n*B/(A+B)^(n+1).
The code corresponding to the previous filter is now
#define SENSOR_AVERAGE_WEIGHT 31
#define SENSOR_CURRENT_WEIGHT 1
int sensor_reading;
void sensor_init(const int reading)
{
sensor_reading = reading;
}
int sensor_update(const int reading)
return sensor_reading = (sensor_reading * SENSOR_AVERAGE_WEIGHT +
reading * SENSOR_CURRENT_WEIGHT) /
(SENSOR_AVERAGE_WEIGHT + SENSOR_CURRENT_WEIGHT);
}
Note that if you choose the weights so that their sum is a power of two, most compilers optimize the division into a simple bit shift.
Applying hysteresis:
(This section, including example code, edited on 2016-12-22 for clarity.)
Proper hysteresis support involves having the displayed value in higher precision than is used for output. Otherwise, your output value with hysteresis applied will never change by a single unit, which I would consider a bad design in an user interface. (I'd much prefer a value to flicker between two consecutive values every few seconds, to be honest -- and that's what I see in e.g. the weather stations I like best with good temperature sensors.)
There are two typical variants in how hysteresis is applied to readouts: fixed, and dynamic. Fixed hysteresis means that the displayed value is updated whenever the value differs by a fixed limit; dynamic means the limits are set dynamically. (The dynamic hysteresis is much rarer, but it may be very useful when coupled with the moving average; one can use the standard deviation (or error bars) to set the hysteresis limits, or set asymmetric limits depending on whether the new value is smaller or greater than the previous one.)
The fixed hysteresis is very simple to implement. First, because we need to apply the hysteresis to a higher-precision value than the output, we choose a suitable multiplier. That is, display_value = value / DISPLAY_MULTIPLIER, where value is the possibly filtered sensor value, and display_value is the integer value displayed (number of bars lit, for example).
Note that below, display_value and the value returned by the functions, refer to the integer value displayed, for example the number of lit LED bars. value is the (possibly filtered) sensor reading, and saved_value containing the sensor reading that is currently displayed.
#define DISPLAY_HYSTERESIS 10
#define DISPLAY_MULTIPLIER 32
int saved_value;
void display_init(const int value)
{
saved_value = value;
}
int display_update(const int value)
{
const int delta = value - saved_value;
if (delta < -DISPLAY_HYSTERESIS ||
delta > DISPLAY_HYSTERESIS)
saved_value = value;
return saved_value / DISPLAY_MULTIPLIER;
}
The delta is just the difference between the new sensor value, and the sensor value corresponding to the currently displayed value.
The effective hysteresis, in units of displayed value, is DISPLAY_HYSTERESIS/DISPLAY_MULTIPLIER = 10/32 = 0.3125 here. It means that the displayed value can be updated three times before a visible change is seen (if e.g. slowly decreasing or increasing; more if the value is just fluctuating, of course). This eliminates rapid flickering between two visible values (when the value is in the middle of two displayed values), but ensures the error of the reading is less than half display units (on average; half plus effective hysteresis in the worst case).
In a real life application, you usually use a more complete form return (saved_value * DISPLAY_SCALE + DISPLAY_OFFSET) / DISPLAY_MULTIPLIER, which scales the filtered sensor value by DISPLAY_SCALE/DISPLAY_MULTIPLIER and moves the zero point by DISPLAY_OFFSET/DISPLAY_MULTIPLIER, both evaluated at 1.0/DISPLAY_MULTIPLIER precision, but only using integer operations. However, for simplicity, I'll just assume that to derive the display value value, say the number of lit LED bars, you just divide the sensor value by DISPLAY_MULTIPLIER. In either case, the hysteresis is DISPLAY_HYSTERESIS/DISPLAY_MULTIPLIER of the output unit. Ratios of about 0.1 to 0.5 work fine; and the below test values, 10 and 32, yields 0.3125, which is about midway of the range of ratios that I believe work best.
Dynamic hysteresis is very similar to above:
#define DISPLAY_MULTIPLIER 32
int saved_value_below;
int saved_value;
int saved_value_above;
void display_init(const int value, const int below, const int above)
{
saved_value_below = below;
saved_value = value;
saved_value_above = above;
}
int display_update(const int value, const int below, const int above)
{
if (value < saved_value - saved_value_below ||
value > saved_value + saved_value_above) {
saved_value_below = below;
saved_value = value;
saved_value_above = above;
}
return saved_value / DISPLAY_MULTIPLIER;
}
Note that if DISPLAY_HYSTERESIS*2 <= DISPLAY_MULTIPLIER, the displayed value is always within a display unit of the actual (filtered) sensor value. In other words, hysteresis can easily deal with flickering, but it does not need to add much error to the displayed value.
In many practical cases the best amount of hysteresis applied depends on the amount of short-term variations in the sensor samples. This includes not only noise, but also the types of signals that are to be measured. A hysteresis of just 0.3 (relative to the output unit) is sufficient to completely eliminate the flicker when sensor readings flip the filtered sensor value between two consecutive integers that map to different integer ouputs, as it ensures that the filtered sensor value must change by at least 0.3 (in output display units) before it effects a change in the display.
The maximum error with hysteresis is half display units plus the current hysteresis. The half unit is the minimum error possible (since consecutive units are one unit apart, so when the true value is in the middle, either value shown is correct to within half a unit). With dynamic hysteresis, if you always start with some fixed hysteresis value when a reading changes enough, but when the reading is within the hysteresis, you instead just decrease the hysteresis (if greater than zero). This approach leads to a changing sensor value being tracked correctly (maximum error being half an unit plus the initial hysteresis), but a relatively static value being displayed as accurately as possible (at half an unit maximum error). I don't show an example of this, because it adds another tunable (how the hysteresis decays towards zero), and requires that you verify (calibrate) the sensor (including any filtering) first; otherwise it's like polishing a turd: possible, but not useful.
Also note that if you have 30 bars in the display, you actually have 31 states (zero bars, one bar, .., 30 bars), and thus the proper range for the value is 0 to 31*DISPLAY_MULTIPLIER - 1, inclusive.

Integrating cos(x)/sqrt(x) between 0 and infinity to a user defined precision

So I'm trying to do what I've said above. The user will enter a precision, such as 3 decimal places, and then using the trapezium rule, the program will keep adding strips on until the 3rd decimal place is no longer changing, and then stop and print the answer.
I'm not sure of the best way to approach this. Due to the function being sinusoidal, one period of 2PI will almost be 0. I feel like this way would be the best way of approaching the problem, but no idea of how to go about it. At the moment I'm checking the y value for each x value to see when that becomes less than the required precision, however it never really goes lower enough. At x = 10 million, for example, y = -0.0002, which is still relatively large for such a large x value.
for (int i = 1; i < 1000000000; i++)
{
sumFirstAndLast += func(z);
z += stripSize;
count++;
printf("%lf\n", func(z));
if(fabs(func(z))<lowestAddition/stripSize){
break;
}
}
So this above is what I'm trying to do currently. Where func is the function. The stripSize is set to 0.01, just something relatively small to make the areas of the trapeziums more accurate. sumFirstAndLast is the sum of the first and last values, set at 0.001 and 1000000. Just a small value and a large value.
As I mentioned, I "think" the best way to do this, would be to check the value of the integral over every 2PI, but once again not sure how to go about this. My current method gives me the correct answer if I take the precision part out, but as soon as I try to put a precision in, it gives a completely wrong answer.
For a non-periodic function that converges to zero you can (sort of) do a check of the function's value and compare to a minimum error value, but this doesn't work for a periodic function as you get an early exit before the integrand sum converges (as you've found out). For a non-periodic function you can simply check the change in the integrand sum on each iteration to a minimum error but that won't work here either.
Instead, you'll have to do like a few comments suggest to check for convergence relative to the period of the function, PI in this case (I found it works better than using 2*PI). To implement this do something like the following code (note I changed your sum to be the actual area instead of doing it at the end):
sumFirstAndLast = (0.5*func(a) + 0.5*func(b)) * stripSize;
double z = a + stripSize;
double CHECK_RANGE = 3.14159265359;
double NextCheck = CHECK_RANGE;
double LastCheckSum = 0;
double MinError = 0.0001;
for (int i = 1; i < 1000000000; i++)
{
sumFirstAndLast += func(z) * stripSize;
if (z >= NextCheck)
{
if (fabs(LastCheckSum - sumFirstAndLast ) < MinError) break;
NextCheck += CheckRange;
LastCheckSum = sumFirstAndLast;
}
z += stripSize;
count++;
}
This seems to work and give the result to the specified accuracy according to the value of MinError. There are probably other (better) ways to check for convergence when numerically integrating a periodic function. A quick Google search reveals this paper for example.
The integral of from 0 to infinity of cos(x)/sqrt(x), or sin(x)/sqrt(x) is well known to be sqrt(pi/2). So evaluating pi to any number of digits is easier problem. Newton did it by integrating a quarter circle to get the area = pi/4. The integrals are evaluated by the methods of complex analysis. They are done in may text books on the subject, and on one of my final exams in graduate school.

Trying to brute force roots for a hermite polynomial

I've got a program that is supposed to find the roots for the **th hermite polynomial by using Newton's method, but it's taking a long time to run the program. I'm pretty new to C, so I can't figure out where my bug is or if this is just the nature of brute forcing this problem. I'm also having issues getting accurate roots, but so far, it's hard to find that bug because I can only run a test case every 5-10 minutes
CODE REMOVED
I'm 100% sure there's no good reason for Newton-Raphson to take so much time. In some cases it may be problematic, because this method isn't guaranteed to converge. But in your specific case - there should be no problem.
One thing that is clear is that you monstrously overuse recursion. Just calculating your hermite with n=37 is a recursion with complexity somewhat as summing 37 Fibonacci numbers, which is about 40 millions.
Now, think that your newton method should invoke the hermite repeatedly, as well as h_deriv (which is of the same order of magnitude of recursion), up until in converges up to 10^-12. Sounds like tens of interations.
And, not enough all this, you also manage to implement newton recursively! There is really no reason in the world to so this. (was lisp/scheme your first programming language?)
This is what you should do to improve the performance:
Fix your hermite. You should calculate the 37 coefficients, this may be done recursively. Once this is done - you should use them to calculate the the value of the polynomial in a normal time.
Same regarding the derivative. Just calculate the 36 coefficients.
Optionally fix your newton. As far as I can see - you'll not gain much of the performance: your "recursion" is an awkward loop nevertheless. However it'll look better, and consume much less stack.
Edit:
After reading the comments I took time and tried to build & run this. And, I must admit, I underestimated the problem complexity.
As turns out, the coefficients calculated by the recursive relation grow rapidly, and the round-off error seems to dominate. So that solving this problem by brute-force has unavoidable implications, and it's not obvious that using the pre-calculated coefficients (and summing them in the straight order) yields the same result.
Nevertheless there's a way to get rid of the ridiculous recursion without changing the calculation logic:
const int N = 37;
double g_pHermiteValues[N+1];
void CalcHermiteAt(double x)
{
double x2 = x*2;
g_pHermiteValues[0] = 1.;
g_pHermiteValues[1] = x2;
for (int n = 2; n <= N; n++)
g_pHermiteValues[n] =
g_pHermiteValues[n - 1] * x2 -
g_pHermiteValues[n - 2] * 2*(n - 1);
}
double CalcHermiteDerivAt()
{
return g_pHermiteValues[N - 1] * 2*N;
}
double newton(double x_0)
{
const double tolerance = 1E-12;
while (true)
{
CalcHermiteAt(x_0);
if (abs(g_pHermiteValues[N]) < tolerance)
return x_0;
x_0 -= g_pHermiteValues[N] / CalcHermiteDerivAt();
}
}
That is, we use the same recursive relation. It's just in order to calculate the value of the Hermite polynomial at a given point we calculate it for all the polynomials up to n=37 iteratively, and store the results in the global array. Then its top element holds the needed result, and the derivative is also deduced from the 2nd array element from the end.
Since in Newton-Raphson algorithm at each step we need both the value and the derivative at the same point - this is done effectively.
P.S. However so far I could not come to the solution. The Newton-Raphson just doesn't converge for the points I've tried to start from.
I believe for such a question a more robust method may be used, such as a median search.

Genetic Programming with the Mandelbrot Set

I'm reading a chapter in this fascinating book about using genetic programming to interactively evolve images. Most of the function set is comprised of simple arithmetic and trig functions (which really operation on and return images). These functions make up the internal nodes of the parse trees that encode our images. The leaves of the tree, or the terminal values, are random numbers and x,y coordinates.
There's a section about adding iterative functions of the complex plane to the function set:
Say the genetics inserts a particular Mandelbrot set as a node somewhere in
a bushy tree. The function expects two arguments: mandel(cReal, cImag), treating
them as real and imaginary coordinates in the complex plane. If the genome
just happened to supply the pixel coordinates (x,y), and mandel() were the root
node, you would get the familiar Mset. But chances are that cReal and cImag are themselves the results of whole branches of functions, with many instances of coordinates
x,y scattered out among the leaves. Enter the iteration loop, orbit
around for a while, and finally escape with some measure of distance to the Mset
attractor, such as the number of iterations.
My question is how would you make a Mandelbrot set renderer as a function that takes the real and imaginary coordinates of a point on the complex plane as arguments and returns a rendering of the Mandelbrot set?
I'm not sure if this actually answers your question, but my understanding of the text you quoted simply says that the mandel function is just another function (like multiplication, min, max, addition, etc) that can appear in your genetic program.
The mandel function, like the multiplication function, takes two arguments (in_1 and in_2) and returns a single value. Whereas the multiplication function just returns in_1 * in_2, the mandel function might do something like this:
int mandel(int in_1, int in_2) {
x = 0
y = 0
iteration = 0
max_iteration = 1000
while( x*x + y*y <= (2*2) && iteration < max_iteration ) {
xtemp = x*x - y*y + in_1
y = 2*x*y + in_2
x = xtemp
++iteration
}
if( iteration == max_iteration ) return 0
else return iteration
}
If your whole genetic program tree consists of nothing but the mandel function with one input as x and the other input as y, then repeatedly evaluating your program for a bunch of different (x,y) values and saving the result will give you a nice picture of the Mandelbrot set.
Of course, the neat thing about genetic programming is that the inputs can be fancier than just x and y. For example, what would the result look like if one input was x and the other input was x + 2*y? Or if one input was x and the other was mandel(x,y)?

Resources