Euler Method for system of differential equations - c++

I'm trying to recreate computation of a SIR model as described here, with extra midpoint calculations. But for some reason no values actually change during the Euler calculations.
#include <iostream>
using namespace std;
int main(){
double s[100];
double i[100];
double r[100];
double bb = 1/2;
double kk = 1/3;
s[0] = 1;
i[0] = 1.27e-6;
r[0] = 0;
int h = 1;
int max = 20;
for (int j = 0; j < max; j += h){
s[j + 1] = s[j] - h*(bb * s[j] * i[j]);
i[j + 1] = i[j] + h*(bb * s[j] * i[j] - kk * i[j]);
r[j + 1] = r[j] + h*(kk * i[j]);
cout << j << "\t" << s[j] << "\t" << i[j] << "\t" << r[j] << "\n";
/*
s[j + 1] = s[j] - 0.5*h*(bb * s[j] * i[j] + bb * s[j+1] * i[j+1]);
i[j + 1] = i[j] + 0.5*h*(bb * s[j] * i[j] - kk * i[j] + bb * s[j+1] * i[j+1] - kk * i[j+1]);
r[j + 1] = r[j] + 0.5*h*(kk * i[j] + kk * i[j+1]);
*/
}
}

Your variables bb and kk are both zero due to integer division. Always use double literals:
double bb = 1.0/2.0;
double kk = 1.0/3.0;

Related

Why does my function always return 0 instead of returning the values of a and b after each iteration?

I'm trying to implement the shooting method which is used to solve 2nd-order ordinary differential equations with boundary conditions in C++. The equation is d^2y/dx^2 = 2ydy/dx. The boundary conditions provided are at x = 0, u1 =0.5 and at x = 1, u1 =1. The step size for x is 0.25. The values of U1 and U2 are being solved simultaneously at each x/iteration. However, on printing the values of U1 and U2 I get 0 as the output.
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;
int i{0}, j{0};
double K1_one, K2_one, K3_one, K4_one, K_one;
double K1_two, K2_two, K3_two, K4_two, K_two;
double x[5] = {0, 0.25, 0.5, 0.75, 1};
double U1[5] = {0.5};
double U2[5] = {};
double G1{0}, G2{0}, G3{0};
double a{0}, b{0};
double f1(double u2)
{
return u2;
}
double f2(double u1, double u2)
{
return 2 * u1 * u2;
}
double RK4_f1(double U2[5])
{
K1_one = 0.25 * (f1(U2[i - 1]));
K2_one = 0.25 * (f1(U2[i - 1] + K1_one / 2));
K3_one = 0.25 * (f1(U2[i - 1] + K2_one / 2));
K4_one = 0.25 * (f1(U2[i - 1] + K3_one));
K_one = (K1_one + 2 * K2_one + 2 * K3_one + K4_one) / 6;
U1[i] = U1[i - 1] + K_one;
a = U1[i];
return a;
}
double RK4_f2(double U1[5], double U2[5])
{
K1_two = 0.25 * (f2(U1[i - 1], U2[i - 1]));
K2_two = 0.25 * (f2(U1[i - 1] + 0.25 / 2, U2[i - 1] + K1_two / 2));
K3_two = 0.25 * (f2(U1[i - 1] + 0.25 / 2, U2[i - 1] + K2_two / 2));
K4_two = 0.25 * (f2(U1[i - 1] + 0.25, U2[i - 1] + K3_two));
K_two = (K1_two + 2 * K2_two + 2 * K3_two + K4_two) / 6;
U2[i] = U2[i - 1] + K_two;
b = U2[i];
return b;
}
int main()
{
cout << "Enter your first random guess for u2" << endl;
cin >> G1;
U2[0] = G1;
cout << "\nu1[i]\tu2[i]\n"
<< endl;
for (int i = 1; i < 5; i++)
{
for (int j = 1; j <= 2; j++)
{
if (j == 1)
{
a = RK4_f1(U2);
}
else
{
b = RK4_f2(U1, U2);
}
}
cout << a << "\t" << b << endl;
}
cout << "Enter your second random guess for u2" << endl;
cin >> G2;
U2[0] = G2;
cout << "\nu1[i]\tu2[i]\n"
<< endl;
for (int i = 1; i < 5; i++)
{
for (int j = 1; j <= 2; j++)
{
if (j == 1)
{
a = RK4_f1(U2);
}
else
{
b = RK4_f2(U1, U2);
}
}
cout << a << "\t" << b << endl;
}
}

E0028 expression must have a constant value. I want to enter the n like a constant number. Thanks

Hello I have tried to entering n division number by a number or a constant.
Here is the code:
}
int main()
{
//The main problem in below
int n_temp;
std::cout << "Please enter the division number";
std::cin >> n_temp;
const unsigned int n = n_temp;
int const iter_n = 10;
double const dx = L / (n - 1);
double T[n];
double P[n], Q[n];
double kP, kE, kW, ke, kw, Sp, Sc;
double a[n], b[n], c[n], d[n];
T[0] = 300; T[n - 1] = 1000;
for (int i = 1; i < n - 1; i++) { T[i] = 500; }
std::cout << "T= ["; for (double T_i : T) { std::cout << T_i << ","; } std::cout << "]\n";
for (int iter = 0; iter < iter_n; iter++) {
a[0] = 1; b[0] = 0; c[0] = 0; d[0] = T[0];
a[n - 1] = 1; b[n - 1] = 0; c[n - 1] = 0; d[n - 1] = T[n - 1];
for (int i = 1; i < n - 1; i++) {
float x = i * dx;
Sp = Spv(T[i], x);
Sc = Scv(T[i], x);
kP = kv(T[i], x);
kE = kv(T[i + 1], x + dx);
kW = kv(T[i - 1], x - dx);
ke = 2 * kP * kE / (kP + kE);
kw = 2 * kP * kW / (kP + kW);
b[i] = ke / dx;
c[i] = kw / dx;
a[i] = b[i] + c[i] + Sp * dx;
d[i] = Sc * dx;
}
P[0] = 0;
Q[0] = d[0];
for (int i = 1; i < n; i++) {
P[i] = b[i] / (a[i] - c[i] * P[i - 1]);
Q[i] = (c[i] * Q[i - 1] + d[i]) / (a[i] - c[i] * P[i - 1]);
}
for (int i = n - 2; i > 0; i--) {
T[i] = P[i] * T[i + 1] + Q[i];
}
std::cout << "T =["; for (double T_i : T) { std::cout << T_i << ","; } std::cout << "]\n";
}
return 0;
}
Here is the revised version which is after reviewing comments. There are some errors that appear in the T. For example E2291,C3536, C2893, C2784, C2672,C2100 Thanks.
int main()
{
int n_temp;
std::cout << "Please enter the division number";
std::cin >> n_temp;
const unsigned int n = n_temp;
int const iter_n = 10;
double const dx = L / (n - 1);
double*T= new double[n];
double*P = new double[n];
double*Q= new double[n];
double kP, kE, kW, ke, kw, Sp, Sc;
double*a= new double[n];
double*b = new double[n];
double* c = new double[n];
double* d = new double[n];
T[0] = 300; T[n - 1] = 1000;
for (int i = 1; i < n - 1; i++) { T[i] = 500; }
std::cout << "T= ["; for (double T_i : T) { std::cout << T_i << ","; } std::cout << "]\n";
for (int iter = 0; iter < iter_n; iter++) {
a[0] = 1; b[0] = 0; c[0] = 0; d[0] = T[0];
a[n - 1] = 1; b[n - 1] = 0; c[n - 1] = 0; d[n - 1] = T[n - 1];
for (int i = 1; i < n - 1; i++) {
float x = i * dx;
Sp = Spv(T[i], x);
Sc = Scv(T[i], x);
kP = kv(T[i], x);
kE = kv(T[i + 1], x + dx);
kW = kv(T[i - 1], x - dx);
ke = 2 * kP * kE / (kP + kE);
kw = 2 * kP * kW / (kP + kW);
b[i] = ke / dx;
c[i] = kw / dx;
a[i] = b[i] + c[i] + Sp * dx;
d[i] = Sc * dx;
}
P[0] = 0;
Q[0] = d[0];
for (int i = 1; i < n; i++) {
P[i] = b[i] / (a[i] - c[i] * P[i - 1]);
Q[i] = (c[i] * Q[i - 1] + d[i]) / (a[i] - c[i] * P[i - 1]);
}
for (int i = n - 2; i > 0; i--) {
T[i] = P[i] * T[i + 1] + Q[i];
}
std::cout << "T =["; for (double T_i : T) { std::cout << T_i << ","; } std::cout << "]\n";
delete[]T;
}
return 0;
}

C++ manually-unrolled (conditional-sum) is slower than regular code, was expecting AVX vectorization

test_euclid_ask.h (only need to read 2 functions: euclid_slow, euclid_fast)
#pragma once
#include "included.h"
double
euclid_slow(int n, double* data1, double* data2, int* mask1, int* mask2, const double weight[])
{
double result = 0.0;
double totalWeight = 0;
for (int i = 0; i < n; i++) {
if (mask1[i] && mask2[i]) {
double term = data1[i] - data2[i];
result += weight[i] * term * term;
totalWeight += weight[i];
}
}
if (totalWeight==0) return 0;
return result / totalWeight;
}
double
euclid_fast(int n, double* data1, double* data2, int* mask1, int* mask2, const double weight[])
{
double result = 0.0;
double totalWeight = 0;
double subResult[4] = { 0. };
double subTweight[4] = { 0. };
double subDiff[4] = { 0. };
double subWeight[4] = { 0. };
double subMask[4] = { 0. };
int nstep4 = n - n % 4;
for (int i = 0; i < nstep4; i += 4) {
subMask[0] = mask1[i] && mask2[i];
subMask[1] = mask1[i + 1] && mask2[i + 1];
subMask[2] = mask1[i + 2] && mask2[i + 2];
subMask[3] = mask1[i + 3] && mask2[i + 3];
if (!(subMask[0] || subMask[1] || subMask[2] || subMask[3])) continue;
subDiff[0] = data1[i] - data2[i];
subDiff[1] = data1[i + 1] - data2[i + 1];
subDiff[2] = data1[i + 2] - data2[i + 2];
subDiff[3] = data1[i + 3] - data2[i + 3];
subDiff[0] *= subDiff[0];
subDiff[1] *= subDiff[1];
subDiff[2] *= subDiff[2];
subDiff[3] *= subDiff[3];
subWeight[0] = weight[i] * subMask[0];
subWeight[1] = weight[i + 1] * subMask[1];
subWeight[2] = weight[i + 2] * subMask[2];
subWeight[3] = weight[i + 3] * subMask[3];
subTweight[0] += subWeight[0];
subTweight[1] += subWeight[1];
subTweight[2] += subWeight[2];
subTweight[3] += subWeight[3];
subResult[0] += subWeight[0] * subDiff[0];
subResult[1] += subWeight[1] * subDiff[1];
subResult[2] += subWeight[2] * subDiff[2];
subResult[3] += subWeight[3] * subDiff[3];
}
for (int i = nstep4; i < n; i++) {
if (mask1[i] && mask2[i]) {
double term = data1[i] - data2[i];
result += weight[i] * term * term;
totalWeight += weight[i];
}
}
result += subResult[0] + subResult[1] + subResult[2] + subResult[3];
totalWeight += subTweight[0] + subTweight[1] + subTweight[2] + subTweight[3];
//cout << "end fast\n";
if (!totalWeight) return 0;
return result / totalWeight;
}
void test_euclid_ask()
{
const int MAXN = 10000000, MINN = 1000000;
double* data1, * data2;
int* mask1, * mask2;
double* dataPro1, * dataPro2;
int* maskPro1, * maskPro2;
double *weight, * weightPro;
//***********
data1 = new double[MAXN + MINN + 1];
data2 = new double[MAXN + MINN + 1];
mask1 = new int[MAXN + MINN + 1];
mask2 = new int[MAXN + MINN + 1];
dataPro1 = new double[MAXN + MINN + 1];
dataPro2 = new double[MAXN + MINN + 1];
maskPro1 = new int[MAXN + MINN + 1];
maskPro2 = new int[MAXN + MINN + 1];
// ******
weight = new double[MAXN + MINN + 1];
weightPro = new double[MAXN + MINN + 1];
MyTimer timer;
int n;
double guess1, guess2, tmp, total1 = 0, total2 = 0, prev1 = 0, prev2 = 0;
for (int t = 5000; t < 6000; t++) {
if (t <= 5000) n = t;
else n = MINN + rand() % (MAXN - MINN);
cout << n << "\n";
int index = 0;
for (int i = 0; i < n; i++) {
weight[i] = int64(randomed()) % 100;
data1[i] = int64(randomed()) % 100;
data2[i] = int64(randomed()) % 100;
mask1[i] = rand() % 10;
mask2[i] = rand() % 10;
}
memcpy(weightPro, weight, n * sizeof(double));
memcpy(dataPro1, data1, n * sizeof(double));
memcpy(dataPro2, data2, n * sizeof(double));
memcpy(maskPro1, mask1, n * sizeof(int));
memcpy(maskPro2, mask2, n * sizeof(int));
//****
int tmp = flush_cache(); // do something to ensure the cache does not contain test data
cout << "ignore this " << tmp << "\n";
timer.startCounter();
guess1 = euclid_slow(n, data1, data2, mask1, mask2, weight);
tmp = timer.getCounterMicro();
total1 += tmp;
cout << "time slow = " << tmp << " us\n";
timer.startCounter();
guess2 = euclid_fast(n, dataPro1, dataPro2, maskPro1, maskPro2, weightPro);
tmp = timer.getCounterMicro();
total2 += tmp;
cout << "time fast = " << tmp << " us\n";
bool ok = fabs(guess1 - guess2) <= 0.1;
if (!ok) {
cout << "error at N = " << n << "\n";
exit(-1);
}
cout << "\n";
}
cout << "slow speed = " << (total1 / 1000) << " ms\n";
cout << "fast speed = " << (total2 / 1000) << " ms\n";
}
Basically, the function computes a kind-of Euclidean distance between 2 arrays:
result = sum(weight[i] * (data1[i] - data2[i])^2)
but only in positions where both values are available (mask1[i]==0 means it's ignored, same with mask2). The normal code is in function euclid_slow.
So I tried to improve the code by processing 4 elements at once, hoping that SSE/AVX can speed this up. However, the result stays the same or slower(using g++ -O3 -march=native) or becomes 40% slower (using Visual Studio 2019 compiler, release mode (x64), -O2, AVX2 enabled). I tried both -O2 and -O3, same result.
The compiler made better optimizations than what I wrote. But how can I make it actually faster?
Edit: code to test the programs here

3x3 array mutiplication in c++

I'm not sure what I went wrong, my code doesn't seem to work with anything else beside single integer. Am trying to get 3x3 array and find its determinant and work out its inverse function and then do the multiplication to get I.
//matrix product
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
for (k = 0; k < 3; k++) {
product[i][j] += array[i][k] * invertA[k][j];
}
}
}
... Below is the array from user input
int main() {
int array[3][3], invertA[3][3], product[3][3], i, j, k; // The global scope
// ask for input
printf("Please enter 9 elements of the matrix seperated by a space: \n");
for (i = 0; i < 3; i++) { //the loop - create a table of 3 x 3
for (j = 0; j < 3; j++) {
scanf("%d", &array[i][j]); //save user-input as integer (%d) into the matrix a[i][j]
}
}
and the other array is from code
//a11 a12 a13
invertA[0][0] = (array[1][1] * array[2][2] - array[2][1] * array[1][2]) / determinant;
invertA[0][1] = -(array[1][0] * array[2][2] - array[1][2] * array[2][0]) / determinant;
invertA[0][2] = (array[1][0] * array[2][1] - array[2][0] * array[1][1]) / determinant;
//a21 a22 a23
invertA[1][0] = -(array[0][1] * array[2][2] - array[0][2] * array[2][1]) / determinant;
invertA[1][1] = (array[0][0] * array[2][2] - array[0][2] * array[2][0]) / determinant;
invertA[1][2] = -(array[0][0] * array[2][1] - array[2][0] * array[0][1]) / determinant;
//a31 a32 a33
invertA[2][0] = (array[0][1] * array[1][2] - array[0][2] * array[1][1]) / determinant;
invertA[2][1] = -(array[0][0] * array[1][2] - array[1][0] * array[0][2]) / determinant;
invertA[2][2] = (array[0][0] * array[1][1] - array[1][0] * array[0][1]) / determinant;

if statement runtime error

I originally had 3 equations: Pu, Pm & Pd. It ran fine.
Once I introduced the if statement, with variations on the 3 equations, depending on the loop iteration, I receive a runtime error.
Any help would be appreciated.
Cheers in advance.
#include <cmath>
#include <iostream>
#include <vector>
#include <iomanip>
int Rounding(double x)
{
int Integer = (int)x;
double Decimal = x - Integer;
if (Decimal > 0.49)
{
return (Integer + 1);
}
else
{
return Integer;
}
}
int main()
{
double a = 0.1;
double sigma = 0.01;
int delta_t = 1;
double M = -a * delta_t;
double V = sigma * sigma * delta_t;
double delta_r = sqrt(3 * V);
int count;
double PuValue;
double PmValue;
double PdValue;
int j_max;
int j_min;
j_max = Rounding(-0.184 / M);
j_min = -j_max;
std::vector<std::vector<double>> Pu((20), std::vector<double>(20));
std::vector<std::vector<double>> Pm((20), std::vector<double>(20));
std::vector<std::vector<double>> Pd((20), std::vector<double>(20));
std::cout << std::setprecision(10);
for (int i = 0; i <= 2; i++)
{
count = 0;
for (int j = i; j >= -i; j--)
{
count = count + 1;
if (j = j_max) // Exhibit 1C
{
PuValue = 7.0/6.0 + (j * j * M * M + 3 * j * M)/2.0;
PmValue = -1.0/3.0 - j * j * M * M - 2 * j * M;
PdValue = 1.0/6.0 + (j * j * M * M + j * M)/2.0;
}
else if (j = j_min) // Exhibit 1B
{
PuValue = 1.0/6.0 + (j * j * M * M - j * M)/2.0;
PmValue = -1.0/3.0 - j * j * M * M + 2 * j * M;
PdValue = 7.0/6.0 + (j * j * M * M - 3 * j * M)/2.0;
}
else
{
PuValue = 1.0/6.0 + (j * j * M * M + j * M)/2.0;
PmValue = 2.0/3.0 - j * j * M * M;
PdValue = 1.0/6.0 + (j * j * M * M - j * M)/2.0;
}
Pu[count][i] = PuValue;
Pm[count][i] = PmValue;
Pd[count][i] = PdValue;
std::cout << Pu[count][i] << ", ";
}
std::cout << std::endl;
}
return 0;
}
You are assigning instead of checking for equal: j_max to j in your if statements.
if (j = j_max)
// ^
else if (j = j_min)
// ^
Change if (j = j_max) to if (j == j_max),
And else if (j = j_min) to else if (j == j_min).
Correct the following if conditional check and all other instances of an if check
if(j=j_max)
with
if (j == j_max)
you are checking for an equality not assigning.
Your code was going into an infinite loop.