Вы находитесь на странице: 1из 37

Содержание

1. Определение порядков малости 3


1.1. Правая формула численного дифференцирования . . . . . . . . . . . . . . . . . . 3
1.2. Центральная формула численного дифференцирования . . . . . . . . . . . . . . 4
1.3. Формулы численного интегрирования методом прямоугольников . . . . . . . . . 5
1.4. Формулы численного интегрирования методом трапеций . . . . . . . . . . . . . . 6

2. Программный способ нахождения порядков малости бесконечно малых ве-


личин 8
2.1. Численный анализ бесконечно малых величин . . . . . . . . . . . . . . . . . . . . 8
2.2. Численный анализ бесконечно большой величины . . . . . . . . . . . . . . . . . . 9

3. Дробные производные 10
3.1. Вычисление дробных производных . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2. Вычисление дробных производных для дробной степени . . . . . . . . . . . . . . 10
3.3. Разложение степенного ряда . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4. Анализ бесконечно малых функций нескольких переменных 12


4.1. Вычисления для ортогонального вектора . . . . . . . . . . . . . . . . . . . . . . . 13
4.2. Вычисление графика порядков малости . . . . . . . . . . . . . . . . . . . . . . . 14

A Программный анализ бесконечно малых 15

B Тест анализатора бесконечно малых 19

C Программный анализ алгоритма пузырьковой сортировки 22

D Тест анализатора пузырьковой сортировки 25

E Программный анализ БМФ многих переменных 26

F Тест анализатора БМФ многих переменных 34


1. Определение порядков малости
Дана функция √
sin(6x) + x2 + 6x (1)
Определение порядка малости и константы C погрешности ϕ(h).

1.1. Правая формула численного дифференцирования

f (x + h) − f (h)
f 0 (x) ≈ (2)
h
Для начала вычислим производную аналитически

x+3
6 cos(6x) + √ (3)
x2 + 6x
При x = 6: f 0 (6) ≈ 0.292878, если значение в косинусе указано в радианах.

1. В Excel вычисляем значения по формуле 2, постепенно уменьшая порядки малости


h до 20, чтобы заметить эффект неточных вычислений после lg(h) = −8 и эффект
невозможных вычислений после lg(h) = −14, которые вызваны неточными машинными
вычислениями (в Excel m = 10−16 );

2. для каждого значения находим погрешность ϕ(h) = f 0 (x) − f˜0 (x), где f˜0 (x) — формула
численного дифференцирования;

3. логарифмируем порядки малости и найденные погрешности;

4. строим график lg(h)-lg(ϕ(h)) — см. рис. 1.

Рис. 1: lg-lg график погрешности правой формулы численного дифференцирования

3
На графике видно, что в начале вычислений график явно представляет собой линейную
функцию вида αx + k, после lg(h) = −8 график представляет собой непонятную функцию,
стремящуюся к оси O ln(h), а после lg(h) = −15 график представляет собой линию lg(ϕ(h)) =
lg(f 0 (h)) ≈ 0.29, так как численно производная в этом промежутке и далее равна 0.
Для определения порядка малости α вычислим линию тренда в промежутке [-8; -1]; по
итогу средний коэффициент α ≈ 0.99. Для определения k нужно найти точку пересечения
линейной функции с осью O ln(ϕ), она оказывается: k ≈ 1.23, тогда C = 10k ≈ 16.9824.

1.2. Центральная формула численного дифференцирования

f (x + h) − f (x − h)
f 0 (x) ≈ (4)
2h
Аналитически производная функции 1 представлена в 3.
При x = 6: f 0 (6) ≈ 0.292878, если значение в косинусе указано в радианах.

1. В Excel вычисляем значения по формуле 4, постепенно уменьшая порядок малости h


до 20, чтобы заметить эффект неточных вычислений после lg(h) = −5 и эффект невоз-
можных вычислений после lg(h) = −14, которые вызваны неточными машинными вы-
числениями (в Excel m = 10−16 );

2. для каждого значения находим погрешность ϕ(h) = f 0 (x) − f˜0 (x), где f˜0 (x) — формула
численного дифференцирования;

3. логарифмируем порядок малости и найденные погрешности;

4. строим график lg(h)-lg(ϕ(h)) — см. рис. 2.

Рис. 2: lg-lg график погрешности центральной формулы численного дифференцирования

4
На графике видно, что в начале вычислений график явно представляет собой линейную
функцию вида αx + k, после lg(h) = −5 график представляет собой непонятную функцию,
стремящуюся к оси O ln(h), а после lg(h) = −15 график представляет собой линию lg(ϕ(h)) =
lg(f 0 (h)) ≈ 0.29, так как численно производная в этом промежутке и далее равна 0.
Для определения порядка малости α вычислим линию тренда в промежутке [-5; -1]; по
итогу средний коэффициент α ≈ 2.01. Для определения k нужно найти точку пересечения
линейной функции с осью O ln(ϕ), она оказывается: k ≈ 0.69, тогда C = 10k ≈ 4.8978.

1.3. Формулы численного интегрирования методом прямоугольни-


ков
!
ai+1
ai + ai+1
Z
f (x)dx ≈ (ai+1 − ai ) · f (5)
ai 2
Для начала вычислим интеграл функции аналитически
√ √
(x + 3) x2 + 6x − 9 ln (x + 3) + x2 + 6x cos(6x)
− (6)
2 6
R 12
Для пределов интегрирования a = 6, b = 12 значение интеграла: 6 ≈ 69.7996.
Прим.: для численного интегрирования методом прямоугольников нужно разделить об-
щую площадь на N частей, поэтому сложность алгоритма O (10x ), что означает, при некото-
рой итерации время выполнения резко возрастёт, поэтому вычисления произведены только
до 108 итераций. В качестве числа h выступит значение 6/10i .

1. В Excel вычисляем значения по формуле 5, постепенно увеличивая N , тем самым умень-


шая h до 6 · 10−9 ;

2. для каждого значения находим погрешность ϕ(h) = F (x) − F̃ (x), где F (x) — первооб-
разная для f (x), F̃ (x) — первообразная, вычисленная по численной формуле;

3. логарифмируем порядок малости и найденные погрешности;

4. строим график lg(h) − lg(ϕ(h)) — см. рис. 3.

5
Рис. 3: lg-lg график погрешности численного интегрировния методом прямоугольников

На графике видно, что в начале вычислений график явно представляет собой линейную
функцию вида αx + k, после lg(h) = −5 график представляет собой другую функцию.
Для определения порядка малости α вычислим линию тренда в промежутке [-5; -1]; по
итогу средний коэффициент α ≈ 1.91. Для определения k нужно найти точку пересечения
линейной функции с осью O ln(ϕ), она оказывается: k ≈ −0.7861, тогда C = 10k ≈ 0.1636.

1.4. Формулы численного интегрирования методом трапеций

ai+1
f (ai ) + f (ai+1 )
Z
f (x)dx ≈ (ai+1 − ai ) · (7)
ai 2
Аналитически интеграл Rфункции 1 представлен в 6. Для пределов интегрирования a = 6,
12
b = 12 значение интеграла: 6 ≈ 69.7996.
Прим.: для численного интегрирования методом прямоугольников нужно разделить об-
щую площадь на N частей, поэтому сложность алгоритма O (10x ), что означает, при некото-
рой итерации время выполнения резко возрастёт, поэтому вычисления произведены только
до 108 итераций. В качестве числа h выступит значение 6/10i .

1. В Excel вычисляем значения по формуле 7, постепенно увеличивая N , тем самым умень-


шая h до 6 · 10−9 ;

2. для каждого значения находим погрешность ϕ(h) = F (x) − F̃ (x), где F (x) — первооб-
разная для f (x), F̃ (x) — первообразная, вычисленная по численной формуле;

3. логарифмируем порядок малости и найденные погрешности;

4. строим график lg(h) − lg(ϕ(h)) — см. рис. 4.

6
Рис. 4: lg-lg график погрешности численного интегрировния методом трапеций

На графике видно, что в начале вычислений график явно представляет собой линейную
функцию вида αx + k, после lg(h) = −4 график представляет собой другую функцию.
Для определения порядка малости α вычислим линию тренда на отрезке [-4; -1]; по итогу
средний коэффициент α ≈ 2.13. Для определения k нужно найти точку пересечения линейной
функции с осью O ln(ϕ), она оказывается: k ≈ −0.1628, тогда C = 10k ≈ 0.6873.

7
2. Программный способ нахождения порядков малости бес-
конечно малых величин
2.1. Численный анализ бесконечно малых величин
Дана функция f √
3 x3 (8)
Для анализа бесконечно малой функции f была составлена программа на языке C#. В
приложении A представлена готовая программа. В приложении B приведён текст модульных
тестов со значениями α = 1.5 и C = 3. Все тесты пройдены, поэтому считается, что программа
написана верно.
Для справки приведён табличный вид функции и её логарифма.
X Y lg(X) lg(Y)
1 3 0 0.477121254
1E-01 9.48683298E-02 -1 -1.022878745
1E-02 3E-03 -2 -2.522878745
1E-03 9.48683298E-05 -3 -4.022878745
1E-04 3E-06 -4 -5.522878745
1E-05 9.48683298E-08 -5 -7.022878745
1E-06 3E-09 -6 -8.522878745
1E-07 9.48683298E-11 -7 -10.022878745
1E-08 3E-12 -8 -11.522878745
1E-09 9.48683298E-14 -9 -13.022878745
1E-10 3E-15 -10 -14.522878745
1E-11 9.48683298E-17 -11 -16.022878745
1E-12 3E-18 -12 -17.522878745
1E-13 9.48683298E-20 -13 -19.022878745
1E-14 3E-21 -14 -20.522878745
1E-15 9.48683298E-23 -15 -22.022878745
В итоге функция асимптоты графика выглядит так: 1.5 · x + 0.4771; порядок малости
α ≈ 1.5, коэффициент C = 3.

8
2.2. Численный анализ бесконечно большой величины
Для анализа бесконечно больших величин была составлена программа на языке C#. В
приложении C представлена готовая программа. В приложении D приведён текст модуль-
ных тестов со значениями α ≈ 2 и C ≈ 0.15. Все тесты пройдены, поэтому считается, что
программа написана верно.
В качестве функции используется подсчёт количества итераций перестановок в алгорит-
ме для случайной функции. Очевидно, сложность алгоритма : O(n2 ). Для справки приведён
табличный вид функции на интервале [100; 1000] с шагом 100. Видно, что столбик анали-
тического вычисления F = C · N α почти что совпадает со столбиком экспериментального
вычисления F .
N F lg(N) lg(F) C · Nα
100 2169 2 3,39252108 2199
200 9756 2,30102999 4,03965202 9760
300 24720 2,47712125 4,39304846 23336
400 43890 2,60205999 4,64236558 43312
500 69834 2,69897000 4,83780300 69975
600 99501 2,77815125 4,99344063 103552
700 141859 2,84509804 5,12010977 144236
800 186428 2,90308998 5,24656751 192194
900 245664 2,95424250 5,35346228 247573
1000 306813 3 5,44218648 310505
В итоге функция асимптоты графика выглядит так: 2.1497 · x − 0.9569; порядок малости
α ≈ 2.1497, коэффициент C ≈ 0.1104.

9
3. Дробные производные
3.1. Вычисление дробных производных
Дана функция f
f (x) = x3 (9)
Необходимо вычислить дробные производные ∂ 1/2 f (0), ∂ 1/2 f (2), ∂ 5/2 f (0).r
∂ 1/2 3 Γ (3 + 1) √ 5 Γ(4) 2 √ 6 · 8 2√ 16 2 x
1/2
∂ f= x = x = x x = √ x x = x ,
∂x1/2 Γ (3 + 1 − 1/2) Γ (7/2) 15 π 5 π
15
где Γ(4) = 6 и Γ(7/2) = √ — табличные значения.
8 π
s
16 x
∂ 1/2 f = x2 (10)
5 π

• ∂ 1/2 f (0) = 0
r
16 2
• ∂ 1/2 f (2) = 22 ≈ 10.2129
5 π

Очевидно, что ∂ 5/2 = ∂ 2+1/2 = ∂ 2 · ∂ 1/2 , где ∂ 1/2 уже вычислена ранее (10). Из этого
выражения ясно следует, что ∂ 5/2 f (0) = 0.

3.2. Вычисление дробных производных для дробной степени


Дана функция g √
g(x) = x (11)
Необходимо вычислить дробные производные ∂ 1/2√ g(0), ∂ 1/2 g(2).
∂1/2 √ Γ(1/2 + 1) Γ(3/2) π
∂ 1/2 g = 1/2
x= x0 = = ,
∂x√ Γ(1/2 − 1/2 + 1) Γ(1) 2
3
где Γ(3/2) = — табличное значение. Из этого выражения ясно следует, что ∂ 1/2 g(0) =
√2
π
= ∂ 1/2 g(2) = ,
2

10
4. Анализ бесконечно малых функций нескольких пере-
менных
√ √ 
Дано: функция f , функция g, точка x0 = 1 1 , вектор r̄ = 1/ 10 3/ 10 .



f (x1 , x2 ) = x21 − 6 x1 · x2 (13)

g(t) = f (x0 + t · r̄) − f (x0 ) (14)


Для вычисления порядка малости α и коэффициента C была изменена программа, пред-
ставленная в приложении A — см. приложение E. Для тестирования был составлен модульный
тест — см. приложение F.
Для убедительности приведён табличный вид функции и её логарифма.
T G lg(T) lg(G)
1 2,87674830 0 0,5
1E-01 3,12405592E-01 -1 -0,5
1E-02 3,15829651E-02 -2 -1,5
1E-03 3,16187785E-03 -3 -2,5
1E-04 3,16223766E-04 -4 -3,5
1E-05 3,16227366E-05 -5 -4,5
1E-06 3,16227726E-06 -6 -5,5
1E-07 3,16227762E-07 -7 -6,5
1E-08 3,16227755E-08 -8 -7,5
1E-09 3,16227755E-09 -9 -8,5
1E-10 3,16227045E-10 -10 -9,5
1E-11 3,16218163E-11 -11 -10,5
1E-12 3,16191517E-12 -12 -11,5
1E-13 3,15303339E-13 -13 -12,5
1E-14 3,10862447E-14 -14 -13,5
1E-15 1,77635684E-15 -15 -14,8
В итоге функция асимптоты графика выглядит так: 0, 9999x + 0, 4999; порядок малости
α ≈ 1, коэфициент C ≈ 3, 1618.

12
4.1. Вычисления для ортогонального вектора
 Пусть s̄ ⊥ r̄.По определению,
√  ортогональный вектор находится из s̄ · r̄ = 0. Очевидно, что
1 3 √ 10
√ √ · 10 − = 0. Программа из приложения E была запущена для новых
10 10 3
данных. Получившийся порядок малости α ≈ 0.97, очевидно, больше порядка малости
α ≈ 0.96 при s̄.
Для справки приведён табличный вид функции и её логарифма.
T G lg(T) lg(G)
1 1,87144434 0 0,3
1E-01 2,06431094E-02 -1 -1,7
1E-02 2,09622912E-04 -2 -3,7
1E-03 2,09962077E-06 -3 -5,7
1E-04 2,09996207E-08 -4 -7,7
1E-05 2,10000017E-10 -5 -9,7
1E-06 2,09876561E-12 -6 -11,7
1E-07 2,13162821E-14 -7 -13,7
В итоге функция асимптоты графика выглядит так: 2x + 0, 3222; порядок малости α ≈ 2,
коэффициент C ≈ 2.1.

13
4.2. Вычисление графика порядков малости
Для графика потребуются векторы, вычисленные при повороте по часовой стрелке от r̄.
Полученный график преставлен на рисунке 5. Точка X0 находится на координатах 1 1 .


Линии, очевидно — места, в которых α = 2. Видно, что круги имеют центры примерно в
точках 3/2 5/2 и 1/2 1/2 .


Рис. 5: График порядков малости

14
A Программный анализ бесконечно малых
1 using static System.Math;
2 using System;
3

4 namespace MathUtilities
5 {
6 /// <summary>
7 /// Исследует бесконечно малые функции.
8 /// </summary>
9 public class InfinitesimalAnalyzer
10 {
11 /// <summary>
12 /// Степени десятки для составления табличного вида БМФ.
13 /// </summary>
14 private static readonly double[] PowersOfTen = new double[]{
15 1, 1E-01, 1E-02, 1E-03, 1E-04, 1E-05, 1E-06, 1E-07, 1E-08, 1E-09,
,→ 1E-10, 1E-11, 1E-12, 1E-13, 1E-14, 1E-15
16 };
17

18 /// <summary>
19 /// Функция для исследования.
20 /// </summary>
21 public Func<double, double> Function { get; set; }
22

23 /// <summary>
24 /// Типичный конструктор для создания новой функции.
25 /// </summary>
26 /// <param name="function">функция для исследования</param>
27 public InfinitesimalAnalyzer(Func<double, double> function)
28 {
29 Function = function;
30 }
31

32 /// <summary>
33 /// Определяет, является ли функция бесконечно малой.
34 /// </summary>
35 /// <returns>истина, если функция бесконечно мала</returns>
36 public bool IsInfinitesimal() =>
37 Function(0) == 0;
38

39 /// <summary>
40 /// Определяет табличный вид функции, в том числе логарифмическую
,→ таблицу.
41 /// </summary>
42 /// <param name="start">с какой позиции начинать</param>

15
43 /// <param name="amount">количество ячеек; не более 16; start + amount <=
,→ 16</param>
44 /// <returns>массив с ячейками</returns>
45 public TableItem[] GetTableRepresentation(uint start = 0, uint amount =
,→ 16)
46 {
47 if (amount > 16)
48 throw new ArgumentException("количетсво ячеек не более 16");
49

50 if (start + amount > 16)


51 throw new ArgumentException("нельзя пытаться вылезти за 16");
52

53 // 16 степеней десятки у нас есть


54 var answer = new TableItem[amount - start];
55

56 // все степени и значения функции при этих аргументах добавляем в


,→ массив
57 for (int i = (int) start; i < amount; i++)
58 answer[i - start] = new TableItem{
59 Input = PowersOfTen[i],
60 Output = Function(PowersOfTen[i])
61 };
62

63 return answer;
64 }
65

66 /// <summary>
67 /// Определяет асимптоту lg-графика.
68 /// </summary>
69 public Asymptote GetAsymptote() =>
70 new Asymptote(Function);
71

72 /// <summary>
73 /// Определяет коэффициент `C` БМФ.
74 /// </summary>
75 public double GetCoefficient() =>
76 Pow(10, GetAsymptote().K);
77 }
78

79 /// <summary>
80 /// Представляет собой ячейку в табличном виде функции.
81 /// </summary>
82 public struct TableItem
83 {
84 /// <summary>
85 /// Аргумент функции.
86 /// </summary>

16
87 public double Input { get; set; }
88

89 /// <summary>
90 /// Значение функции.
91 /// </summary>
92 public double Output { get; set; }
93

94 /// <summary>
95 /// Десятичный логарифм аргумента функции.
96 /// </summary>
97 public double LgInput { get => Log10(Input); }
98

99 /// <summary>
100 /// Десятичный логарифм значения функции.
101 /// </summary>
102 /// <remark>
103 /// Вычисляет логарифм значения по модулю.
104 /// </remark>
105 public double LgOutput { get => Log10(Abs(Output)); }
106 }
107

108 /// <summary>


109 /// Представляет собой асимптоту lg-графика.
110 /// </summary>
111 public class Asymptote
112 {
113 /// <summary>
114 /// Коэфициент при X.
115 /// </summary>
116 public double Alpha { get; set; }
117

118 /// <summary>


119 /// Свободный член.
120 /// </summary>
121 public double K { get; set; }
122

123 /// <summary>


124 /// Создаёт асимптоту
125 /// </summary>
126 /// <param name="function"></param>
127 public Asymptote(Func<double, double> function)
128 {
129 // по сути, коэф находится там, где
130 // если хотя бы два отрезка представляют собой прямую линию;
131 // но предположим, контрольная точка находится на точке lg(h) = -4
132 var left = Pow(10, -4);
133 var right = Pow(10, -4.001);

17
134

135 Alpha = LogOfAbs(function(right) / function(left)) / Log10(right /


,→ left);
136 K = -1 * Log10(right) * LogOfAbs(function(left) / function(right)) /
,→ Log10(left / right) + LogOfAbs(function(right));
137 }
138

139 private double LogOfAbs(double a) =>


140 Log10(Abs(a));
141 }
142 }

18
B Тест анализатора бесконечно малых
1 using NUnit.Framework;
2

3 namespace MathUtilities.Tests
4 {
5 [TestFixture]
6 [TestOf(typeof(InfinitesimalAnalyzer))]
7 public class InfinitesimalAnalyzerTest
8 {
9 private static double[] ExpectedTableInputs = new double[]{
10 1, 1E-01, 1E-02, 1E-03, 1E-04, 1E-05, 1E-06, 1E-07, 1E-08, 1E-09,
,→ 1E-10, 1E-11, 1E-12, 1E-13, 1E-14, 1E-15
11 };
12

13 private static double[] ExpectedTableOutputs = new double[]{


14 1E+01, 1, 1E-01, 1E-02, 1E-03, 1E-04, 1E-05, 1E-06, 1E-07, 1E-08,
,→ 1E-09, 1E-10, 1E-11, 1E-12, 1E-13, 1E-14
15 };
16

17 private static double[] ExpectedTableLgInputs = new double[]{


18 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15
19 };
20

21 private static double[] ExpectedTableLgOutputs = new double[]{


22 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14
23 };
24

25 [Test]
26 public void InfinitesimalTest()
27 {
28 var ia = new InfinitesimalAnalyzer(Function);
29 var got = ia.IsInfinitesimal();
30 Assert.IsTrue(got);
31 }
32

33 [Test]
34 public void NotInfinitesimalTest()
35 {
36 var ia = new InfinitesimalAnalyzer(NotInfinitesimalFunction);
37 var got = ia.IsInfinitesimal();
38 Assert.IsFalse(got);
39 }
40

41 [Test]
42 public void TableRepresentationTest()
43 {

19
44 var ia = new InfinitesimalAnalyzer(Function);
45 var got = ia.GetTableRepresentation();
46

47 for (int i = 0; i < 16; i++)


48 {
49 Assert.AreEqual(ExpectedTableInputs[i], got[i].Input);
50 Assert.IsTrue(Math.Equals(ExpectedTableOutputs[i],
,→ got[i].Output));
51 Assert.AreEqual(ExpectedTableLgInputs[i], got[i].LgInput);
52 Assert.AreEqual(ExpectedTableLgOutputs[i], got[i].LgOutput);
53 }
54 }
55

56 [Test]
57 public void AsymptoteTest()
58 {
59 var ia = new InfinitesimalAnalyzer(Function);
60 var got = ia.GetAsymptote();
61 Assert.AreEqual(got.Alpha, 1);
62 Assert.AreEqual(got.K, 1);
63 }
64

65 [Test]
66 public void CoefficientTest()
67 {
68 var ia = new InfinitesimalAnalyzer(Function);
69 var got = ia.GetCoefficient();
70 Assert.AreEqual(got, 10);
71 }
72

73 public double Function(double x) =>


74 10 * x;
75

76 public double NotInfinitesimalFunction(double x) =>


77 x + 1;
78 }
79

80 [TestFixture]
81 [TestOf(typeof(TableItem))]
82 public class TableItemTest
83 {
84 [Test]
85 [TestCase(1E-4, -4)]
86 public void TestLgInput(double input, double expected)
87 {
88 var ti = new TableItem{Input = input};
89 var got = ti.LgInput;

20
90

91 Assert.AreEqual(expected, got);
92 }
93

94 [Test]
95 [TestCase(1E-4, -4)]
96 public void TestLgOutput(double output, double expected)
97 {
98 var ti = new TableItem{Output = output};
99 var got = ti.LgOutput;
100

101 Assert.AreEqual(expected, got);


102 }
103 }
104

105 [TestFixture]
106 [TestOf(typeof(Asymptote))]
107 public class AsymptoteTest
108 {
109 [Test]
110 public void TestAlpha()
111 {
112 var a = new Asymptote(Function);
113 var expectedAlpha = 1;
114 Assert.AreEqual(expectedAlpha, a.Alpha);
115 }
116

117 [Test]
118 public void TestK()
119 {
120 var a = new Asymptote(Function);
121 var expectedK = 1;
122 Assert.AreEqual(expectedK, a.K);
123 }
124

125 private double Function(double x) =>


126 10 * x;
127 }
128 }

21
C Программный анализ алгоритма пузырьковой сорти-
ровки
1 using System;
2 using static System.Math;
3

4 namespace MathUtilities
5 {
6 /// <summary>
7 /// Реализация алгоритма анализа ББФ с помощью БМФ.
8 /// </summary>
9 public class InfiniteAnalyzer
10 {
11 /// <summary>
12 /// Анализатор бесконечно малой величины.
13 /// </summary>
14 private readonly InfinitesimalAnalyzer _analyzer;
15

16 /// <summary>
17 /// Собственно, сортировка.
18 /// </summary>
19 /// <remark>
20 /// Вместо неё может быть любая ББФ, которая по методу `Sort` возвратит
,→ число.
21 /// </remark>
22 private readonly ISort _sort;
23

24 public InfiniteAnalyzer()
25 {
26 // ББФ := 1 / БМФ(1 / x)
27 _analyzer = new InfinitesimalAnalyzer((x) => (1.0 /
,→ IterationsAmount((int) Round(1 / x))));
28 _sort = new BubbleSort();
29 }
30

31 /// <summary>
32 /// Табличный вид функции.
33 ///
34 /// Определяется с 10 до 10^6. На больших числах выполняется слишком
,→ долго.
35 /// </summary>
36 /// <returns>табличный вид функции</returns>
37 public TableItem[] GetTableRepresentation() =>
38 _analyzer.GetTableRepresentation(1, 6);
39

40

22
41 /// <summary>
42 /// Рассчитывает ассимптоту lg-графика БМФ, которая задана вместо ББФ.
43 /// </summary>
44 /// <returns>асимптота графика</returns>
45 public Asymptote GetAsymptote() =>
46 _analyzer.GetAsymptote();
47

48 /// <summary>
49 /// Рассчитывает коэффициент `C` БМФ, которая задана вместо ББФ.
50 /// </summary>
51 /// <returns></returns>
52 public double GetCoefficient() =>
53 _analyzer.GetCoefficient();
54

55 /// <summary>
56 /// Считает количество перестановок для массива.
57 /// </summary>
58 /// <param name="itemsAmount">количество элементов массива</param>
59 /// <returns>количество перестановок в массиве</returns>
60 private int IterationsAmount(int itemsAmount)
61 {
62 // пустой массив
63 var arr = new int[itemsAmount];
64 // заполняем массив наихудшим случаем
65 for (int i = 0; i < itemsAmount; i++)
66 arr[i] = i;
67 // запускаем сортировку и передаём количество перестановок
68 return _sort.Sort(arr);
69 }
70 }
71

72 /// <summary>
73 /// Интерфейс сортировки.
74 /// </summary>
75 public interface ISort
76 {
77 /// <summary>
78 /// Количество перестановок, произведённых для сортировки.
79 /// </summary>
80 /// <param name="arr">массив для сортировки</param>
81 /// <returns>количество перестановок, произведённых для
,→ сортировки</returns>
82 int Sort(int[] arr);
83 }
84

85

86

23
87 /// <summary>
88 /// Реализация пузырьковой сортировки.
89 /// </summary>
90 public class BubbleSort : ISort
91 {
92 /// <summary>
93 /// Собственно сама сортировка.
94 /// </summary>
95 /// <remark>
96 /// Атрибуция:
,→ https://ru.wikibooks.org/wiki/Примеры_реализации_сортировки_пузырьком
97 /// </remark>
98 /// <param name="arr">массив, который нужно отсортировать</param>
99 /// <returns>количество перестановок</returns>
100 public int Sort(int[] arr)
101 {
102 // изначально перестановок нет
103 int counter = 0;
104 for (int i = 0; i < arr.Length - 1; i++)
105 {
106 for (int j = 0; j < arr.Length - i - 1; j++)
107 {
108 if (arr[j+1] > arr[j])
109 {
110 swap(ref arr[j], ref arr[j+1]);
111 counter++;
112 }
113 }
114 }
115 // передать количество перестановок
116 return counter;
117 }
118

119 /// <summary>


120 /// Типичная перестановка значений переменных.
121 /// </summary>
122 /// <param name="a">первая переменная</param>
123 /// <param name="b">вторая переменная</param>
124 private static void swap(ref int a, ref int b)
125 {
126 b += a;
127 a -= b;
128 b -= a;
129 }
130 }
131 }

24
D Тест анализатора пузырьковой сортировки
1 using static System.Math;
2 using NUnit.Framework;
3

4 namespace MathUtilities.Tests
5 {
6 [TestFixture]
7 [TestOf(typeof(InfiniteAnalyzer))]
8 public class InfiniteAnalyzerTest
9 {
10 [Test]
11 public void TestAsymptote()
12 {
13 var ia = new InfiniteAnalyzer();
14 var a = ia.GetAsymptote();
15 Assert.AreEqual(2, Round(a.Alpha));
16 }
17 }
18 }

25
E Программный анализ БМФ многих переменных
1 using static System.Math;
2 using System;
3

4 namespace MathUtilities
5 {
6 /// <summary>
7 /// Работа с функцией многих переменных.
8 /// </summary>
9 public class MultivariateAnalyzer
10 {
11 /// <summary>
12 /// Функция многих переменных для рассмотрения.
13 /// </summary>
14 private readonly Func<Vector, double> _multivariateFunction;
15

16 /// <summary>
17 /// Точка рассмотрения. В задаче - просто X_0.
18 /// </summary>
19 private readonly Vector _pointOfView;
20

21 /// <summary>
22 /// Направление движения. В задаче - просто R.
23 /// </summary>
24 private readonly Vector _vector;
25

26 /// <summary>
27 /// Анализатор функции одной переменной.
28 /// </summary>
29 private readonly InfinitesimalAnalyzer _analyzer;
30

31 public MultivariateAnalyzer(
32 Func<Vector, double> multivariateFunction,
33 Vector pointOfView,
34 Vector vector
35 ) {
36 _multivariateFunction = multivariateFunction;
37 _pointOfView = pointOfView;
38 _vector = vector;
39 _analyzer = new InfinitesimalAnalyzer(Function);
40 }
41

42 /// <summary>
43 /// Рассчитывает табличный вид бесконечно малой дополнительной функции.
44 /// </summary>
45 /// <returns></returns>

26
46 public TableItem[] GetTableRepresentation() =>
47 _analyzer.GetTableRepresentation();
48

49 /// <summary>
50 /// Рассчитывает асимптоту бесконечно малой дополнительной функции.
51 /// </summary>
52 /// <returns></returns>
53 public Asymptote GetAsymptote() =>
54 _analyzer.GetAsymptote();
55

56 /// <summary>
57 /// Рассчитывает коэффициент бесконечно малой дополнительной функции.
58 /// </summary>
59 /// <returns></returns>
60 public double GetCoefficient() =>
61 _analyzer.GetCoefficient();
62

63 /// <summary>
64 /// Передаёт точки кругов коэфициента `C`.
65 /// </summary>
66 /// <param name="iterationsAmount">количество точек для
,→ построения</param>
67 /// <returns>точки кругов</returns>
68 public Vector[] GetCircle(int iterationsAmount = 180)
69 {
70 // матрица поворота на 360 / iterations градусов в радианах
71 var rotationMatrix = Math.GetRotationMatrix(PI / 90);
72 // создаём пустой массив
73 var answer = new Vector[iterationsAmount];
74 // копируем вектор сюда
75 var vector = _vector;
76 // такая же функция, что и Function
77 Func<double, double> f;
78

79 // повторяем много раз


80 for (int i = 0; i < iterationsAmount; i++)
81 {
82 // функция с направлением vector
83 f = (t) => _multivariateFunction(_pointOfView + t * vector) -
,→ _multivariateFunction(_pointOfView);
84 // вставляем её в анализатор
85 _analyzer.Function = f;
86 // рассчитываем значение вектора
87 answer[i] = _pointOfView + _analyzer.GetCoefficient() * vector;
88 // поворачиваем вектор
89 vector *= rotationMatrix;
90 }

27
91

92 return answer;
93 }
94

95 /// <summary>
96 /// Дополнительная преобразованная функция многих переменных в БМФ одной
,→ переменной.
97 /// </summary>
98 /// <param name="t">параметр бесконечно малой</param>
99 /// <returns>значение БМФ</returns>
100 private double Function(double t) =>
101 _multivariateFunction(_pointOfView + t * _vector) -
,→ _multivariateFunction(_pointOfView);
102 }
103

104 /// <summary>


105 /// Представляет собой вектор любой длины.
106 /// </summary>
107 public class Vector
108 {
109 /// <summary>
110 /// Массив элементов вектора.
111 /// </summary>
112 /// <value></value>
113 private double[] Items { get; set; }
114

115 /// <summary>


116 /// Длина вектора.
117 /// </summary>
118 public int Length { get => Items.Length; }
119

120 /// <summary>


121 /// Стандартный конструктор задания элементов вектора.
122 /// </summary>
123 /// <param name="items">элементы вектора</param>
124 public Vector(params double[] items) =>
125 this.Items = items;
126

127 public override string ToString() =>


128 string.Join("\t", Items);
129

130 /// <summary>


131 /// Передаёт элемент вектора по индексу.
132 /// </summary>
133 /// <param name="index">индекс элемента вектора</param>
134 /// <returns>элемент вектора в индексе</returns>
135 public double Get(int index) => Items[index];

28
136

137 /// <summary>


138 /// Рассчитывает ортогональный этому вектору вектор.
139 /// </summary>
140 /// <remark>
141 /// Реализован только для R^2.
142 /// </remark>
143 /// <returns>ортогональный вектор</returns>
144 public Vector GetOrth() =>
145 new Vector(Get(1), -1 * Get(0));
146

147 /// <summary>


148 /// Определение оператора сложения векторов.
149 /// </summary>
150 /// <param name="left">левый вектор</param>
151 /// <param name="right">правый вектор</param>
152 /// <returns>сумма векторов - новый вектор</returns>
153 public static Vector operator +(Vector left, Vector right)
154 {
155 if (left.Length != right.Length)
156 throw new ApplicationException("для сложения векторы должны быть
,→ одной длины");
157

158 int length = left.Length;


159 var answer = new double[length];
160 for (int i = 0; i < length; i++)
161 answer[i] = left.Get(i) + right.Get(i);
162 return new Vector(answer);
163 }
164

165 /// <summary>


166 /// Определение оператора разницы векторов.
167 /// </summary>
168 /// <param name="left">уменьшаемый вектор</param>
169 /// <param name="right">вычитаемый вектор</param>
170 /// <returns>разница векторов - новый вектор</returns>
171 public static Vector operator -(Vector left, Vector right)
172 {
173 if (left.Length != right.Length)
174 throw new ApplicationException("для вычитания векторы должны быть
,→ одной длины");
175 int length = left.Length;
176 var answer = new double[length];
177 for (int i = 0; i < length; i++)
178 answer[i] = left.Get(i) - right.Get(i);
179 return new Vector(answer);
180 }

29
181 /// <summary>
182 /// Определение операции скалярного произведения векторов.
183 /// </summary>
184 /// <param name="left">левый вектор</param>
185 /// <param name="right">правый вектор</param>
186 /// <returns>скалярное произведение векторов - число</returns>
187 public static double operator *(Vector left, Vector right)
188 {
189 if (left.Length != right.Length)
190 throw new ApplicationException("для произведения векторы должны
,→ быть одной длины");
191

192 int length = left.Length;


193 double answer = 0;
194 for (int i = 0; i < length; i++)
195 answer += left.Get(i) * right.Get(i);
196 return answer;
197 }
198

199 /// <summary>


200 /// Определение операции произведения числа на вектор.
201 /// </summary>
202 /// <param name="number">число</param>
203 /// <param name="vector">вектор</param>
204 /// <returns>произведение - новый вектор</returns>
205 public static Vector operator *(double number, Vector vector)
206 {
207 int length = vector.Length;
208 var answer = new double[length];
209 for (int i = 0; i < length; i++)
210 answer[i] = number * vector.Get(i);
211 return new Vector(answer);
212 }
213

214 public static Vector operator *(Vector vector, Matrix matrix)


215 {
216 if (vector.Length != matrix.Length)
217 throw new ApplicationException("для произведения вектор и матрица
,→ должны быть одной длины");
218 int length = vector.Length;
219 var answer = new double[length];
220 for (int i = 0; i < length; i++)
221 {
222 answer[i] = 0;
223 for (int j = 0; j < length; j++)
224 answer[i] += vector.Get(j) * matrix.Get(j, i);
225 }

30
226 return new Vector(answer);
227 }
228 }
229

230 /// <summary>


231 /// Класс, представляющий матрицу.
232 ///
233 /// Прим.: все функции работают только с квадратными матрицами.
234 /// Прим.: некоторые функции работают только с матрицей 2 на 2.
235 /// </summary>
236 public class Matrix
237 {
238 /// <summary>
239 /// Разделитель элементов матрицы в строковом представлении.
240 /// </summary>
241 private const string ITEM_DELIMITER = ", ";
242

243 /// <summary>


244 /// Разделитель строк матрицы в строковом представлении.
245 /// </summary>
246 private const string ROW_DELIMITER = "\n";
247

248 /// <summary>


249 /// Элементы матрицы.
250 /// </summary>
251 public double[][] items { get; private set; }
252

253 /// <summary>


254 /// Стандартный конструктор.
255 /// </summary>
256 /// <param name="items">двумерный массив элементов матрицы</param>
257 public Matrix(double[][] items)
258 {
259 if (items.Length != items[0].Length)
260 throw new ArgumentException("матрица должна быть квадратной");
261

262 this.items = items;


263 }
264

265 /// <summary>


266 /// Элемент матрицы в индексах.
267 /// </summary>
268 /// <param name="index1">столбец</param>
269 /// <param name="index2">строка</param>
270 public double Get(int index1, int index2) =>
271 items[index1][index2];
272

31
273 /// <summary>
274 /// Длина стороны матрицы.
275 /// </summary>
276 public int Length =>
277 items.Length;
278

279 /// <summary>


280 /// Переопределение преобразования в строку:
281 /// все элементы через запятую, строки через перевод строки.
282 /// </summary>
283 public override string ToString()
284 {
285 int length = Length;
286 var arr = new string[length];
287 for (int i = 0; i < length; i++)
288 arr[i] = String.Join(ITEM_DELIMITER, items[i]);
289 return String.Join(ROW_DELIMITER, arr);
290 }
291

292 /// <summary>


293 /// Умножение матрицы на вектор.
294 /// </summary>
295 /// <param name="matrix">матрица</param>
296 /// <param name="vector">вектор</param>
297 /// <returns>произведение - новый вектор</returns>
298 public static Vector operator *(Matrix matrix, Vector vector)
299 {
300 int length = vector.Length;
301 var items = new double[length];
302 Vector temp;
303

304 // просто перемножаем строки на вектор,


305 // так как строки матрицы - такие же векторы
306 for (int i = 0; i < length; i++)
307 {
308 temp = new Vector(matrix.items[i]);
309 items[i] = temp * vector;
310 }
311

312 return new Vector(items);


313 }
314

315 /// <summary>


316 /// Передаёт обратную матрицу.
317 ///
318 /// Здесь представлена только оптимизированная версия для матрицы 2×2.
319 /// </summary>

32
320 /// <returns>обратная матрице матрица</returns>
321 public Matrix GetReversed()
322 {
323 // получаем определитель матрицы
324 var det = GetSmallDeterminant();
325 // создаём пустой двумерный массив
326 var matrix = new double[2][];
327 // заполняем первую строку по формуле
328 matrix[0] = new double[2];
329 matrix[0][0] = items[1][1] / det;
330 matrix[0][1] = -1 * items[0][1] / det;
331 // заполняем вторую строку по формуле
332 matrix[1] = new double[2];
333 matrix[1][0] = -1 * items[1][0] / det;
334 matrix[1][1] = items[0][0] / det;
335 return new Matrix(matrix);
336 }
337

338 /// <summary>


339 /// Считает определитель этой матрицы по оптимизированной формуле для
,→ матрицы 2 на 2.
340 /// </summary>
341 /// <returns>определитель матрицы</returns>
342 public double GetSmallDeterminant() =>
343 items[0][0] * items[1][1] - items[0][1] * items[1][0];
344 }
345

346 /// <summary>


347 /// Класс для отдельных математических операций.
348 /// </summary>
349 public static class Math
350 {
351 /// <summary>
352 /// Рассчитывает матрицу поворота вектора на заданный угол в радианах.
353 /// </summary>
354 /// <param name="angle">угол в радианах</param>
355 /// <returns>матрица поворота</returns>
356 public static Matrix GetRotationMatrix(double angle)
357 {
358 var matrixAsArray = new double[2][];
359 matrixAsArray[0] = new double[]{Cos(angle), Sin(angle)};
360 matrixAsArray[1] = new double[]{-1 * Sin(angle), Cos(angle)};
361 return new Matrix(matrixAsArray);
362 }
363 }
364 }

33
F Тест анализатора БМФ многих переменных
1 using static System.Math;
2 using NUnit.Framework;
3

4 namespace MathUtilities.Tests
5 {
6 [TestFixture]
7 [TestOf(typeof(MultivariateAnalyzer))]
8 public class MultivariateAnalyzerTest
9 {
10 private const int V = 6;
11 private static Vector vec = new Vector(1 / Sqrt(10), 3 / Sqrt(10));
12

13 [Test]
14 public void Test()
15 {
16 var ma = new MultivariateAnalyzer(
17 Function,
18 new Vector(1, 1),
19 vec
20 );
21 var alpha1 = ma.GetAsymptote().Alpha;
22

23 ma = new MultivariateAnalyzer(
24 Function,
25 new Vector(1, 1),
26 vec.GetOrth()
27 );
28 var alpha2 = ma.GetAsymptote().Alpha;
29

30 Assert.IsTrue(alpha2 > alpha1);


31 }
32

33 private double Function(Vector vector) =>


34 Pow(vector.Get(0), 2) - V * Sqrt(vector.Get(0) * vector.Get(1));
35 }
36

37 [TestFixture]
38 [TestOf(typeof(Vector))]
39 public class VectorTest
40 {
41 [Test]
42 [TestCase(new double[]{7.9, 9.1}, 1, 9.1)]
43 public void TestGet(double[] arr, int index, double expected)
44 {
45 var v = new Vector(arr);

34
46 var got = v.Get(index);
47 Assert.AreEqual(got, expected);
48 }
49

50 [Test]
51 [TestCase(new double[]{7, 2, 1, 9}, 4)]
52 public void TestLength(double[] arr, int expected)
53 {
54 var v = new Vector(arr);
55 var got = v.Length;
56 Assert.AreEqual(expected, got);
57 }
58

59 [Test]
60 [TestCase(new double[]{1, 1}, new double[]{1, -1})]
61 [TestCase(new double[]{5, 10}, new double[]{10, -5})]
62 public void TestOrth(double[] arr, double[] expected)
63 {
64 var v = new Vector(arr);
65 var got = v.GetOrth();
66 for (int i = 0; i < 2; i++)
67 Assert.AreEqual(expected[i], got.Get(i));
68 }
69

70 [Test]
71 [TestCase(new double[]{1, 1})]
72 [TestCase(new double[]{5, 10})]
73 public void AltTestOrth(double[] arr)
74 {
75 var v = new Vector(arr);
76 var orth = v.GetOrth();
77 var got = v * orth;
78 Assert.AreEqual(0, got);
79 }
80

81 [Test]
82 [TestCase(new double[]{1, 2}, new double[]{5, 7}, new double[]{6, 9})]
83 public void TestSum(double[] leftArray, double[] rightArray, double[]
,→ expected)
84 {
85 var left = new Vector(leftArray);
86 var right = new Vector(rightArray);
87 var got = left + right;
88 for (int i = 0; i < got.Length; i++)
89 Assert.AreEqual(expected[i], got.Get(i));
90 }
91

35
92 [Test]
93 [TestCase(new double[]{1, 2}, new double[]{1, 2, 3})]
94 public void TestSumException(double[] leftArray, double[] rightArray)
95 {
96 var left = new Vector(leftArray);
97 var right = new Vector(rightArray);
98

99 Assert.Throws<ApplicationException>(() => { var a = left + right; });


100 }
101

102 [Test]
103 [TestCase(new double[]{5, 7}, new double[]{4, 5}, new double[]{1, 2})]
104 public void TestMinus(double[] leftArray, double[] rightArray, double[]
,→ expected)
105 {
106 var left = new Vector(leftArray);
107 var right = new Vector(rightArray);
108 var got = left - right;
109 for (int i = 0; i < got.Length; i++)
110 Assert.AreEqual(expected[i], got.Get(i));
111 }
112

113 [Test]
114 [TestCase(new double[]{1, 2}, new double[]{1, 2, 3})]
115 public void TestMinusException(double[] leftArray, double[] rightArray)
116 {
117 var left = new Vector(leftArray);
118 var right = new Vector(rightArray);
119

120 Assert.Throws<ApplicationException>(() => { var a = left - right; });


121 }
122

123 [Test]
124 [TestCase(new double[]{1, 2}, new double[]{5, 7}, 19)]
125 public void TestMultiplication(double[] leftArray, double[] rightArray,
,→ double expected)
126 {
127 var left = new Vector(leftArray);
128 var right = new Vector(rightArray);
129 var got = left * right;
130 Assert.AreEqual(expected, got);
131 }
132

133 [Test]
134 [TestCase(new double[]{1, 2}, new double[]{1, 2, 3})]
135 public void TestMultiplicationException(double[] leftArray, double[]
,→ rightArray)

36
136 {
137 var left = new Vector(leftArray);
138 var right = new Vector(rightArray);
139

140 Assert.Throws<ApplicationException>(() => { var a = left * right; });


141 }
142

143 [Test]
144 [TestCase(2, new double[]{4, 5}, new double[]{8, 10})]
145 public void TestMultiplicationWithNumber(double number, double[] arr,
,→ double[] expected)
146 {
147 var v = new Vector(arr);
148 var got = number * v;
149 for (int i = 0; i < got.Length; i++)
150 Assert.AreEqual(expected[i], got.Get(i));
151 }
152

153 [Test]
154 [TestCase(new double[]{4, 2}, new double[]{46, 50})]
155 public void TestMult(double[] arr, double[] expected)
156 {
157 var v = new Vector(arr);
158 var arr1 = new double[]{7, 12};
159 var arr2 = new double[]{9, 1};
160 var matrixArray = new double[2][];
161 matrixArray[0] = arr1;
162 matrixArray[1] = arr2;
163 var m = new Matrix(matrixArray);
164 var got = v * m;
165

166 for (int i = 0; i < 2; i++)


167 Assert.AreEqual(expected[i], got.Get(i));
168 }
169 }
170

171 [TestFixture]
172 [TestOf(typeof(Matrix))]
173 public class MatrixTest
174 {
175 public Matrix matrix;
176

177 [SetUp]
178 public void Init()
179 {
180 var arr = new double[2][];
181 arr[0] = new double[]{1, 2};

37
182 arr[1] = new double[]{3, 4};
183 matrix = new Matrix(arr);
184 }
185

186 [Test]
187 public void TestGet()
188 {
189 Assert.AreEqual(1, matrix.Get(0,0));
190 Assert.AreEqual(2, matrix.Get(0,1));
191 Assert.AreEqual(3, matrix.Get(1,0));
192 Assert.AreEqual(4, matrix.Get(1,1));
193 }
194

195 [Test]
196 public void TestLength()
197 {
198 Assert.AreEqual(2, matrix.Length);
199 }
200

201 [Test]
202 public void TestReversed()
203 {
204 var arr = new double[2][];
205 arr[0] = new double[]{-2, 1};
206 arr[1] = new double[]{1.5, -0.5};
207 var expected = new Matrix(arr);
208 var got = matrix.GetReversed();
209

210 for (int i = 0; i < 2; i++)


211 for (var j = 0; j < 2; j++)
212 Assert.AreEqual(expected.Get(i, j), got.Get(i, j));
213 }
214

215 [Test]
216 [TestCase(new double[]{4, 2}, new double[]{8, 20})]
217 public void TestMultVecToMatrix(double[] vecArr, double[] expected)
218 {
219 var v = new Vector(vecArr);
220 var got = matrix * v;
221 for (int i = 0; i < vecArr.Length; i++)
222 Assert.AreEqual(expected[i], got.Get(i));
223 }
224 }
225

226 [TestFixture]
227 [TestOf(typeof(Math))]
228 public class MathTest

38
229 {
230 [Test]
231 public void TestRotationMatrix()
232 {
233 var arr = new double[2][];
234 arr[0] = new double[]{0, 1};
235 arr[1] = new double[]{-1, 0};
236 var expected = new Matrix(arr);
237

238 // PI / 2 = 90\deg
239 var got = Math.GetRotationMatrix(PI / 2);
240

241 for (int i = 0; i < 2; i++)


242 for (var j = 0; j < 2; j++)
243 Assert.AreEqual(expected.Get(i, j), got.Get(i, j), 1E-4);
244 }
245 }
246 }

39

Вам также может понравиться