diff --git a/afanasev_dmitry_lab_6/FastDeterminantCalculator.java b/afanasev_dmitry_lab_6/FastDeterminantCalculator.java new file mode 100644 index 0000000..ed734e5 --- /dev/null +++ b/afanasev_dmitry_lab_6/FastDeterminantCalculator.java @@ -0,0 +1,118 @@ +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class FastDeterminantCalculator { + + public static void main(String[] args) { + int[] sizes = {100, 300, 500}; + int[] threads = {1, 4, 8, 10}; + + for (int size : sizes) { + BigDecimal[][] matrix = generateMatrix(size); + for (int threadCount : threads) { + long start = System.currentTimeMillis(); + BigDecimal determinant = calculateDeterminant(matrix, threadCount); + long end = System.currentTimeMillis(); + System.out.printf("Matrix size: %dx%d, Threads: %d, Time: %d ms\n", + size, size, threadCount, (end - start)); + } + } + } + + public static BigDecimal[][] generateMatrix(int size) { + BigDecimal[][] matrix = new BigDecimal[size][size]; + for (int i = 0; i < size; i++) { + BigDecimal rowSum = BigDecimal.ZERO; + for (int j = 0; j < size; j++) { + matrix[i][j] = BigDecimal.valueOf(Math.random() * 10); + if (i != j) { + rowSum = rowSum.add(matrix[i][j]); + } + } + matrix[i][i] = rowSum.add(BigDecimal.valueOf(Math.random() * 10 + 1)); + } + return matrix; + } + + public static BigDecimal calculateDeterminant(BigDecimal[][] matrix, int threadCount) { + int size = matrix.length; + BigDecimal[][] lu = new BigDecimal[size][size]; + int[] permutations = new int[size]; + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + + if (!luDecomposition(matrix, lu, permutations, executor)) { + executor.shutdown(); + return BigDecimal.ZERO; // Матрица вырожденная + } + + executor.shutdown(); + + BigDecimal determinant = BigDecimal.ONE; + for (int i = 0; i < size; i++) { + determinant = determinant.multiply(lu[i][i]); + if (permutations[i] != i) { + determinant = determinant.negate(); // Меняем знак при перестановке + } + } + return determinant; + } + + public static boolean luDecomposition(BigDecimal[][] matrix, BigDecimal[][] lu, int[] permutations, ExecutorService executor) { + int size = matrix.length; + + for (int i = 0; i < size; i++) { + System.arraycopy(matrix[i], 0, lu[i], 0, size); + permutations[i] = i; + } + + for (int k = 0; k < size; k++) { + int pivot = k; + for (int i = k + 1; i < size; i++) { + if (lu[i][k].abs().compareTo(lu[pivot][k].abs()) > 0) { + pivot = i; + } + } + + if (lu[pivot][k].abs().compareTo(BigDecimal.valueOf(1e-10)) < 0) { + return false; + } + + if (pivot != k) { + BigDecimal[] temp = lu[k]; + lu[k] = lu[pivot]; + lu[pivot] = temp; + + int tempPerm = permutations[k]; + permutations[k] = permutations[pivot]; + permutations[pivot] = tempPerm; + } + + CountDownLatch latch = new CountDownLatch(size - k - 1); + for (int i = k + 1; i < size; i++) { + int row = i; + int finalK = k; + executor.submit(() -> { + MathContext mc = new MathContext(20, RoundingMode.HALF_UP); + lu[row][finalK] = lu[row][finalK].divide(lu[finalK][finalK], mc); + for (int j = finalK + 1; j < size; j++) { + lu[row][j] = lu[row][j].subtract(lu[row][finalK].multiply(lu[finalK][j], mc)); + } + latch.countDown(); + }); + } + + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + return true; + } +} diff --git a/afanasev_dmitry_lab_6/README.md b/afanasev_dmitry_lab_6/README.md new file mode 100644 index 0000000..2e7e3c9 --- /dev/null +++ b/afanasev_dmitry_lab_6/README.md @@ -0,0 +1,31 @@ +# Лабораторная работа 6 + +## Описание +Задание заключается в реализации алгоритмов нахождения детерминанта квадратной матрицы. Необходимо разработать два алгоритма: последовательный и параллельный. А также провести бенчмарки, а затем описать результаты в отчете. + +**100x100 матрица**: +- **8 потоков** — наилучший результат. +- **10 потоков** — результат немного хуже. +- **4 потока** — примерно такой же результат как на 10 потоках. +- **1 поток** — наихудший результат. + +**300x300 матрица**: +- **10 потока** — лучший результат. +- **8 потоков** — чуть хуже. +- **4 потока** — ещё медленее. +- **1 поток** — наихудший результат. + +**500x500 матрица**: +- **10 потока** — лучший результат. +- **8 потоков** — чуть хуже. +- **4 потока** — ещё медленее. +- **1 поток** — наихудший результат. + +**Ссылка на демонстрацию работы программы**: https://vkvideo.ru/video215756667_456239456?list=ln-W6TTsYuIRdX8ft7ADr + +**Вывод**: +- Если операция сложнее, рост производительности происходит с увеличением числа потоков. +- Слишком много потоков увеличивает накладные расходы (замтено только на неочень сложных операциях). Это может быть связано, например, с: +1. **Переключением контекстов**: Когда потоков больше, чем ядер процессора, операционная система часто переключает контексты, что занимает время. +2. **Конкуренцией за ресурсы**: Много потоков конкурируют за ограниченные ресурсы, такие как процессорное время и кэш. +3. **Управлением потоками**: С увеличением числа потоков растёт нагрузка на систему, связанную с их созданием, управлением и завершением.