using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
namespace NumIntegration
{
public class Program
{
/*
* TODO:
^* 1. Численное интегрирование методом Трапеций
^* 2. Численное интегрирование методом Трапеций с поправкой Эйлера
^* 3. Проверка порядка точности для методов
^* 4. Вычисление интеграла с точностью Eps с помощью апостериорной оценки Рунге
* 5. Вычисление интеграла с точностью Eps и автоматическим подбором шага с помощью ариорной оценки Рунге
* (*) Графичесоке описание: Вывести график изменения шага интегрирования (только для п.5)
*/
/// <summary>
/// Функция, от которой нужно посчитать интеграл
/// </summary>
/// <param name="x">Точка</param>
/// <returns>Значение в точке</returns>
public static double Function(double x)
{
//return x*Math.Log((1+x)/(1-x));
/*double numenator = Math.Sin(x);
double cos = Math.Cos(x);
double denumentor = (cos * cos + 1);
return numenator / denumentor;*/
return x*x*x;
}
/// <summary>
/// Взятый интеграл
/// </summary>
/// <param name="x">Точка</param>
/// <returns>Значение в точке</returns>
public static double AccurateValue(double x)
{
//double t = -Math.Cos(x);
//return Math.Atan(t);
return x*x*x*x/4.0;
}
/// <summary>
/// Точное значение интеграла
/// </summary>
/// <param name="a">Начало отрезка</param>
/// <param name="b">Конец отрезка</param>
/// <returns>Значение точного интеграла</returns>
public static double AccurateIntegral(double a, double b)
{
if (a > b) return (-1) * (AccurateValue(a) - AccurateValue(b));
return AccurateValue(b) - AccurateValue(a);
}
public delegate double IntegralMethod(int pointsCount, double a, double b);
/// <summary>
/// Первая производная подинтегральной функции
/// </summary>
/// <param name="x">Точка</param>
/// <returns>Значение в точке</returns>
public static double Deriative(double x)
{
/*double cos = Math.Cos(x);
double sin = Math.Sin(x);
return (2 * cos * sin * sin + cos * (cos * cos + 1)) / ((cos * cos + 1) * (cos * cos + 1));*/
return 3*x*x;
}
/// <summary>
/// Метод, который меняет местами две переменные
/// </summary>
/// <param name="a">Ссылка на первый параметр</param>
/// <param name="b">Ссылка на второй параметр</param>
public static void Swap(ref double a, ref double b)
{
double temp = a;
a = b;
b = temp;
}
/// <summary>
/// Метод Трапеций
/// </summary>
/// <param name="a">Начало отрезка</param>
/// <param name="b">Конец отрезка</param>
/// <param name="step">Шаг</param>
/// <returns>Приближенное значение интеграла, посчитанное данным методом</returns>
public static double MethodTrapeze(double a, double b, int pointsCounts)
{
double count = 0.0;
int minus = 1;
if (a > b)
{
Swap(ref a, ref b);
minus = -1;
}
double step = (b - a) / pointsCounts;
double point = a + step;
while (pointsCounts - 1 > 0)
{
count += Function(point);
point += step;
pointsCounts--;
}
count = (count + 0.5 * (Function(a) + Function(b))) * step;
return count * minus;
}
/// <summary>
/// Численное интегрирование
/// </summary>
/// <param name="pointsCount">Количетсво точек</param>
/// <param name="a">Начало отрезка</param>
/// <param name="b">Конец отрезка</param>
/// <returns>Значение интеграла</returns>
public static double IntegralTrap(int pointsCount, double a, double b)
{
return MethodTrapeze(a, b, pointsCount);
}
/// <summary>
/// Численное интегрирование методом трапеций с поправкой Эйлера
/// </summary>
/// <param name="pointsCount">Количетсво точек</param>
/// <param name="a">Начало отрезка</param>
/// <param name="b">Конец отрезка</param>
/// <returns>Значение интеграла</returns>
public static double IntegralEuler(int pointsCount, double a, double b)
{
double step;
if (a > b)
step = (a - b) / pointsCount;
else
step = (b - a) / pointsCount;
return MethodTrapeze(a, b, pointsCount) - step * step / 12 * (Deriative(b) - Deriative(a));
}
public static void IntegralMethodTrapeze()
{
//double begin = Math.PI / 2, end = Math.PI;
double begin = 2, end = 4;
double accurateIntegral = AccurateIntegral(begin, end);
Console.WriteLine("Точное значение интеграла: {0}", accurateIntegral);
Console.WriteLine("<<<Метод трапеции>>>");
Console.WriteLine(" Разбиение\t|\tИнтеграл\t|\tАбс. ошибка\t\t|\tПорядок");
for (int i = 10; i <= 320; i *= 2)
{
double integral = IntegralTrap(i / 2, begin, end);
double integral2 = IntegralTrap(i, begin, end);
double absoluteError = Math.Abs(accurateIntegral - integral);
double absoluteError2 = Math.Abs(accurateIntegral - integral2);
if (i == 10)
{
Console.WriteLine("\t{0}\t|\t{1:#0.#############}\t|\t{2,10}\t|\t -------------", i, integral2,
absoluteError);
continue;
}
Console.WriteLine("\t{0}\t|\t{1:#0.#############}\t|\t{2,10}\t|\t{3:#0.#############}", i, integral2,
absoluteError, absoluteError / absoluteError2);
}
}
public static void IntegralMethodEuler()
{
//double begin = Math.PI / 2, end = Math.PI;
double begin = 2, end = 4;
double accurateIntegral = AccurateIntegral(begin, end);
Console.WriteLine("\n\n");
Console.WriteLine("Точное значение интеграла: {0}", accurateIntegral);
Console.WriteLine("<<<Метод трапеции с поправкой Эйлера>>>");
Console.WriteLine(" Разбиение\t|\tИнтеграл\t|\tАбс. ошибка\t\t|\tПорядок");
for (int i = 10; i <= 320; i *= 2)
{
double integral = IntegralEuler(i / 2, begin, end);
double integral2 = IntegralEuler(i, begin, end);
double absoluteError = Math.Abs(accurateIntegral - integral);
double absoluteError2 = Math.Abs(accurateIntegral - integral2);
if (i == 10)
{
Console.WriteLine("\t{0}\t|\t{1:#0.#############}\t|\t{2,10}\t|\t -------------", i, integral2,
absoluteError);
continue;
}
Console.WriteLine("\t{0}\t|\t{1:#0.#############}\t|\t{2,10}\t|\t{3:#0.#############}", i, integral2,
absoluteError, absoluteError / absoluteError2);
}
}
public static void Runge(int pointsCount, double begin, double end, IntegralMethod Integral, int p, double eps)
{
double integ;
double integr;
do
{
integ = Integral(pointsCount, begin, end);
integr = Integral(2 * pointsCount, begin, end);
pointsCount *= 2;
} while (Math.Abs(integ - integr) >= (Math.Pow(2, p) - 1) * eps);
Console.WriteLine("Количество точек: " + pointsCount + "\nЗначение интеграла: " + integr);
}
static void Main(string[] args)
{
IntegralMethodTrapeze();
IntegralMethodEuler();
double begin = Math.PI / 2, end = Math.PI;
int pointsCount = 10;
double eps = 2.5E-04;
int p = 2;
Console.WriteLine("Оценка Рунге для метода трапеций с eps = " + eps);
Runge(pointsCount, begin, end, new IntegralMethod(IntegralTrap), p, eps);
p = 4;
eps = 0.0000000001;
Console.WriteLine("\nОценка Рунге для метода трапеций с eps = " + eps);
Runge(pointsCount, begin, end, new IntegralMethod(IntegralEuler), p, eps);
Console.ReadKey();
}
}
}