Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа 3. 6 вар. Трофимов-2019.pdf
Скачиваний:
190
Добавлен:
19.02.2020
Размер:
119.22 Кб
Скачать

AЛистинг кода метода дихотомии

1using static System.Math;

2using System;

3

4namespace MathUtilities

5{

6

7

8

9

10

11

12

13

14

15

///<summary>

///Находит оптимум функции одной переменной при помощи метода дихотомии.

///</summary>

public class DichotomyOptimizer

{

///<summary>

///Функция для исследования.

///</summary>

private readonly Func<double, double> _function;

16

17

18

19

20

///<summary>

///Начало поиска.

///</summary>

private readonly double _start;

21

22

23

24

25

///<summary>

///Шаг поиска.

///</summary>

private readonly double _step;

26/// <summary>

27/// Точность поиска. Влияет на размер области поиска.

28/// </summary>

29private readonly double _precision;

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

///<summary>

///Максимальное количество операций.

///</summary>

private readonly uint _operationAmount;

///<summary>

///Смотрим ли максимум или минимум.

///</summary>

private readonly bool _lookingForMax;

///<summary>

///Счётчик операций.

///</summary>

private uint counter;

45

11

46/// <summary>

47/// Стандартный конструктор анализатора.

48/// </summary>

49/// <param name="function">функция для исследования</param>

50/// <param name="start">точка начала поиска</param>

51/// <param name="step">шаг поиска</param>

52/// <param name="precision">точность поиска</param>

53/// <param name="operationsAmount">максимальное количество

,! операций</param>

54/// <param name="lookingForMax">смотрим ли максимум или минимум</param>

55public DichotomyOptimizer(

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

Func<double, double> function, double start = 0,

double step = 1E-02, double precision = 1E-04,

uint operationsAmount = 150, bool lookingForMax = false

) {

_function = function; _start = start;

//разворачивает шаг в нужную сторону

//учитывает max / min

_step = function(start + step) > function(start - step) ? lookingForMax ? step : -step

: lookingForMax ? -step : step;

_precision = precision; _operationAmount = operationsAmount; _lookingForMax = lookingForMax;

ResetCounter();

}

78/// <summary>

79/// Рассчитывает оптимальное значение функции.

80/// </summary>

81/// <returns>оптимальное значение функции</returns>

82public double GetOptimal()

83{

84

// узнаём область поиска

85

var triplet = GetArea();

86

// если область поиска маленькая,

87

// не продолжать искать

88

while (!IsTooSmall(triplet))

89

{

90

// если количество операций превысило максимальное, выкинуть

 

,! ошибку

12

91

if (IsCountDown())

92

throw new ApplicationException("не удалось найти оптимального

 

,! решения");

93

 

94

95

96

97

98

99

// делим область на две части: левую и правую

var left = new Triplet {A = triplet.A, B = triplet.Center};

var right = new Triplet {A = triplet.Center, B = triplet.B};

// выбираем лучшую между левой и правой triplet = FindGood(left, right);

}

100

 

101

return triplet.Center;

102

}

103

 

104/// <summary>

105/// Рассчитывает область поиска или кидает исключение по превышении ,! количества операций.

106/// </summary>

107/// <returns>область поиска оптимума</returns>

108public Triplet GetArea()

109{

110

// записываем шаг

поиска

111

var step = _step;

 

112

// создаём тройку

с нуля

113

var triplet = new

Triplet {A = _start, B = _start + step * 2 };

114

// пока не найдём удачную тройку, ищем

115

while (!IsLucky(triplet))

116

{

 

117

// если количество операций превысило максимальное, кинуть

 

,! ошибку

 

118

119

if (IsCountDown())

throw new ApplicationException("не удалось найти область

,! поиска");

120

121

122

123

124

125

126

// двигаем провотиположную A сторону на количество шагов

triplet.B += step;

// удваиваем шаг step *= 2;

}

127

128

129

130

131

132

133

ResetCounter(); return triplet;

}

///<summary>

///Удачна ли тройка для этой функции.

///</summary>

13

134/// <remark>

135/// Учитывает настройку, какой параметр ищем: max / min.

136/// </remark>

137/// <param name="triplet">тройка</param>

138/// <returns>истина, если тройка удачная</returns>

139private bool IsLucky(Triplet triplet) =>

140

141

142

143

144

145

_lookingForMax

? _function(triplet.Center) >= _function(triplet.A) && _function(triplet.Center) >= _function(triplet.B)

: _function(triplet.Center) <= _function(triplet.A) && _function(triplet.Center) <= _function(triplet.B);

146/// <summary>

147/// Узнаёт, не мала ли тройка.

148/// </summary>

149/// <param name="triplet">тройка</param>

150/// <returns>истина, если тройка меньше точности поиска</returns>

151private bool IsTooSmall(Triplet triplet) =>

152

Abs(triplet.B - triplet.A) <= _precision;

153

154

155/// <summary>

156/// Выбирает из двух троек лучшую.

157/// </summary>

158/// <remark>

159/// Учитывает настройку, какой параметр ищем: max / min.

160/// </remark>

161/// <param name="left">одна тройка</param>

162/// <param name="right">другая тройка</param>

163/// <returns>тройка, которая оказалась лучше</returns>

164private Triplet FindGood(Triplet left, Triplet right)

165{

166

// либо

оба лучшие, либо оба не лучшие

167

if (!(IsLucky(left) ^ IsLucky(right)))

168

return

 

169

_lookingForMax

170

 

? _function(left.Center) > _function(right.Center) ? left :

 

 

,!

right

171

 

: _function(left.Center) < _function(right.Center) ? left :

 

 

,!

right;

172

else if

(IsLucky(left))

173

return left;

174

else if

(IsLucky(right))

175

return right;

176

else

 

 

177

throw new ApplicationException($"произошла неизвестная ошибка

 

,!

при выборе между {left} и {right}");

14

178

}

179

180/// <summary>

181/// Увеличивает счётчик на 1 и передаёт, не превысило ли количество ,! операций максимальное.

182/// </summary>

183/// <returns>истина, если количество операций превысило

,! максимальное</returns>

184

185

186

private bool IsCountDown() => counter++ > _operationAmount;

187/// <summary>

188/// Сбрасывает счётчик.

189/// </summary>

190private void ResetCounter() =>

191

counter = 0;

192

}

193

 

194

195

196

197

198

199

200

201

202

203

///<summary>

///Тройка чисел.

///</summary>

public class Triplet

{

///<summary>

///Левая часть тройки.

///</summary>

public double A { get; set; }

204

205

206

207

208

///<summary>

///Правая часть тройки.

///</summary>

public double B { get; set; }

209/// <summary>

210/// Центральная часть тройки.

211/// </summary>

212public double Center { get => A + (B - A) / 2; }

213

214 public override string ToString() =>

215

$"{A} - {Center} - {B}";

216}

217}

15