Search code examples
c++mathdifferential-equationsrunge-kutta

C++: Simple Fourth Order Runge-Kutta calculator


Im making a calculator to solve a few fourth order Runge-Kutta equations we were doing in class, and while I was able to get the calculator to work and run, the values it gives me are not quite right and I cannot figure out why.

#include <iostream>                                                                                 
#include <cmath>                                                                                    
#include <iomanip>                                                                                  
#include <cctype>                                                                                   
#include <string>                                                                                   
#include <windows.h>                                                                                
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <sstream>                                                                                  
#include <vector>                                                                                   
#include <numeric>                                                                                  
#include <algorithm>                                                                                
using namespace std;                                                                                
double PI = acos(-1.0);                                                                             
long double Ks(int,int,long double,long double,long double,long double,long double);

int main ()                                                                                         
{
    char answer;
    do                                                                                              
    int Ans,PoN;
    long double X,Y,A,B,h,Fin,K;
    cout << "Please enter X and Y used for problem [X Y]: ";
    cin >> X >> Y; 
    cout << "What is the step size? ";
    cin >> h;
    cout << "What are we approximating to? Y(T) where T = ";
    cin >> Fin;
    cout << "Which equation form are you using (Please use number)?" << endl;
    cout << "1) Ax (+/-) By" << endl;
    cout << "2) Ax (+/-) By^2" << endl;
    cout << "3) Ay (+/-) By^2" << endl;
    cout << "Answer: ";
    cin >> Ans;
    cout << "You picked: ";
    switch(Ans)
    {
        case 1:
            cout << "Ax (+/-) By" << endl;
            cout << "Enter A: ";
            cin >> A;
            cout << "Is the sign in the middle positive(1) or negative(2)? ";
            cin >> PoN;
            cout << "Enter B: ";
            cin >> B;
            break;
        case 2:
            cout << "Ax (+/-) By^2" << endl;
            cout << "Enter A: ";
            cin >> A;
            cout << "Is the sign in the middle positive(1) or negative(2)? ";
            cin >> PoN;
            cout << "Enter B: ";
            cin >> B;
            break;
        case 3:
            cout << "Ay (+/-) By^2" << endl;
            cout << "Enter A: ";
            cin >> A;
            cout << "Is the sign in the middle positive(1) or negative(2)? ";
            cin >> PoN;
            cout << "Enter B: ";
            cin >> B;
            break;
    }
    //cout << fixed << setprecision(8);
    cout << " Y[#] |  New Y  | Exact" << endl;
    cout << "------|---------|------" << endl;
    for(long double i = X+h; i <= Fin; i += h)
    {   
        K = Ks(PoN,Ans,A,B,X,Y,h);
        Y = Y + (h/6)*K;
        cout << setw(2) << "Y[" << setw(3) << i << setw(1) << "]" << "|" << Y << endl;
    }



    cout << "Would you like to repeat this program?(Y/N) ";                                     
    cin >> answer;                                                                          
}
while (answer == 'y' || answer == 'Y');                                                         
if (answer == 'N' || answer == 'n')                                                             
{
cout << "Goodbye" << endl;                                                                      
system("start notepad.exe");                                                                    
}
system("pause");                                                                                    
return 0;
}
long double Ks(int PoN, int Ans, long double A,long double B,long double X,long double Y,long double h)
{
long double K1=0,K2=0,K3=0,K4=0,K=0;
switch(Ans)
{
    case 1:
    {   
        switch(PoN)
        {
            case 1: //Ax + By
                K1 = A*X+B*Y;
                K2 = A*(X+((1.0/2)*h)) + B*(Y+(1.0/2)*h*K1);
                K3 = A*(X+((1.0/2)*h)) + B*(Y+(1.0/2)*h*K2);
                K4 = A*(X+h) + B*(Y+h*K3);
                break;
            case 2: //Ax - By
                K1 = (A*X)-(B*Y);
                K2 = A*(X+((1.0/2)*h)) - B*(Y+(1.0/2)*h*K1);
                K3 = A*(X+((1.0/2)*h)) - B*(Y+(1.0/2)*h*K2);
                K4 = A*(X+h) - B*(Y+h*K3);
                //cout << K1 << " " << K2 << " " << K3 << " " << K4 << endl;
                break;
        }
    break;
    }
    case 2:
    {
        switch(PoN)
        {
            case 1: // Ax + By^2
                K1 = A*X+pow(B*Y,2);
                K2 = A*(X+((1.0/2)*h)) + pow(B*(Y+(1.0/2)*h*K1),2);
                K3 = A*(X+((1.0/2)*h)) + pow(B*(Y+(1.0/2)*h*K2),2);
                K4 = A*(X+h) + pow(B*(Y+h*K3),2);
                break;
            case 2: // Ax - By^2
                K1 = A*X - pow(B*Y,2);
                K2 = A*(X+((1.0/2)*h)) - pow(B*(Y+(1.0/2)*h*K1),2);
                K3 = A*(X+((1.0/2)*h)) - pow(B*(Y+(1.0/2)*h*K2),2);
                K4 = A*(X+h) - pow(B*(Y+h*K3),2);
                break;
        }
    break;
    }

    case 3:
    {   
        switch(PoN)
        {
            case 1: //Ay + By^2
                K1 = A*X+B*Y;
                K2 = A*(Y+((1.0/2)*h)) + B*(Y+(1.0/2)*h*K1);
                K3 = A*(Y+((1.0/2)*h)) + B*(Y+(1.0/2)*h*K2);
                K4 = A*(Y+h) + B*(Y+h*K3);
                break;
            case 2: //Ay - By^2
                K1 = A*X-B*Y;
                K2 = A*(Y+((1.0/2)*h)) - B*(Y+(1.0/2)*h*K1);
                K3 = A*(Y+((1.0/2)*h)) - B*(Y+(1.0/2)*h*K2);
                K4 = A*(Y+h) - B*(Y+h*K3);
                break;
        }
    break;
    }
}
K = (K1 + 2.0*K2 + 2.0*K3 + K4);
return K;
}

Now to test it I used this problem:

Where h is the step size, since it makes a new Y value for every iteration, one mistake causes the answer to snowball after the first iteration. I thought it might not be calculating enough points after the decimal but as you can see I used long doubles to no avail. Using the setprecision command does not work it just adds however many zeroes on the end to technically satisfy the command. enter image description here

In this picture I have a Runge-Kutta calculator I found on the left in white and my own program running on the left. As you can see the first iteration is correct but after that they get more and more wrong.


Solution

  • With each iteration of the method, you update your Y approximation, but not the X. Try replacing

    K = Ks(PoN,Ans,A,B,X,Y,h);
    

    with

    K = Ks(PoN,Ans,A,B,i-h,Y,h);
    

    (i.e. change X to i-h). You might also want to consider more meaningful names for your variables and dividing your functions into smaller pieces. Both of these could make something like this easier to spot.