Advertisement
MrGhost75

NumericalAnalysis_LAB_1

Mar 21st, 2021
1,035
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 22.13 KB | None | 0 0
  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.text.DecimalFormat;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.Collections;
  8.  
  9.  
  10. // Xj: {-2 0 2 3 4}
  11. // Yj: {3 4 1 2 -1}
  12.  
  13.  
  14. public class Main {
  15.     public static void main(String[] args) throws IOException {
  16.  
  17.         // Поток для чтения:
  18.         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
  19.  
  20.  
  21.         // Считываем значения всех Xj-ых с клавиатуры:
  22.         System.out.println("Введите значения Xj через пробел:");
  23.         String[] string_xjValues = reader.readLine().split("\\s+");
  24.  
  25.  
  26.         // Количество узлов интерполяции:
  27.         int n = string_xjValues.length;
  28.  
  29.  
  30.         // Занесем значения всех Xj-ых в список xjValues типа X:
  31.         ArrayList<X> xjValues = new ArrayList<>();
  32.         for (String string_xjValue : string_xjValues) {
  33.             double coefficient = Double.parseDouble(string_xjValue);
  34.             X newElemX = new X(coefficient, 0);
  35.             xjValues.add(newElemX);
  36.         }
  37.  
  38.  
  39.         // Считываем значения всех Yj-ых с клавиатуры:
  40.         System.out.println("Введите значения Yj через пробел:");
  41.         String[] string_yjValues = reader.readLine().split("\\s+");
  42.  
  43.  
  44.         // Преобразуем значения Yj-ых в целочисленный тип:
  45.         double[] yjValues = new double[n];
  46.         for (int i = 0; i < n; i++) {
  47.             yjValues[i] = Double.parseDouble(string_yjValues[i]);
  48.         }
  49.  
  50.  
  51.  
  52.         // (1). Построим полином Лагранжа:
  53.         ArrayList<X> lagrangePolynomial = X.buildLagrangePolynomial(xjValues, yjValues, n);
  54.  
  55.         // Выведем его на экран:
  56.         System.out.println("\nПолином Лагранжа:\n" + lagrangePolynomial + "\n");
  57.  
  58.  
  59.  
  60.  
  61.         // (2). Построим полином Ньютона:
  62.         ArrayList<X> newtonPolynomial = X.buildNewtonPolynomial(xjValues, yjValues, n);
  63.  
  64.         // Выведем его на экран:
  65.         System.out.println("Полином Ньютона:\n" + newtonPolynomial);
  66.  
  67.  
  68.  
  69.  
  70.         // (3а). Для построения полинома методом найменьших квадратов (Least Square Method, LSM),
  71.         // сначала запросим степень полинома - m (1 <= m < n):
  72.         int m = -1;
  73.         do {
  74.             System.out.print("\nВведите целое число m (Степень полинома Qm(x)), 0 <= m <= " + (n - 1) + ": ");
  75.             m = Integer.parseInt(reader.readLine());
  76.         } while (m < 0 || m > n - 1);
  77.  
  78.         // Построим полином методом найменьших квадратов:
  79.         ArrayList<X> lsmPolynomial = X.buildLSMPolynomial(xjValues, yjValues, n, m);
  80.  
  81.         // Выведем его на экран:
  82.         System.out.println("\nПолином по методу найменьших квадратов степени m = " + m + " :\n" + lsmPolynomial);
  83.  
  84.         // (3б). Теперь найдём среднеквадратическое отклонение:
  85.         double standardDeviationValue = X.standardDeviationLSM(lsmPolynomial, xjValues, yjValues, n);
  86.         System.out.println("\nСреднеквадратическое отклонение = " + standardDeviationValue);
  87.  
  88.  
  89.  
  90.         // (4). Задача экстраполирования.
  91.         // Найдём значения полиномов в точках X(i) = (x(i) + (h(i) / 2)),
  92.         // где h(i) = x(i+1) - x(i), при этом i є [0; n-1].
  93.         // Также найдем значения в точках:
  94.         // X(-1) = x(0) - h(0)/2 и X(n) = x(n) + h(n-1)/2.
  95.  
  96.         // (4.а):
  97.         // Найдём сначала нужные нам точки:
  98.         double[] extrapolateNodes = X.extrapolateNodes(xjValues, n);
  99.         System.out.println("\nТеперь проверим значения в точках: " + Arrays.toString(extrapolateNodes) + "\n");
  100.  
  101.         // (4.б):
  102.         // Значения в этих точках для полинома Лагранжа:
  103.         double[] lagrangeExtrapolateValues = X.extrapolatePolynomialValues(lagrangePolynomial, extrapolateNodes);
  104.         for (int i = 0; i < lagrangeExtrapolateValues.length; i++) {
  105.             //L(Xi) = lagrangeExtrapolateValues[i]
  106.             System.out.println("L(" + extrapolateNodes[i] + ") = " + new DecimalFormat("#.###").format(lagrangeExtrapolateValues[i]));
  107.         }
  108.         System.out.println();
  109.  
  110.         // Значения в этих точках для полинома Ньютона:
  111.         double[] newtonExtrapolateValues = X.extrapolatePolynomialValues(newtonPolynomial, extrapolateNodes);
  112.         for (int i = 0; i < newtonExtrapolateValues.length; i++) {
  113.             //N(Xi) = newtonExtrapolateValues[i]
  114.             System.out.println("N(" + extrapolateNodes[i] + ") = " + new DecimalFormat("#.###").format(newtonExtrapolateValues[i]));
  115.         }
  116.         System.out.println();
  117.  
  118.         // Значения в этих точках для полинома LSM:
  119.         double[] lsmExtrapolateValues = X.extrapolatePolynomialValues(lsmPolynomial, extrapolateNodes);
  120.         for (int i = 0; i < lsmExtrapolateValues.length; i++) {
  121.             //Qm(Xi) = lsmExtrapolateValues[i]
  122.             System.out.println("Qm(" + extrapolateNodes[i] + ") = " + new DecimalFormat("#.###").format(lsmExtrapolateValues[i]));
  123.         }
  124.  
  125.  
  126.         // Закрыть поток для чтения:
  127.         reader.close();
  128.     }
  129. }
  130.  
  131. public class X {
  132.     private double coefficient;
  133.     private final int degree;
  134.  
  135.     //Конструктор для создания переменной x с конкретным коэф-м и показателем степени.
  136.     public X (double coefficient, int degree) {
  137.         this.coefficient = coefficient;
  138.         this.degree = degree;
  139.     }
  140.  
  141.     //Конструктор для создания обычной переменной x.
  142.     public X () {
  143.         this.coefficient = 1;
  144.         this.degree = 1;
  145.     }
  146.  
  147.     //(1). Функция, которая создаёт интерполяционный полином Лагранжа.
  148.     public static ArrayList<X> buildLagrangePolynomial(ArrayList<X> xjValues, double[] yjValues, int n) {
  149.  
  150.         //Пока что пустой интерполяционный полином Лагранжа:
  151.         ArrayList<X> lagrangePolynomial = new ArrayList<>();
  152.  
  153.         //Суммируем все j-е базисные полиномы, умноженные на сооотв. значения Yj-x,
  154.         //получая, таким образом, полином Лагранжа.
  155.         for (int j = 0; j < n; j++) {
  156.  
  157.             double denominator = 1; //знаменатель (число)
  158.             ArrayList<X> nominator = new ArrayList<>(Collections.singletonList(new X(1, 0))); //числитель (полином)
  159.  
  160.  
  161.             //Перемножение всех числителей и знаменателей от 0 до n, не включая индекс j:
  162.             for (int m = 0; m < n; m++) {
  163.                 if (m != j) {
  164.  
  165.                     //Произведение числителей (полином n-1 степени)
  166.                     ArrayList<X> secondBraces = new ArrayList<>(Arrays.asList(new X(), new X((-1) * xjValues.get(m).coefficient, xjValues.get(m).degree)));
  167.                     nominator = multiplyBraces(nominator, secondBraces);
  168.  
  169.                     //Произведение знаменателей (число):
  170.                     denominator *= (xjValues.get(j).coefficient - xjValues.get(m).coefficient);
  171.                 }
  172.             }
  173.  
  174.             //Базисный полином Лагранжа - произведение числителя(полинома) на перевернутый знаменатель(число).
  175.             ArrayList<X> basisPolynomial = X.multiplyNumberAndBrace((1.0 / denominator), nominator);
  176.  
  177.             //Перемножение Yj на базисный полином Лагранжа Lj(x):
  178.             ArrayList<X> multipliedPolynomial = X.multiplyNumberAndBrace(yjValues[j], basisPolynomial);
  179.  
  180.             //Добавляем результат перемножения в выходной полином Лагранжа:
  181.             lagrangePolynomial.addAll(multipliedPolynomial);
  182.         }
  183.  
  184.         //Приведём абсолютно все свободные слагаемые в полиноме Лагранжа:
  185.         cancellation(lagrangePolynomial);
  186.  
  187.         //Возвращаем полином Лагранжа:
  188.         return lagrangePolynomial;
  189.     }
  190.  
  191.     //(2). Функция, которая создаёт интерполяционный полином Ньютона.
  192.     public static ArrayList<X>  buildNewtonPolynomial(ArrayList<X> xjValues, double[] yjValues, int n) {
  193.         /*
  194.         * Полином Ньютона находится по формуле:
  195.         * Pn(x) = ((сумма от k=1 до k=n) произведений f(x0,...,xk)
  196.         * на (произведения от i=0 до i=k-1) (x - xi)), где f(x0) = y0 по условию,
  197.         * а f(x0,...,xk) - разделенная разность k-го порядка,
  198.         * которая представляет собой число.
  199.         */
  200.  
  201.         //Пока что пустой интерполяционный полином Ньютона:
  202.         ArrayList<X> newtonPolynomial = new ArrayList<>();
  203.  
  204.         //Теперь рассчитаем оставшуюся сумму:
  205.         for (int k = 1; k <= n; k++) {
  206.  
  207.             double dividedDifference = 0; // разделенная разность
  208.             ArrayList<X> polynomial = new ArrayList<>(Collections.singletonList(new X(1, 0))); // пока что пустой полином произведения (X - Xi)
  209.  
  210.             //Поиск полинома в виде произведения (X - Xi)
  211.             for (int i = 0; i < k - 1; i++) {
  212.                 ArrayList<X> tempPolynomial = new ArrayList<>(Arrays.asList(new X(), new X((-1) * xjValues.get(i).coefficient, xjValues.get(i).degree)));
  213.                 polynomial = multiplyBraces(polynomial, tempPolynomial);
  214.             }
  215.            
  216.             //Поиск разделенной разности: Сумма (f(Xi) / Произведение(xi - xj))
  217.             for (int i = 0; i < k; i++) {
  218.  
  219.                 double f_xi = yjValues[i]; // Числитель = f(Xi) = Yi
  220.                 double denominator = 1; // Знаменатель = Произведение (xi - xj)
  221.  
  222.                 for (int j = 0; j < k; j++) {
  223.                     if (j != i) {
  224.                         denominator *= (xjValues.get(i).coefficient - xjValues.get(j).coefficient);//(xi - xj)
  225.                     }
  226.                 }
  227.  
  228.                 dividedDifference += (f_xi * (1.0/denominator));
  229.             }
  230.  
  231.             //Умножаем разделенную разность(число) на наш временный полином.
  232.             ArrayList<X> multipliedPolynomial = multiplyNumberAndBrace(dividedDifference, polynomial);
  233.  
  234.             //Добавляем каждое слагаемое (полином (n-1)-й степени) искомой суммы в наш полином Ньютона.
  235.             newtonPolynomial.addAll(multipliedPolynomial);
  236.  
  237.         }
  238.  
  239.         //Приведём абсолютно все свободные слагаемые в полиноме Ньютона:
  240.         cancellation(newtonPolynomial);
  241.  
  242.         //Развернём его в обратном порядке:
  243.         Collections.reverse(newtonPolynomial);
  244.  
  245.         //Возвращаем полином Ньютона:
  246.         return newtonPolynomial;
  247.     }
  248.  
  249.     //(3а). Функция, которая строит интерп. полином методом найменьших квадратов:
  250.     public static ArrayList<X>  buildLSMPolynomial(ArrayList<X> xjValues, double[] yjValues, int n, int m) {
  251.         //Создадим полином
  252.         ArrayList<X> lsmPolynomial = new ArrayList<>();
  253.  
  254.         //Для его нахождения создаём матрицу
  255.         double[][] matrix = new double[m+1][m+2];
  256.  
  257.         //Заполним матрицу, не включая столбец свободных членов, соотв. значениями Ck,
  258.         //которые наход. по формуле:
  259.         //Ck = Сумма от p до n (Xp ^ k), где p є [0; n], k є [0; 2m]
  260.         double ck = 0;
  261.         for (int i = 0; i < m + 1; i++) {
  262.             for (int j = 0, k = i;  j < (m + 1) && k < (m + 1 + i);   j++, k++) {
  263.  
  264.                 //Находим Ck-й коэффициент:
  265.                 for (int p = 0; p < n; p++) {
  266.                     ck += Math.pow(xjValues.get(p).coefficient, k);
  267.                 }
  268.  
  269.                 matrix[i][j] = ck;
  270.                 ck = 0;
  271.             }
  272.         }
  273.  
  274.         //Заполним столбец свободных членов коэф-ми Di,
  275.         //которые рассчит-ся по формуле:
  276.         //Di = Сумма от j до n (f(Xj) * (Xj ^ i)), где j є [0; n], i є [0; m]
  277.         double di = 0;
  278.         for (int i = 0; i < m + 1; i++) {
  279.             for (int j = 0; j < n; j++) {
  280.                 di += (yjValues[j] * Math.pow(xjValues.get(j).coefficient, i));
  281.             }
  282.  
  283.             matrix[i][m+1] = di;
  284.             di = 0;
  285.         }
  286.  
  287.         //Совершаем прямой ход по Гауссу и приводим матрицу к ступенчатому виду
  288.         gaussForward(matrix);
  289.  
  290.         //Найдём коэф-ы ai для нашего искомого полинома обратным ходом по Гауссу:
  291.         double[] aiCoefficients = gaussMethod(matrix);
  292.  
  293.         //Создадим полином М-й степени по полученным коэф-м ai:
  294.         for (int i = 0; i < aiCoefficients.length; i++) {
  295.             lsmPolynomial.add(new X(aiCoefficients[i], i));
  296.         }
  297.  
  298.         //Развернем полином в обратном порядке для читабельности.
  299.         Collections.reverse(lsmPolynomial);
  300.  
  301.         //Вернём полученный полином.
  302.         return lsmPolynomial;
  303.     }
  304.  
  305.     //(3б). Функция, считающая среднеквадратическое отклонение для полинома LSM:
  306.     public static double standardDeviationLSM(ArrayList<X> lsmPolynomial, ArrayList<X> xjValues, double[] yjValues, int n) {
  307.  
  308.         double stdDeviation = 0;
  309.         double tempSum;
  310.  
  311.         for (int j = 0; j < n; j++) {
  312.             tempSum = getPolynomialValue(xjValues.get(j).coefficient, lsmPolynomial);
  313.             stdDeviation += Math.pow((yjValues[j] - tempSum), 2);
  314.         }
  315.  
  316.         stdDeviation = Math.sqrt(stdDeviation / n);
  317.         return stdDeviation;
  318.     }
  319.  
  320.     //(4а). Функция, которая находит нужные узлы экстраполяции на оси ОХ:
  321.     public static double[] extrapolateNodes(ArrayList<X> xjValues, int n) {
  322.         double[] extrapolateNodes = new double[n + 1];
  323.  
  324.         // X(-1) = x(0) - h(0)/2.
  325.         extrapolateNodes[0] = xjValues.get(0).coefficient - ((xjValues.get(1).coefficient - xjValues.get(0).coefficient) / 2);
  326.  
  327.         // X(i) = (x(i) + (h(i) / 2)),
  328.         // где h(i) = x(i+1) - x(i), при этом i є [0; n-1].
  329.         for (int i = 0; i < n - 1; i++) {
  330.             extrapolateNodes[i+1] = xjValues.get(i).coefficient + ((xjValues.get(i+1).coefficient - xjValues.get(i).coefficient) / 2);;
  331.         }
  332.  
  333.         // X(n) = x(n) + h(n-1)/2.
  334.         extrapolateNodes[n] = xjValues.get(n-1).coefficient + ((xjValues.get(n-1).coefficient - xjValues.get(n-2).coefficient) / 2);
  335.  
  336.         return extrapolateNodes;
  337.     }
  338.  
  339.     //(4б). Функция, которая находит значения полинома во всех заданных узлах экстраполяции:
  340.     public static double[] extrapolatePolynomialValues(ArrayList<X> polynomial, double[] extrapolateNodes) {
  341.         double[] polynomialValues = new double[extrapolateNodes.length];
  342.  
  343.         for (int i = 0; i < extrapolateNodes.length; i++) {
  344.             polynomialValues[i] = getPolynomialValue(extrapolateNodes[i], polynomial);
  345.         }
  346.  
  347.         return polynomialValues;
  348.     };
  349.  
  350.     //Получим значение полинома в заданной точке.
  351.     private static double getPolynomialValue(double xj, ArrayList<X> polynomial) {
  352.         double value = 0;
  353.  
  354.         for (X elem: polynomial) {
  355.             value += elem.coefficient * Math.pow(xj, elem.degree);
  356.         }
  357.  
  358.         return value;
  359.     }
  360.  
  361.     //Перемножение двух полиномов(скобок):
  362.     private static ArrayList<X> multiplyBraces(ArrayList<X> firstBraces, ArrayList<X> secondBraces) {
  363.  
  364.         //Результат перемножения 2-х скобок запишем в этот список:
  365.         ArrayList<X> resultBraces = new ArrayList<>();
  366.  
  367.         //Перемножение двух скобок (коэффициенты перемножаем, степени складываем):
  368.         for(X firstElem: firstBraces) {
  369.             for (X secondElem: secondBraces) {
  370.                 double resultCoefficient = firstElem.coefficient * secondElem.coefficient;
  371.                 int resultDegree = firstElem.degree + secondElem.degree;
  372.                 X resultElemX = new X(resultCoefficient, resultDegree);
  373.                 resultBraces.add(resultElemX);
  374.             }
  375.         }
  376.  
  377.         //Приводим подобные слагаемые:
  378.         cancellation(resultBraces);
  379.  
  380.         //Возвращаем полученное произведение в виде полинома(список из объектов типа X)
  381.         return resultBraces;
  382.     }
  383.  
  384.     //Умножение числа на полином(скобку):
  385.     private static ArrayList<X> multiplyNumberAndBrace(double number, ArrayList<X> braces) {
  386.         for (X elem : braces) {
  387.             elem.coefficient *= number;
  388.         }
  389.         return braces;
  390.     }
  391.  
  392.     //Приведение подобных слагаемых:
  393.     private static void cancellation(ArrayList<X> braces) {
  394.         for (int i = 0; i < braces.size(); i++) {
  395.             for (int k = 0; k < braces.size(); k++) {
  396.                 if (
  397.                         (k != i)
  398.                         && (braces.get(k).degree == braces.get(i).degree)
  399.                         && (braces.get(i).coefficient != 0)
  400.                 ) {
  401.                     braces.get(i).coefficient += braces.get(k).coefficient;
  402.                     braces.get(k).coefficient = 0;
  403.                 }
  404.             }
  405.         }
  406.         //Уберём все элементы, у которых коэффициент обнулен.
  407.         braces.removeIf(elem -> (Math.abs(elem.coefficient) <= 0.00001));
  408.     }
  409.  
  410.     //Функция сдвига заданной строки в конец.
  411.     private static void changeRows(double[][] matrix, int position) {
  412.         int n = matrix.length;
  413.         double[] temp = matrix[position];
  414.         for (int i = position; i < n - 1; i++) {
  415.             matrix[i] = matrix[i + 1]; //каждой строке, начиная с заданной, присвоим строку, что стоит после неё.
  416.         }
  417.         matrix[n-1] = temp;
  418.     }
  419.  
  420.     //Функция прямого хода по Гауссу.
  421.     private static void gaussForward(double[][] matrix) {
  422.         int n = matrix.length;
  423.         int m = matrix[0].length;
  424.  
  425.         double delta;
  426.         for (int k = 0; k < n; k++) {
  427.             for (int i = k + 1; i < n; i++) {
  428.                 while(matrix[k][k] == 0) {
  429.                     changeRows(matrix, k);
  430.                 }
  431.                 delta = matrix[i][k] / matrix[k][k]; // формула (1)
  432.                 for (int j = k; j < m; j++) {
  433.                     matrix[i][j] -= delta * matrix[k][j]; // формула (2)
  434.                 }
  435.             }
  436.         }
  437.     }
  438.  
  439.     //Метод Гаусса обратный.
  440.     private static double[] gaussMethod(double[][] matrix) {
  441.         int n = matrix.length;
  442.         int m = matrix[0].length;
  443.         double[] result = new double[m-1];
  444.  
  445.         double[] b = new double[n];//Столбец свободных членов
  446.         for (int i = 0; i < n; i++) {
  447.             b[i] = matrix[i][m - 1];
  448.         }
  449.  
  450.         for (int i = n - 1; i >= 0; i--) {
  451.             double sum = 0.0;
  452.             for (int j = i + 1; j < n; j++) {
  453.                 sum += matrix[i][j] * result[j];
  454.             }
  455.             result[i] = (b[i] - sum) / matrix[i][i];
  456.         }
  457.         return result;
  458.     }
  459.  
  460.     @Override
  461.     public String toString() {
  462.  
  463.         if (this.degree == 0) //Если показатель степени при Х == 0, то выводим лишь коэффициент.
  464.             //Форматирование коэф. до максимум 5 знаков после запятой
  465.             return "" + new DecimalFormat("#.#####").format(this.coefficient);
  466.  
  467.         /*
  468.         else if(this.coefficient > 0) //Если коэф. больше нуля, то выводим с дополнительным знаком "+".
  469.             //Форматирование коэф. до максимум 5 знаков после запятой
  470.             return "+" + new DecimalFormat("#.#####").format(this.coefficient) + "x^" + this.degree;
  471.         */
  472.  
  473.         else //В других случаях выводим всё без изменений.
  474.             //Форматирование коэф. до максимум 5 знаков после запятой
  475.             return new DecimalFormat("#.#####").format(this.coefficient) + "x^" + this.degree;
  476.     }
  477. }
  478.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement