Stinson Exercise 5.6 Galois Field

/*
Author:  Pate Williams (c) 1997

Exercise
"5.6 The field GF(2 ^ 5) can be constructed as
Z_2[x]/(x ^ 5 + x ^ 2 + 1). Perform the following
computations in this field.
(a) Compute (x ^ 4 + x ^ 2) * (x ^ 3 + x + 1).
(b) Using the Extended Euclidean algorithm
compute (x ^ 3 + x ^ 2) ^ - 1.
(c) Using the square and multiply algorithm,
compute x ^ 25." -Douglas R. Stinson-
See "Cryptography: Theory and Practice" by
Douglas R. Stinson page 201.
*/

#include <math.h>
#include <stdio.h>

#define SIZE 32l

void poly_mul(long m, long n, long *a, long *b, long *c, long *p)
{
	long ai, bj, i, j, k, sum;

	*p = m + n;
	for (k = 0; k <= *p; k++) {
		sum = 0;
		for (i = 0; i <= k; i++) {
			j = k - i;
			if (i > m) ai = 0; else ai = a[i];
			if (j > n) bj = 0; else bj = b[j];
			sum += ai * bj;
		}
		c[k] = sum;
	}
}

void poly_div(long m, long n, long *u, long *v,
	long *q, long *r, long *p, long *s)
{
	long j, jk, k, nk, vn = v[n];

	for (j = 0; j <= m; j++) r[j] = u[j];
	if (m < n) {
		*p = 0, *s = m;
		q[0] = 0;
	}
	else {
		*p = m - n, *s = n - 1;
		for (k = *p; k >= 0; k--) {
			nk = n + k;
			q[k] = r[nk] * pow(vn, k);
			for (j = nk - 1; j >= 0; j--) {
				jk = j - k;
				if (jk >= 0)
					r[j] = vn * r[j] - r[nk] * v[j - k];
				else
					r[j] = vn * r[j];
			}
		}
		while (*p > 0 && q[*p] == 0) *p = *p - 1;
		while (*s > 0 && r[*s] == 0) *s = *s - 1;
	}
}

void poly_exp_mod(long degreeA, long degreem, long n,
	long modulus, long *A, long *m, long *s,
	long *ds)
{
	int zero;
	long dp, dq, dx = degreeA, i;
	long p[SIZE], q[SIZE], x[SIZE];

	*ds = 0, s[0] = 1;
	for (i = 0; i <= dx; i++) x[i] = A[i];
	while (n > 0) {
		if ((n & 1) == 1) {
			/* s = (s * x) % m; */
			poly_mul(*ds, dx, s, x, p, &dp);
			poly_div(dp, degreem, p, m, q, s, &dq, ds);
			for (i = 0; i <= *ds; i++) s[i] %= modulus;
			zero = s[*ds] == 0, i = *ds;
			while (i > 0 && zero) {
				if (zero) *ds = *ds - 1;
				zero = s[--i] == 0;
			}
		}
		n >>= 1;
		/* x = (x * x) % m; */
		poly_mul(dx, dx, x, x, p, &dp);
		poly_div(dp, degreem, p, m, q, x, &dq, &dx);
		for (i = 0; i <= dx; i++) x[i] %= modulus;
		zero = x[dx] == 0, i = dx;
		while (i > 0 && zero) {
			if (zero) dx--;
			zero = x[--i] == 0;
		}
	}
}

void poly_copy(long db, long *a, long *b, long *da)
/* a = b */
{
	long i;

	*da = db;
	for (i = 0; i <= db; i++) a[i] = b[i];
}

int poly_Extended_Euclidean(long db, long dn,
	long *b, long *n,
	long *t, long *dt)
{
	int nonzero;
	long db0, dn0, dq, dr, dt0 = 0, dtemp, du, i;
	long b0[SIZE], n0[SIZE], q[SIZE];
	long r[SIZE], t0[SIZE], temp[SIZE], u[SIZE];

	*dt = 0;
	poly_copy(dn, n0, n, &dn0);
	poly_copy(db, b0, b, &db0);
	t0[0] = 0;
	t[0] = 1;
	poly_div(dn0, db0, n0, b0, q, r, &dq, &dr);
	nonzero = r[0] != 0;
	for (i = 1; !nonzero && i <= dr; i++)
		nonzero = r[i] != 0;
	while (nonzero) {
		poly_mul(dq, *dt, q, t, u, &du);
		if (dt0 < du)
			for (i = dt0 + 1; i <= du; i++) t0[i] = 0;
		for (i = 0; i <= du; i++)
			temp[i] = t0[i] - u[i];
		dtemp = du;
		poly_copy(*dt, t0, t, &dt0);
		poly_copy(dtemp, t, temp, dt);
		poly_copy(db0, n0, b0, &dn0);
		poly_copy(dr, b0, r, &db0);
		poly_div(dn0, db0, n0, b0, q, r, &dq, &dr);
		nonzero = r[0] != 0;
		for (i = 1; !nonzero && i <= dr; i++)
			nonzero = r[i] != 0;
	}
	if (db0 != 0 && b0[0] != 1) return 0;
	return 1;
}

void poly_mod(long da, long p, long *a, long *new_da)
{
	int zero;
	long i;

	for (i = 0; i <= da; i++) {
		a[i] %= p;
		if (a[i] < 0) a[i] += p;
	}
	zero = a[da] == 0;
	for (i = da - 1; zero && i >= 0; i--) {
		da--;
		zero = a[i] == 0;
	}
	*new_da = da;
}

void poly_write(char *label, long da, long *a)
{
	long i;

	printf("%s", label);
	for (i = da; i >= 0; i--)
		printf("%ld ", a[i]);
	printf("\n");
}

int main(void)
{
	long da = 4, db = 3, dc = 3, dd = 5;
	long de, dq, dr, ds, p = 2;
	long a[5] = { 0, 0, 1, 0, 1 };
	long b[4] = { 1, 1, 0, 1 };
	long c[4] = { 0, 0, 1, 1 };
	long d[6] = { 1, 0, 1, 0, 0, 1 };
	long e[SIZE], q[SIZE], r[SIZE], s[SIZE];

	poly_write("A = ", da, a);
	poly_write("B = ", db, b);
	poly_write("C = ", dc, c);
	poly_write("D = ", dd, d);
	poly_mul(da, db, a, b, e, &de);
	poly_mod(de, p, e, &de);
	poly_div(de, dd, e, d, q, r, &dq, &dr);
	poly_mod(dq, p, q, &dq);
	poly_mod(dr, p, r, &dr);
	poly_write("A * B mod 2 = ", de, e);
	poly_write("A * B / D mod 2 = ", dq, q);
	poly_write("A * B mod D, 2  = ", dr, r);
	if (!poly_Extended_Euclidean(dc, dd, c, d, e, &de))
		printf("*error*\in poly_Extended_Euclidean\n");
	poly_mod(de, p, e, &de);
	poly_write("C ^ - 1 mod D = ", de, e);
	poly_mul(dc, de, c, e, s, &ds);
	poly_mod(ds, p, s, &ds);
	poly_div(ds, dd, s, d, q, r, &dq, &dr);
	poly_mod(dr, p, r, &dr);
	poly_write("C * C ^ - 1 mod D, 2 = ", dr, r);
	dq = 1;
	q[0] = 0;
	q[1] = 1;
	poly_exp_mod(dq, dd, 7, p, q, d, s, &ds);
	poly_mod(ds, p, s, &ds);
	poly_write("x ^  7 mod D, 2 = ", ds, s);
	poly_exp_mod(dq, dd, 9, p, q, d, s, &ds);
	poly_mod(ds, p, s, &ds);
	poly_write("x ^  9 mod D, 2 = ", ds, s);
	poly_exp_mod(dq, dd, 10, p, q, d, s, &ds);
	poly_mod(ds, p, s, &ds);
	poly_write("x ^ 10 mod D, 2 = ", ds, s);
	poly_exp_mod(dq, dd, 25, p, q, d, s, &ds);
	poly_mod(ds, p, s, &ds);
	poly_write("x ^ 25 mod D, 2 = ", ds, s);
	return 0;
}

More Elliptic Curve Point Counting Results Using the Shanks-Mestre Algorithm by James Pate Williams, Jr.

As can be seen the C++ application appears to be much faster than the C# application. Also, in my humble opinion, C++ with header files and C++ source code files is much more elegant than C# with only class source code. I leave it to someone else to add C# interfaces to my class source code files.

Elliptic Curve Point Counting Using the Shanks-Mestre Algorithm in C# and C++ by James Pate Williams, Jr.

A few years ago, I implemented the Shanks-Mestre elliptic curve point counting algorithm in C# using the BigInteger data structure and the algorithm found in Henri Cohen’s textbook A Course in Computational Algebraic Number Theory. I translated the C# application to C++ in August 21-22, 2023. The C++ code uses the long long 64-bit signed integer data type. Below are some results. I also implemented Schoof’s point counting algorithm in C#.

Artificial Neural Network Learns the Exclusive OR (XOR) Function by James Pate Williams, Jr.

The exclusive or (XOR) function is a very well known simple two input binary function in the world of computer architecture. The truth table has four rows with two input columns 00, 01, 10, and 11. The output column is 0, 1, 1, 0. In other words, the XOR function is false for like inputs and true for unlike inputs. This function is also known in the world of cryptography and is the encryption and decryption function for the stream cipher called the onetime pad. The onetime pad is perfectly secure as long as none of the pad is resused. The original artificial feedforward neural network was unable to correctly generate the outputs of the XOR function. This disadvantage was overcome by the addition of back-propagation to the artificial neural network. The outputs must be adjusted to 0.1 and 0.9 for the logistic also known as the sigmoid activation function to work.

using System;
using System.Windows.Forms;

namespace BPNNTestOne
{
    public class BPNeuralNetwork
    {
        private static double RANGE = 0.1;
        private double learningRate, momentum, tolerance;
        private double[] deltaHidden, deltaOutput, h, o, p;
        private double[,] newV, newW, oldV, oldW, v, w, O, T, X;
        private int numberHiddenUnits, numberInputUnits;
        private int numberOutputUnits, numberTrainingExamples;
        private int maxEpoch;

        private Random random;
        private TextBox tb;

        public double[] P
        {
            get
            {
                return p;
            }
        }

        double random_range(double x_0, double x_1)
        {
            double temp;

            if (x_0 > x_1)
            {
                temp = x_0;
                x_0 = x_1;
                x_1 = temp;
            }

            return (x_1 - x_0) * random.NextDouble() + x_0;
        }

        public BPNeuralNetwork
            (
            double alpha,
            double eta,
            double threshold,
            int nHidden,
            int nInput,
            int nOutput,
            int nTraining,
            int nMaxEpoch,
            int seed,
            TextBox tbox
            )
        {
            int i, j, k;

            random = new Random(seed);

            learningRate = eta;
            momentum = alpha;
            tolerance = threshold;
            numberHiddenUnits = nHidden;
            numberInputUnits = nInput;
            numberOutputUnits = nOutput;
            numberTrainingExamples = nTraining;
            maxEpoch = nMaxEpoch;
            tb = tbox;

            h = new double[numberHiddenUnits + 1];
            o = new double[numberOutputUnits + 1];
            p = new double[numberOutputUnits + 1];

            h[0] = 1.0;

            deltaHidden = new double[numberHiddenUnits + 1];
            deltaOutput = new double[numberOutputUnits + 1];

            newV = new double[numberHiddenUnits + 1, numberOutputUnits + 1];
            oldV = new double[numberHiddenUnits + 1, numberOutputUnits + 1];
            v = new double[numberHiddenUnits + 1, numberOutputUnits + 1];

            newW = new double[numberInputUnits + 1, numberHiddenUnits + 1];
            oldW = new double[numberInputUnits + 1, numberHiddenUnits + 1];
            w = new double[numberInputUnits + 1, numberHiddenUnits + 1];


            for (j = 0; j <= numberHiddenUnits; j++)
            {
                for (k = 1; k <= numberOutputUnits; k++)
                {
                    oldV[j, k] = random_range(-RANGE, +RANGE);
                    v[j, k] = random_range(-RANGE, +RANGE);
                }
            }

            for (i = 0; i <= numberInputUnits; i++)
            {
                for (j = 0; j <= numberHiddenUnits; j++)
                {
                    oldW[i, j] = random_range(-RANGE, +RANGE);
                    w[i, j] = random_range(-RANGE, +RANGE);
                }
            }

            O = new double[numberTrainingExamples + 1, numberOutputUnits + 1];
            T = new double[numberTrainingExamples + 1, numberInputUnits + 1];
            X = new double[numberTrainingExamples + 1, numberInputUnits + 1];
        }

        public void SetTrainingExample(double[] t, double[] x, int d)
        {
            int i, k;

            for (i = 0; i <= numberInputUnits; i++)
                X[d, i] = x[i];

            for (k = 0; k <= numberOutputUnits; k++)
                T[d, k] = t[k];
        }

        private double f(double x)
        // squashing function = a sigmoid function
        {
            return 1.0 / (1.0 + Math.Exp(-x));
        }

        private double g(double x)
        // derivative of the squashing function
        {
            return f(x) * (1.0 - f(x));
        }

        public void ForwardPass(double[] x)
        {
            double sum;
            int i, j, k;

            for (j = 1; j <= numberHiddenUnits; j++)
            {
                for (i = 0, sum = 0; i <= numberInputUnits; i++)
                    sum += x[i] * w[i, j];

                h[j] = sum;
            }

            for (k = 1; k <= numberOutputUnits; k++)
            {
                for (j = 1, sum = h[0] * v[0, k]; j <= numberHiddenUnits; j++)
                    sum += f(h[j]) * v[j, k];

                o[k] = sum;
                p[k] = f(o[k]);
            }
        }

        private void BackwardPass(double[] t, double[] x)
        {
            double sum;
            int i, j, k;

            for (k = 1; k <= numberOutputUnits; k++)
                deltaOutput[k] = (p[k] * (1 - p[k])) * (t[k] - p[k]);

            for (k = 1; k <= numberOutputUnits; k++)
            {
                newV[0, k] = learningRate * h[0] * deltaOutput[k];

                for (j = 1; j <= numberHiddenUnits; j++)
                    newV[j, k] = learningRate * f(h[j]) * deltaOutput[k];

                for (j = 0; j <= numberHiddenUnits; j++)
                {
                    v[j, k] += newV[j, k] + momentum * oldV[j, k];
                    oldV[j, k] = newV[j, k];
                }
            }

            for (j = 1; j <= numberHiddenUnits; j++)
            {
                for (k = 1, sum = 0; k <= numberOutputUnits; k++)
                    sum += v[j, k] * deltaOutput[k];

                deltaHidden[j] = g(h[j]) * sum;

                for (i = 0; i <= numberInputUnits; i++)
                {
                    newW[i, j] = learningRate * x[i] * deltaHidden[j];
                    w[i, j] += newW[i, j] + momentum * oldW[i, j];
                    oldW[i, j] = newW[i, j];
                }
            }

        }

        public double[,] Backpropagation(bool intermediate, int number)
        {
            double error = double.MaxValue;
            int d, k, epoch = 0;

            while (epoch < maxEpoch && error > tolerance)
            {
                error = 0.0;

                for (d = 1; d <= numberTrainingExamples; d++)
                {
                    double[] x = new double[numberInputUnits + 1];

                    for (int i = 0; i <= numberInputUnits; i++)
                        x[i] = X[d, i];

                    ForwardPass(x);

                    double[] t = new double[numberOutputUnits + 1];

                    for (int i = 0; i <= numberOutputUnits; i++)
                        t[i] = T[d, i];

                    BackwardPass(t, x);

                    for (k = 1; k <= numberOutputUnits; k++)
                    {
                        O[d, k] = p[k];
                        error += Math.Pow(T[d, k] - O[d, k], 2);
                    }
                }

                epoch++;

                error /= (numberTrainingExamples * numberOutputUnits);

                if (intermediate && epoch % number == 0)
                    tb.Text += error.ToString("E10") + "\r\n";
            }

            tb.Text += "\r\n";
            tb.Text += "Mean Square Error = " + error.ToString("E10") + "\r\n";
            tb.Text += "Epoch = " + epoch + "\r\n";

            return O;
        }
    }
}
// Learn the XOR Function
// Inputs/Targets
// 0 0 / 0
// 0 1 / 1
// 1 0 / 1
// 1 1 / 0
// The logistic function works
// with 0 -> 0.1 and 1 -> 0.9
//
// BPNNTestOne (c) 2011
// James Pate Williams, Jr.
// All rights reserved.

using System;
using System.Windows.Forms;

namespace BPNNTestOne
{
    public partial class MainForm : Form
    {
        private int seed = 512;
        private BPNeuralNetwork bpnn;

        public MainForm()
        {
            InitializeComponent();

            int numberInputUnits = 2;
            int numberOutputUnits = 1;
            int numberHiddenUnits = 2;
            int numberTrainingExamples = 4;

            double[,] X =
            {
                {1.0, 0.0, 0.0},
                {1.0, 0.0, 0.0},
                {1.0, 0.0, 1.0},
                {1.0, 1.0, 0.0},
                {1.0, 1.0, 1.0}
            };

            double[,] T =
            {
                {1.0, 0.0},
                {1.0, 0.1},
                {1.0, 0.9},
                {1.0, 0.9},
                {1.0, 0.1}
            };

            bpnn = new BPNeuralNetwork(0.1, 0.9, 1.0e-12,
                    numberHiddenUnits, numberInputUnits,
                    numberOutputUnits, numberTrainingExamples,
                    5000, seed, textBox1);

            for (int i = 1; i <= numberTrainingExamples; i++)
            {
                double[] x = new double[numberInputUnits + 1];
                double[] t = new double[numberOutputUnits + 1];

                for (int j = 0; j <= numberInputUnits; j++)
                    x[j] = X[i, j];

                for (int j = 0; j <= numberOutputUnits; j++)
                    t[j] = T[i, j];
 
                bpnn.SetTrainingExample(t, x, i);
            }

            double[,] O = bpnn.Backpropagation(true, 500);

            textBox1.Text += "\r\n";
            textBox1.Text += "x0\tx1\tTarget\tOutput\r\n\r\n";

            for (int i = 1; i <= numberTrainingExamples; i++)
            {
                for (int j = 1; j <= numberInputUnits; j++)
                    textBox1.Text += X[i, j].ToString("##0.#####") + "\t";

                for (int j = 1; j <= numberOutputUnits; j++)
                {
                    textBox1.Text += T[i, j].ToString("####0.#####") + "\t";
                    textBox1.Text += O[i, j].ToString("####0.#####") + "\t";
                }

                textBox1.Text += "\r\n";
            }
        }
    }
}

Comparison of Euler Method, Runge-Kutta 2, Runge-Kutta 4, and Taylor Series Solutions of a Single Ordinary Differential Equation

#include "RungeKutta4.h"
#include <iomanip>
#include <iostream>
using namespace std;

int main()
{
	int nSteps;
	vector<Point> solution1, solution2;
	vector<Point> solution3, solution4;

	while (true)
	{
		cout << "n-steps (zero to exit app) = ";
		cin >> nSteps;

		if (nSteps == 0)
			break;

		cout << "n\t\txn\tyn2p(xn)\tyn4p(xn)\tEuler\t\tTaylor\t\tDFDX2\t\tDFDX4\r\n";
		RungeKutta4::ComputeEuler(nSteps, 1, 2, -1, solution1);
		RungeKutta4::ComputeRK2(nSteps, 1, 2, -1, solution2);
		RungeKutta4::ComputeRK4(nSteps, 1, 2, -1, solution3);
		RungeKutta4::ComputeTaylor(nSteps, 1, 2, -1, solution4);

		for (int i = 0; i <= nSteps; i++)
		{
			POINT pt1 = solution1[i];
			POINT pt2 = solution2[i];
			POINT pt3 = solution3[i];
			POINT pt4 = solution4[i];
			cout << setw(2) << pt1.n << "\t";
			cout << setprecision(8) << fixed << pt1.x << "\t";
			cout << setprecision(8) << fixed << pt3.y << "\t";
			cout << setprecision(8) << fixed << pt4.y << "\t";
			cout << setprecision(8) << fixed << pt1.y << "\t";
			cout << setprecision(8) << fixed << pt2.y << "\t";
			cout << setprecision(8) << fixed << pt2.derivative << "\t";
			cout << setprecision(8) << fixed << pt3.derivative << "\r\n";
		}
	}
}
#pragma once
#include <vector>
using namespace std;

typedef struct Point
{
	int n;
	long double derivative, x, y;
} POINT, *PPOINT;

class RungeKutta4
{
private:
	static long double FX(
		long double x,
		long double y);
	static long double DFDX(
		long double x,
		long double y,
		long double yp);
public:
	static void ComputeEuler(
		int nSteps,
		long double x0,
		long double x1,
		long double y0,
		vector<Point>& pts);
	static void ComputeRK2(
		int nSteps,
		long double x0,
		long double x1,
		long double y0,
		vector<Point>& pts);
	static void ComputeRK4(
		int nSteps,
		long double x0,
		long double x1,
		long double y0,
		vector<Point>& pts);
	static void ComputeTaylor(
		int nSteps,
		long double x0,
		long double x1,
		long double y0,
		vector<Point>& pts);
};
// Translated from FORTRAN 77 source code found
// in "Elementary Numerical Analysis:
// An Algorithmic Approach" by S. D. Conte and Carl de
// Boor. Translator: James Pate Williams, Jr. (c)
// August 20, 2023

#include "RungeKutta4.h"

long double RungeKutta4::FX(
	long double x, long double y)
{
	long double x2 = x * x;
	long double term1 = 1.0 / x2;
	long double term2 = -y / x;
	long double term3 = -y * y;
	return term1 + term2 + term3;
}

long double RungeKutta4::DFDX(
	long double x,
	long double y,
	long double yp)
{
	long double x3 = x * x * x;
	long double term1 = -2.0 / x3;
	long double term2 = -yp / x;
	long double term3 = y / x / x;
	long double term4 = -2.0 * y * yp;
	return term1 + term2 + term3 + term4;
}

void RungeKutta4::ComputeEuler(
	int nSteps,
	long double x0,
	long double x1,
	long double y0,
	vector<Point>& pts)
{
	Point pt0 = {};
	pt0.n = 0;
	pt0.x = x0;
	pt0.y = y0;
	double derivative = FX(x0, y0);
	pt0.derivative = derivative;
	pts.push_back(pt0);

	if (nSteps == 1)
		return;

	long double h = (x1 - x0) / nSteps;
	long double xn = x0;
	long double yn = y0;

	for (int n = 1; n <= nSteps; n++)
	{
		xn = x0 + n * h;
		long double yn = y0 + h * FX(xn, y0);
		derivative = FX(xn, y0);
		pt0.n = n;
		pt0.derivative = derivative;
		pt0.x = xn;
		pt0.y = yn;
		pts.push_back(pt0);
		y0 = yn;
	}
}

void RungeKutta4::ComputeRK2(
	int nSteps,
	long double x0,
	long double x1,
	long double y0,
	vector<Point>& pts)
{
	Point pt0 = {};
	pt0.n = 0;
	pt0.x = x0;
	pt0.y = y0;
	double derivative = FX(x0, y0);
	pt0.derivative = derivative;
	pts.push_back(pt0);

	if (nSteps == 1)
		return;

	long double h = (x1 - x0) / nSteps;
	long double xn = x0;
	long double yn = y0;

	for (int n = 1; n <= nSteps; n++)
	{
		long double k1 = h * FX(xn, yn);
		long double k2 = h * FX(xn + h, yn + k1);
		yn += 0.5 * (k1 + k2);
		xn = x0 + n * h;
		derivative = FX(xn, yn);
		pt0.n = n;
		pt0.derivative = derivative;
		pt0.x = xn;
		pt0.y = yn;
		pts.push_back(pt0);
	}
}

void RungeKutta4::ComputeRK4(
	int nSteps,
	long double x0,
	long double x1,
	long double y0,
	vector<Point>& pts)
{
	Point pt0 = {};
	pt0.n = 0;
	pt0.x = x0;
	pt0.y = y0;
	double derivative = FX(x0, y0);
	pt0.derivative = derivative;
	pts.push_back(pt0);

	if (nSteps == 1)
		return;

	long double h = (x1 - x0) / nSteps;
	long double xn = x0;
	long double yn = y0;

	for (int n = 1; n <= nSteps; n++)
	{
		long double k1 = h * FX(xn, yn);
		long double k2 = h * FX(xn + h / 2, yn + k1 / 2);
		long double k3 = h * FX(xn + h / 2, yn + k2 / 2);
		long double k4 = h * FX(xn + h, yn + k3);
		xn = x0 + n * h;
		yn = yn + (k1 + k2 + k3 + k4) / 6.0;
		derivative = FX(xn, yn);
		pt0.n = n;
		pt0.derivative = derivative;
		pt0.x = xn;
		pt0.y = yn;
		pts.push_back(pt0);
	}
}

void RungeKutta4::ComputeTaylor(
	int nSteps,
	long double x0,
	long double x1,
	long double y0,
	vector<Point>& pts)
{
	Point pt0 = {};
	pt0.n = 0;
	pt0.x = x0;
	pt0.y = y0;
	double derivative = FX(x0, y0);
	pt0.derivative = derivative;
	pts.push_back(pt0);

	if (nSteps == 1)
		return;

	long double h = (x1 - x0) / nSteps;
	long double xn = x0;
	long double yn = y0;
	long double yp = FX(x0, y0);

	for (int n = 1; n <= nSteps; n++)
	{
		xn = x0 + n * h;
		yp = FX(xn, y0);
		long double yn = y0 + h * (FX(xn, y0) + h * DFDX(xn, y0, yp) / 2);
		derivative = FX(xn, y0);
		pt0.n = n;
		pt0.derivative = derivative;
		pt0.x = xn;
		pt0.y = yn;
		pts.push_back(pt0);
		y0 = yn;
	}
}

Numerical Differentiation in C# by James Pate Williams, Jr. Translated from FORTRAN 77 Formulas

using System;
using System.Windows.Forms;

namespace NumericalDifferentiation
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            comboBox1.SelectedIndex = 0;
        }

        private double F1(double x)
        {
            return x * (x * (x - 2) + 4) - 1;
        }

        private double F2(double x)
        {
            return x * Math.Exp(-x) + 1;
        }

        private double F3(double x)
        {
            return x * x * Math.Sin(x) + 1;
        }

        private double DF1(double x)
        {
            return 3 * x * x - 4 * x + 4; 
        }

        private double DF2(double x)
        {
            return Math.Exp(-x) - x * Math.Exp(-x);
        }

        private double DF3(double x)
        {
            return 2 * x * Math.Sin(x) + x * x * Math.Cos(x);
        }

        private double DDF1(double x)
        {
            return 6 * x - 4;
        }

        private double DDF2(double x)
        {
            return -2 * Math.Exp(-x) + x * Math.Exp(-x);
        }

        private double DDF3(double x)
        {
            return
                2 * Math.Sin(x) + 2 * x * Math.Cos(x) +
                2 * x * Math.Cos(x) - x * x * Math.Sin(x);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            double a = (double)numericUpDown1.Value;
            double b = (double)numericUpDown2.Value;
            int n = (int)numericUpDown3.Value;
            double deriv1c, deriv1f;
            double deriv2c, deriv2f;
            double x = a, y, u, v;
            double error1c, error1f, error2c, error2f;
            double h = (b - a) / n;

            if (comboBox1.SelectedIndex == 0)
                textBox1.Text += "x\t  f'(x) e  f'(x) 1  f'(x) 2  " +
                    "error1   error2   f''(x)e  f''(x)1  f''(x)2  " +
                    "error1   error2\r\n";
            else if (comboBox1.SelectedIndex == 1)
                textBox1.Text += "x\t  g'(x) e  g'(x) 1  g'(x) 2  " +
                    "error1   error2   g''(x)e  g''(x)1  g''(x)2  " +
                    "error1   error2\r\n";
            else if (comboBox1.SelectedIndex == 2)
                textBox1.Text += "x\t  h'(x) e  h'(x) 1  h'(x) 2  " +
                    "error1   error2   h''(x)e  h''(x)1  h''(x)2  " +
                    "error1   error2\r\n";

            while (x <= b)
            {
                switch (comboBox1.SelectedIndex)
                {
                    case 0:
                        y = F1(x);
                        u = DF1(x);
                        v = DDF1(x);
                        deriv1c = Differentiation.Derivative1sc(x, h, F1);
                        deriv1f = Differentiation.Derivative1sf(x, h, F1);
                        deriv2c = Differentiation.Derivative2sc(x, h, F1);
                        deriv2f = Differentiation.Derivative2sf(x, h, F1);
                        error1c = Math.Abs(deriv1c - u);
                        error1f = Math.Abs(deriv1f - u);
                        error2c = Math.Abs(deriv2c - v);
                        error2f = Math.Abs(deriv2f - v);
                        textBox1.Text +=
                            x.ToString("F5").PadLeft(8) + " " +
                            u.ToString("F5").PadLeft(8) + " " +
                            deriv1c.ToString("F5").PadLeft(8) + " " +
                            deriv1f.ToString("F5").PadLeft(8) + " " +
                            error1c.ToString("F5").PadLeft(8) + " " +
                            error1f.ToString("F5").PadLeft(8) + " " +
                            v.ToString("F5").PadLeft(8) + " " +
                            deriv2c.ToString("F5").PadLeft(8) + " " +
                            deriv2f.ToString("F5").PadLeft(8) + " " +
                            error2c.ToString("F5").PadLeft(8) + " " +
                            error2f.ToString("F5").PadLeft(8) + "\r\n";
                        break;
                    case 1:
                        y = F2(x);
                        u = DF2(x);
                        v = DDF2(x);
                        deriv1c = Differentiation.Derivative1sc(x, h, F2);
                        deriv1f = Differentiation.Derivative1sf(x, h, F2);
                        deriv2c = Differentiation.Derivative2sc(x, h, F2);
                        deriv2f = Differentiation.Derivative2sf(x, h, F2);
                        error1c = Math.Abs(deriv1c - u);
                        error1f = Math.Abs(deriv1f - u);
                        error2c = Math.Abs(deriv2c - v);
                        error2f = Math.Abs(deriv2f - v);
                        textBox1.Text +=
                            x.ToString("F5").PadLeft(8) + " " +
                            u.ToString("F5").PadLeft(8) + " " +
                            deriv1c.ToString("F5").PadLeft(8) + " " +
                            deriv1f.ToString("F5").PadLeft(8) + " " +
                            error1c.ToString("F5").PadLeft(8) + " " +
                            error1f.ToString("F5").PadLeft(8) + " " +
                            v.ToString("F5").PadLeft(8) + " " +
                            deriv2c.ToString("F5").PadLeft(8) + " " +
                            deriv2f.ToString("F5").PadLeft(8) + " " +
                            error2c.ToString("F5").PadLeft(8) + " " +
                            error2f.ToString("F5").PadLeft(8) + "\r\n";
                        break;
                    case 2:
                        y = F3(x);
                        u = DF3(x);
                        v = DDF3(x);
                        deriv1c = Differentiation.Derivative1sc(x, h, F3);
                        deriv1f = Differentiation.Derivative1sf(x, h, F3);
                        deriv2c = Differentiation.Derivative2sc(x, h, F3);
                        deriv2f = Differentiation.Derivative2sf(x, h, F3);
                        error1c = Math.Abs(deriv1c - u);
                        error1f = Math.Abs(deriv1f - u);
                        error2c = Math.Abs(deriv2c - v);
                        error2f = Math.Abs(deriv2f - v);
                        textBox1.Text +=
                            x.ToString("F5").PadLeft(8) + " " +
                            u.ToString("F5").PadLeft(8) + " " +
                            deriv1c.ToString("F5").PadLeft(8) + " " +
                            deriv1f.ToString("F5").PadLeft(8) + " " +
                            error1c.ToString("F5").PadLeft(8) + " " +
                            error1f.ToString("F5").PadLeft(8) + " " +
                            v.ToString("F5").PadLeft(8) + " " +
                            deriv2c.ToString("F5").PadLeft(8) + " " +
                            deriv2f.ToString("F5").PadLeft(8) + " " +
                            error2c.ToString("F5").PadLeft(8) + " " +
                            error2f.ToString("F5").PadLeft(8) + "\r\n";                   
                        break;
                    default:
                        break;
                }

                x += h;
            }

            textBox1.Text += comboBox1.SelectedItem;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = string.Empty;
        }
    }
}
// Derivative formulas translated from FORTRAN 77
// source code found in "Elementary Numerical Analysis:
// An Algorithmic Approach" by S. D. Conte and Carl de
// Boor. Translator: James Pate Williams, Jr. (c)
// August 18 - 19, 2023

using System;

namespace NumericalDifferentiation
{
    // Numerically compute first and second
    // ordinary derivatives
    class Differentiation
    {
        static public double Derivative1sc(
            double a, double h, Func<double, double> f)
        {
            return (f(a + h) - f(a - h)) / (h + h);
        }

        static public double Derivative1sf(
            double a, double h, Func<double, double> f)
        {
            return (-3.0 * f(a) + 4.0 * f(a + h) - f(a + h + h)) / (h + h);
        }

        static public double Derivative2sc(
            double a, double h, Func<double, double> f)
        {
            return (f(a - h) - 2.0 * f(a) + f(a + h)) / (h + h);
        }

        static public double Derivative2sf(
            double a, double h, Func<double, double> f)
        {
            return (f(a) - 2.0 * f(a + h) + f(a + h + h)) / (h + h);
        }
    }
}

Adams-Moulton Predictor Corrector Method to Solve a One-Dimensional Ordinary Differential Equation Translated from FORTRAN 77 Code by James Pate Williams, Jr.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AdamsMoultonMethod1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private double Solution(double x)
        {
            return Math.Exp(x) - 1.0 - x;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            int numberSteps = (int)numericUpDown1.Value;
            AdamsMoulton.AdamsMoultonMethod(
                numberSteps, Solution, textBox1);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = string.Empty;
        }
    }
}
// Adams-Moulton Method translated from FORTRAN 77
// source code found in "Elementary Numerical Analysis:
// An Algorithmic Approach" by S. D. Conte and Carl de
// Boor. Translator: James Pate Williams, Jr. (c)
// August 18, 2023

using System;
using System.Windows.Forms;

namespace AdamsMoultonMethod1
{
    public struct Point
    {
        public double x, y;
    }
    class AdamsMoulton
    {
        static private string FormatNumber(double x)
        {
            return x.ToString("E11").PadLeft(12);
        }
        static private string FormatLine(
            int n, double x, double y, double delta, double error)
        {
            return
                n.ToString("D2") + " " +
                FormatNumber(x) + " " +
                FormatNumber(y) + " " +
                FormatNumber(delta) + " " +
                FormatNumber(error) + "\r\n";
        }
        static public void AdamsMoultonMethod(
            int numberSteps, Func<double, double> solution,
            TextBox textBox)
        {
            double h = 1.0 / numberSteps;
            double xn = 0.0, yn = 0.0, yofxn;
            double xBegin = 0.0, yBegin = 0.0;
            double fnPredict, ynPredict;
            double delta = 0.0, error = 0.0;
            double[] f = new double[numberSteps];
            int n = 0;

            textBox.Text += "n\txn\tyn\tdelta\terror\r\n";
            textBox.Text += FormatLine(n, xn, yn, delta, error);
            f[1] = xBegin + yBegin;

            for (n = 1; n <= 3; n++)
            {
                xn = xBegin + n * h;
                yn = solution(xn);
                f[n + 1] = xn + yn;
                textBox.Text += FormatLine(n, xn, yn, delta, error);
            }

            for (n = 4; n <= numberSteps; n++)
            {
                ynPredict =
                    yn + h / 24.0 * (55.0 * f[4] - 59.0 * f[3] +
                    37.0 * f[2] - 9.0 * f[1]);
                xn = xBegin + n * h;
                fnPredict = xn + ynPredict;
                yn += h / 24.0 * (9.0 * fnPredict + 19.0 * f[4]
                    - 5.0 * f[3] + f[2]);
                delta = (yn - ynPredict) / 14.0;
                f[1] = f[2];
                f[2] = f[3];
                f[3] = f[4];
                f[4] = xn + yn;
                yofxn = solution(xn);
                error = yn - yofxn;
                textBox.Text += FormatLine(n, xn, yn, delta, error);
            }
        }
    }
}

Determinant Calculations: Bareiss Algorithm and Gaussian Elimination by James Pate Williams, Jr.

Below are three screenshots of two methods of calculating the determinant of a matrix, namely the Bareiss Algorithm and Gaussian Elimination:

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace MatrixInverseComparison
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }
        static private string FormatNumber(double x)
        {
            string result = string.Empty;

            if (x > 0)
                result += x.ToString("F5").PadLeft(10);
            else
                result += x.ToString("F5").PadLeft(10);

            return result;
        }

        private void MultiplyPrintMatricies(
            double[,] A, double[,] B, int n)
        {
            double[,] I = new double[n, n];

            textBox1.Text += "Matrix Product:\r\n";

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double sum = 0.0;

                    for (int k = 0; k < n; k++)
                        sum += A[i, k] * B[k, j];

                    I[i, j] = sum;
                }
            }

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    textBox1.Text += FormatNumber(I[i, j]) + " ";
                }

                textBox1.Text += "\r\n";
            }
        }

        private void PrintMatrix(string title, double[,] A, int n)
        {
            textBox1.Text += title + "\r\n";

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    textBox1.Text += FormatNumber(A[i, j]) + " ";
                }

                textBox1.Text += "\r\n";
            }
        }

        private void Compute(double[,] MI, int n)
        {
            double determinantGE = 1;
            double[] b = new double[n];
            double[] x = new double[n];
            double[,] MB1 = new double[n, n];
            double[,] MB2 = new double[n, n];
            double[,] MG = new double[n, n];
            double[,] MS = new double[n, n];
            double[,] IG = new double[n, n];
            double[,] IS = new double[n, n];
            int[] pivot = new int[n];
            Stopwatch sw = new();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                    MB1[i, j] = MB2[i, j] = MG[i, j] = MS[i, j] = MI[i, j];
            }
            PrintMatrix("Initial Matrix: ", MI, n);
            sw.Start();
            int flag = DirectMethods.Factor(MG, n, pivot);
            if (flag != 0)
            {
                for (int i = 0; i < n; i++)
                    determinantGE *= MG[i, i];
                determinantGE *= flag;
            }
            sw.Stop();
            PrintMatrix("Gaussian Elimination Final:", MG, n);
            for (int i = 0; i < n; i++)
                b[i] = 0;
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    b[j] = 1.0;
                    DirectMethods.Substitute(MG, b, x, n, pivot);
                    for (int k = 0; k < n; k++)
                        IG[k, j] = x[k];
                    b[j] = 0.0;
                }
            }
            PrintMatrix("Gaussian Elimination Inverse:", IG, n);
            textBox1.Text += "Determinant: " +
                FormatNumber(determinantGE) + "\r\n";
            MultiplyPrintMatricies(IG, MI, n);
            textBox1.Text += "Runtime (MS) = " +
                sw.ElapsedMilliseconds + "\r\n";
            sw.Start();
            double determinant1 = BareissAlgorithm.Determinant1(MB1, n);
            sw.Stop();
            PrintMatrix("Bareiss Algorithm Final 1:", MB1, n);
            textBox1.Text += "Determinant: " +
                FormatNumber(determinant1) + "\r\n";
            textBox1.Text += "Runtime (MS) = " +
                sw.ElapsedMilliseconds + "\r\n";
            sw.Start();
            double determinant2 = BareissAlgorithm.Determinant2(MB2, n);
            sw.Stop();
            PrintMatrix("Bareiss Algorithm Final 2:", MB2, n);
            textBox1.Text += "Determinant: " +
                FormatNumber(determinant2) + "\r\n";
            textBox1.Text += "Runtime (MS) = " +
                sw.ElapsedMilliseconds + "\r\n";
        }
        private void button1_Click(object sender, EventArgs e)
        {
            int n = (int)numericUpDown1.Value;
            int seed = (int)numericUpDown2.Value;
            double[,] A = new double[n, n];
            Random random = new Random(seed);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double q = n * random.NextDouble();

                    while (q == 0.0)
                        q = n * random.NextDouble();

                    A[i, j] = q;
                }
            }
            
            Compute(A, n);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = string.Empty;
        }
    }
}
using System;

namespace MatrixInverseComparison
{
    public class DirectMethods
    {
        // Substitute and Factor translated from FORTRAN 77
        // source code found in "Elementary Numerical Analysis:
        // An Algorithmic Approach" by S. D. Conte and Carl de
        // Boor. Translator: James Pate Williams, Jr. (c)
        // August 14 - 17, 2023
        static public void Substitute(
            double[,] w,
            double[] b,
            double[] x,
            int n,
            int[] pivot)
        {
            double sum;
            int i, j, n1 = n - 1;

            if (n == 1)
            {
                x[0] = b[0] / w[0, 0];
                return;
            }

            // forward substitution
            x[0] = b[pivot[0]];

            for (i = 0; i < n; i++)
            {
                for (j = 0, sum = 0.0; j < i; j++)
                    sum += w[i, j] * x[j];
                x[i] = b[pivot[i]] - sum;
            }

            // backward substitution
            x[n1] /= w[n1, n1];

            for (i = n - 2; i >= 0; i--)
            {
                for (j = i + 1, sum = 0.0; j < n; j++)
                    sum += w[i, j] * x[j];
                x[i] = (x[i] - sum) / w[i, i];
            }
        }

        // Factor returns +1 if an even number of exchanges
        // Factor returns -1 if an odd  number of exchanges
        // Factor retrurn 0  if matrix is singular
        static public int Factor(
            double[,] w, int n, int[] pivot)
        // returns 0 if matrix is singular
        {
            double awikod, col_max, ratio, row_max, temp;
            double[] d = new double[n];
            int flag = 1, i, i_star, j, k;

            for (i = 0; i < n; i++)
            {
                pivot[i] = i;
                row_max = 0;
                for (j = 0; j < n; j++)
                    row_max = Math.Max(row_max, Math.Abs(w[i, j]));
                if (row_max == 0)
                {
                    flag = 0;
                    row_max = 1;
                }
                d[i] = row_max;
            }
            if (n <= 1)
                return flag;
            // factorization
            for (k = 0; k < n - 1; k++)
            {
                // determine pivot row the row i_star
                col_max = Math.Abs(w[k, k]) / d[k];
                i_star = k;
                for (i = k + 1; i < n; i++)
                {
                    awikod = Math.Abs(w[i, k]) / d[i];
                    if (awikod > col_max)
                    {
                        col_max = awikod;
                        i_star = i;
                    }
                }
                if (col_max == 0)
                    flag = 0;
                else
                {
                    if (i_star > k)
                    {
                        // make k the pivot row by
                        // interchanging with i_star
                        flag *= -1;
                        i = pivot[i_star];
                        pivot[i_star] = pivot[k];
                        pivot[k] = i;
                        temp = d[i_star];
                        d[i_star] = d[k];
                        d[k] = temp;
                        for (j = 0; j < n; j++)
                        {
                            temp = w[i_star, j];
                            w[i_star, j] = w[k, j];
                            w[k, j] = temp;
                        }
                    }
                    // eliminate x[k]
                    for (i = k + 1; i < n; i++)
                    {
                        w[i, k] /= w[k, k];
                        ratio = w[i, k];
                        for (j = k + 1; j < n; j++)
                            w[i, j] -= ratio * w[k, j];
                    }
                }
            }

            if (w[n - 1, n - 1] == 0)
                flag = 0;

            return flag;
        }
    }
}
namespace MatrixInverseComparison
{
    // One implementation is based on https://en.wikipedia.org/wiki/Bareiss_algorithm
    // Another perhaps better implementation is found on the following webpage
    // https://cs.stackexchange.com/questions/124759/determinant-calculation-bareiss-vs-gauss-algorithm
    class BareissAlgorithm
    {
        static public double Determinant1(double[,] M, int n)
        {
            double M00;

            for (int k = 0; k < n; k++)
            {
                if (k - 1 == -1)
                    M00 = 1;
                else
                    M00 = M[k - 1, k - 1];

                for (int i = k + 1; i < n; i++)
                {
                    for (int j = k + 1; j < n; j++)
                    {
                        M[i, j] = (
                            M[i, j] * M[k, k] -
                            M[i, k] * M[k, j]) / M00;
                    }
                }
            }

            return M[n - 1, n - 1];
        }

        static public double Determinant2(double[,] A, int dim)
        {
            if (dim <= 0)
            {
                return 0;
            }

            double sign = 1;

            for (int k = 0; k < dim - 1; k++)
            {
                //Pivot - row swap needed
                if (A[k, k] == 0)
                {
                    int m;
                    for (m = k + 1; m < dim; m++)
                    {
                        if (A[m, k] != 0)
                        {
                            double[] tempRow = new double[dim];

                            for (int i = 0; i < dim; i++)
                                tempRow[i] = A[m, i];
                            for (int i = 0; i < dim; i++)
                                A[m, i] = A[k, i];
                            for (int i = 0; i < dim; i++)
                                A[k, i] = tempRow[i];
                            sign = -sign;
                            break;
                        }
                    }
                    //No entries != 0 found in column k -> det = 0
                    if (m == dim)
                    {
                        return 0;
                    }
                }
                //Apply formula
                for (int i = k + 1; i < dim; i++)
                {
                    for (int j = k + 1; j < dim; j++)
                    {
                        A[i, j] = A[k, k] * A[i, j] - A[i, k] * A[k, j];

                        if (k >= 1)
                        {
                            A[i, j] /= A[k - 1, k - 1];
                        }
                    }
                }
            }

            return sign * A[dim - 1, dim - 1];
        }
    }
}