FileName.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <malloc.h>
  5. #include <stdlib.h>
  6. // Нахождение r1 (Равна значению функции)
  7. double findr1(double x, double y) {
  8. return sqrt(x) * y;
  9. }
  10. // Нахождение r2 и r3
  11. double findr23(double h, double x, double y, double r) {
  12. x = x + (h / 2);
  13. y = y + (r / 2);
  14. return findr1(x, y);
  15. }
  16. // Нахождение r4
  17. double findr4(double h, double x, double y, double r3) {
  18. x = x + h;
  19. y = y + r3;
  20. return findr1(x, y);
  21. }
  22. // 1. Метод Рунге-Кутты
  23. void RungeKutty() {
  24. // исходные параметры
  25. int a = 0; // начало отрезка
  26. int b = 4; // конец отрезка
  27. double x = 0; //x0
  28. double y = 1; //y0
  29. double h = 0.2; // шаг
  30. int n = (b - a) / h; // количество шагов
  31. double r1, r2, r3, r4; // доп. значения
  32. // цикл для решения ду методом Рунге-Кутты
  33. for (int i = 0; i <= n; i++) {
  34. //Вывод найденных значений
  35. printf("%3d\t x = %.2f\t y = %.5f\n", i, x, y);
  36. //Нахождение дополнительных значений
  37. r1 = h * findr1(x, y);
  38. r2 = h * findr23(h, x, y, r1);
  39. r3 = h * findr23(h, x, y, r2);
  40. r4 = h * findr4(h, x, y, r3);
  41. //Переход на следующее значение функции и следующее значение аргумента
  42. y = y + (r1 + (2 * r2) + (2 * r3) + r4) / 6;
  43. x = x + h;
  44. }
  45. }
  46. // Нахождения интеграла методом Парабол
  47. double Integral(double* x, double* y, double a, double b, double h, int n, int root) {
  48. double SumEven = 0; // сумма четных
  49. double SumOdd = 0; // сумма нечетных
  50. double Integ = 0; // интеграл
  51. for (int i = 0; i <= n; i++) {
  52. //Вывод найденных значений
  53. printf("%3d\t x = %.5f\t y = %.5f\n", i, x[i], y[i]);
  54. //Нахождение дополнительных значений
  55. if (y[i] == 0)
  56. {
  57. printf("Корень x = %.5f\t y = %.5f\n", x[i], y[i]);
  58. root = 1;
  59. break;
  60. }
  61. if (i != 0 && i != n)
  62. {
  63. if (i % 2 == 0)
  64. SumEven = SumEven + y[i];
  65. else
  66. SumOdd = SumOdd + y[i];
  67. }
  68. //Переход на следующее значение функции и следующее значение аргумента
  69. x[i + 1] = x[i] + h;
  70. y[i + 1] = sin(2.0 * x[i + 1] + 1.0);
  71. }
  72. Integ = (b - a) / (6 * (n / 2)) * ((y[0] + y[n]) + 2.0 * SumEven + 4.0 * SumOdd);
  73. return Integ;
  74. }
  75. // 2.Метод Парабол
  76. void Parabol() {
  77. double pi = 3.14159265359;
  78. // исходные параметры
  79. double a = 0.0; // начало отрезка
  80. double b = pi / 3.0; // конец отрезка
  81. int n = 10; // количество шагов, (n/2) - число разбиений
  82. double h = (b - a) / n; // шаг
  83. // начальное значение переменных
  84. double* x = calloc(n + 1, sizeof(double)); x[0] = a; //x0
  85. double* y = calloc(n + 1, sizeof(double)); y[0] = sin(2.0 * x[0] + 1.0); //y0
  86. double integral1, integral2;
  87. // Доп. значения
  88. int root = 0; //Если корень найден, то root = 1
  89. double pogresh;
  90. //Ищем интегралы
  91. integral1 = Integral(x, y, a, b, h, n, root);
  92. if (root == 0)
  93. {
  94. printf("Интеграл 1 = %.10f\n", integral1);
  95. //Для оценки погрешности увеличиваем количество шагов(n) в 2 раза:
  96. n = n * 2;
  97. h = (b - a) / n; //пересчитываем шаг
  98. x = realloc(x, (n + 1) * sizeof(double)); x[0] = a; //перезписываем память и x0
  99. y = realloc(y, (n + 1) * sizeof(double)); y[0] = sin(2.0 * x[0] + 1.0); //перезписываем память и y0
  100. integral2 = Integral(x, y, a, b, h, n, root);
  101. if (root == 0)
  102. {
  103. printf("Интеграл 2 = %.10f\n", integral2);
  104. //Ищем погрешность
  105. pogresh = (integral2 - integral1) / 15;
  106. printf("\nПогрешность = %.10f\n", fabs(pogresh)); //fabs выводит моудуль, т.к. abs округляет до 0.
  107. }
  108. }
  109. }
  110. // f(x)
  111. double function(double x) {
  112. return ((3 * pow(x, 2)) - 2 * x - 1);
  113. }
  114. // f'(x)
  115. double derivative(double x) {
  116. return (6 * x - 2);
  117. }
  118. // 3.Метод Хорд
  119. void Chord() {
  120. // Исходные параметры
  121. double a = -10; // начало отрезка
  122. double b = 10; // конец отрезка
  123. double h = 1; // шаг
  124. double* arrX = calloc(0, sizeof(double)); //Подозрения на отрезки изоляции
  125. double* otrX = calloc(0, sizeof(double)); //Отрезки изоляции
  126. // Доп. параметры
  127. int k = 0; // кол-во подозрений на отрезки
  128. int otr = 0; // кол-во отрезков
  129. int flag = 0; //Если знак производной поменяется, то flag = 1
  130. double j = 0; //X на отрезке
  131. int i = 0; //текущий шаг подозрений
  132. int t = 0; //текущий шаг отрезков
  133. int ri = 0; //индекс корней
  134. int root = 0; //Подсчет корней
  135. double* x = calloc(1, sizeof(double)); //искомый корень
  136. double* rootX = calloc(1, sizeof(double)); //все найденные корни
  137. double Fa = 0; //функция от начала отрезка изоляции
  138. double Fb = 0; //функция от конца отрезка изоляции
  139. // Находим отрезки изоляции
  140. for (j = a; j < b; j = j + h) {
  141. if (function(j) * function(j + h) < 0)
  142. {
  143. k++;
  144. arrX = realloc(arrX, (2 * k + 1) * sizeof(double)); // увеличиваем длину массива
  145. //arrX[i] подозрительные на отрезки изоляции
  146. arrX[i] = j; i++;
  147. arrX[i] = j + h; i++;
  148. }
  149. if (function(j) == 0)
  150. {
  151. root++;
  152. rootX = realloc(rootX, root * sizeof(double)); //массив для корней
  153. rootX[ri] = j; ri++;
  154. }
  155. }
  156. if (k == 0 && root == 0)
  157. printf("Кореней нет");
  158. else
  159. {
  160. // Проверка, что производная сохраняет знак на подозрительных отрезках изоляции
  161. double h1 = h / 10; //новый шаг для проверки
  162. for (i = 0; i < 2 * k; i += 2) // перебор подозрений
  163. {
  164. flag = 0;
  165. printf("Подозрительный на отрезок изоляции: [%.2f; %.2f]\n", arrX[i], arrX[i + 1]);
  166. for (j = arrX[i]; j < arrX[i + 1] - h1; j += h1) {
  167. if (derivative(j) * derivative(j + h1) < 0) {
  168. flag = 1; //Знак не сохраняется
  169. break;
  170. }
  171. }
  172. if (flag == 0)
  173. {
  174. printf("[%.2f,%.2f] - Отрезок изоляции\n", arrX[i], arrX[i + 1]);
  175. otr++;
  176. otrX = realloc(otrX, (2 * otr) * sizeof(double));
  177. otrX[t] = arrX[i]; t++;
  178. otrX[t] = arrX[i + 1]; t++;
  179. }
  180. }
  181. //Применение метода хорд
  182. for (int t = 0; t < 2 * otr; t += 2) // перебор отрезков
  183. {
  184. a = otrX[t];
  185. b = otrX[t + 1];
  186. Fb = function(b);
  187. for (i = 0; root < root + 1 * otr; i++) {
  188. x = realloc(x, (i + 1) * sizeof(double));
  189. Fa = function(a);
  190. x[i] = a - ((Fa * (b - a)) / (Fb - Fa));
  191. a = x[i];
  192. if ((round(x[i - 1] * 100000000)) == (round(x[i] * 100000000)))
  193. {
  194. root++;
  195. rootX = realloc(rootX, root * sizeof(double)); //массив для корней
  196. rootX[ri] = x[i]; ri++;
  197. break;
  198. }
  199. }
  200. }
  201. printf("\nОтвет:\n");
  202. // Результат c точностью k = %.7f
  203. for (int i = 0; i < root; i++) //массив корней (ответ)
  204. {
  205. printf("Корень %d = %.7f\n", i + 1, rootX[i]);
  206. }
  207. }
  208. }
  209. // функция вычисления определителя матрицы
  210. double determinant(double** matrix, int n) {
  211. double det = 0;
  212. int znak = 1;
  213. double** minor = calloc((n - 1), sizeof(double*));
  214. for (int i = 0; i < (n - 1); i++) {
  215. minor[i] = calloc((n - 1), sizeof(double));
  216. for (int j = 0; j < (n - 1); j++) {
  217. minor[i][j] = 0;
  218. }
  219. }
  220. if (n == 1)
  221. det = matrix[0][0];
  222. else if (n == 2) //для матрицы 2x2
  223. det = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
  224. else {
  225. for (int k = 0; k < n; k++) { // рекурсивно вычисляем определитель для каждого элемента первой строки
  226. int i = 0;
  227. int j = 0;
  228. if (k % 2 == 0)
  229. znak = 1;
  230. else
  231. znak = -1;
  232. for (int row = 1; row < n; row++) {
  233. for (int col = 0; col < n; col++) {
  234. if (col != k) {
  235. minor[i][j++] = matrix[row][col];
  236. if (j == n - 1) {
  237. j = 0;
  238. i++;
  239. }
  240. }
  241. }
  242. }
  243. det += matrix[0][k] * determinant(minor, n - 1) * znak; // рекурсивный вызов для каждого элемента первой строки
  244. }
  245. }
  246. return det;
  247. }
  248. // 4. Интерполирование функции
  249. void Interpolation() {
  250. // исходные параметры
  251. int degree; // степень искомого многочлена
  252. int n; // найти количество введенных узлов
  253. printf("Введите количество узлов: ");
  254. scanf("%d", &n);
  255. double* arrX = calloc(n, sizeof(double));
  256. double* arrY = calloc(n, sizeof(double));
  257. double mainDet; // определитель матрицы
  258. double* val = calloc(n, sizeof(double)); //Искомые значения
  259. //Ввод узлов
  260. for (int i = 0; i < n; i++) {
  261. printf("x[%d] = ", i);
  262. scanf("%lf", &arrX[i]);
  263. printf("y[%d] = ", i);
  264. scanf("%lf", &arrY[i]);
  265. }
  266. // Заполнение двумерного массива, возводим соответствующие узлы в степени
  267. double** matrix = calloc(n, sizeof(double*));
  268. for (int i = 0; i < n; i++) {
  269. printf("\n");
  270. degree = n - 1;
  271. matrix[i] = calloc(n, sizeof(double));
  272. for (int j = 0; j < n; j++, degree--) {
  273. matrix[i][j] = pow(arrX[i], degree);
  274. printf("%f\t", matrix[i][j]);
  275. }
  276. }
  277. printf("\n");
  278. // Решить СЛУ методом Крамера
  279. mainDet = determinant(matrix, n); // Нахождение определителя матрицы
  280. printf("Определитель матрицы: %.10f\n", mainDet);
  281. for (int column = 0; column < n; column++) {
  282. double** matrixDet = calloc(n, sizeof(double*));
  283. for (int i = 0; i < n; i++) {
  284. matrixDet[i] = calloc(n, sizeof(double));
  285. for (int j = 0; j < n; j++) {
  286. if (j == column) {
  287. matrixDet[i][j] = arrY[i];
  288. }
  289. else
  290. matrixDet[i][j] = matrix[i][j];
  291. }
  292. }
  293. val[column] = (determinant(matrixDet, n)) / mainDet; //Искомые значения
  294. }
  295. //Вывод ответа
  296. printf("\ny = ");
  297. for (int i = 0, j = n - 1; i < n, j >= 0; i++, j--) {
  298. printf("%.2f", val[i]);
  299. if (j > 0)
  300. {
  301. printf("x");
  302. if (j > 1)
  303. printf("^%d", j);
  304. if (val[i + 1] >= 0)
  305. printf("+");
  306. }
  307. }
  308. }
  309. int main() {
  310. system("chcp 1251>nul"); //для работы с русским языком
  311. int n, end;
  312. do
  313. {
  314. printf("\nВыберите нужную тему:");
  315. printf("\n1. Метод Рунге-Кутты");
  316. printf("\n2. Метод Парабол");
  317. printf("\n3. Метод Хорд");
  318. printf("\n4. Интерполирование функции\n");
  319. scanf("%d", &n);
  320. switch (n)
  321. {
  322. case 1: RungeKutty(); break;
  323. case 2: Parabol(); break;
  324. case 3: Chord(); break;
  325. case 4: Interpolation(); break;
  326. default: printf("Такой темы нет\n"); break;
  327. }
  328. printf("\nВы хотите выбрать другую тему? (1 - да, 0 - нет).\n");
  329. scanf("%d", &end);
  330. } while (end > 0);
  331. return 0;
  332. }