import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class PolynomialTask { private int n; private List firstPolynomial; private List secondPolynomial; public PolynomialTask(int n, List firstPoly, List secondPoly) { this.n = n; this.firstPolynomial = firstPoly; this.secondPolynomial = secondPoly; } public Integer[] multiplyPolynomials(List firstPolynomial, List secondPolynomial) { int[] multiplied = new int[firstPolynomial.size() + secondPolynomial.size() - 1]; int sizeOfFirstPoly = firstPolynomial.size(); int sizeOfSecondPoly = secondPolynomial.size(); for (int i = 0; i < sizeOfFirstPoly; i++) { for (int j = 0; j < sizeOfSecondPoly; j++) multiplied[i + j] = (multiplied[i + j] + (firstPolynomial.get(i) * secondPolynomial.get(j))) % n; } return Arrays.stream(multiplied).boxed().toArray(Integer[]::new); } public int[] moduloDividePolynomialsReturnQuotient(List firstPoly, List secondPoly) throws MultiplierNotFoundException, DivisionErrorException { int[] quotient = new int[firstPoly.size() + secondPoly.size()]; int firstPolyDegree = firstPoly.size() - 1; int secondPolyDegree = secondPoly.size() - 1; List polynomialAfterSubtract = firstPoly; while (firstPolyDegree >= secondPolyDegree) { polynomialAfterSubtract = calcQuotient(polynomialAfterSubtract, secondPoly, quotient); firstPolyDegree = polynomialAfterSubtract.size() - 1; } int[] remainder = new int[polynomialAfterSubtract.size()]; for (int i = 0; i < polynomialAfterSubtract.size(); i++) { remainder[i] = polynomialAfterSubtract.get(i); } return remainder; } private List calcQuotient(List firstPoly, List secondPoly, int[] quotient) throws MultiplierNotFoundException, DivisionErrorException { int firstPolyDegree = firstPoly.size() - 1; int secondPolyDegree = secondPoly.size() - 1; if (firstPolyDegree < secondPolyDegree) { throw new DivisionErrorException(); } int quotientCoefficient; if ((((float) firstPoly.get(firstPolyDegree) / (float) secondPoly.get(secondPolyDegree))) == Math.round(firstPoly.get(firstPolyDegree) / secondPoly.get(secondPolyDegree))) { quotientCoefficient = firstPoly.get(firstPolyDegree) / secondPoly.get(secondPolyDegree); } else { quotientCoefficient = invElem(firstPoly.get(firstPolyDegree), secondPoly.get(secondPolyDegree)); } quotient[firstPolyDegree - secondPolyDegree] += quotientCoefficient; List newPoly = generatePolyFromIndexAndValue(firstPolyDegree - secondPolyDegree, quotientCoefficient); Integer[] multipliedPolynomials = multiplyPolynomials(newPoly, secondPoly); List polynomialAfterFirstDivide = new ArrayList<>(Arrays.asList(multipliedPolynomials)); return removeUnnecessaryZeros(subtractTwoPolynomials(firstPoly, polynomialAfterFirstDivide)); } private List removeUnnecessaryZeros(List polynomialAfterSubtract) { int amountOfZeros = 0; for (int i = polynomialAfterSubtract.size() - 1; i >= 0; i--) { if (polynomialAfterSubtract.get(i) == 0) { amountOfZeros++; } else { break; } } polynomialAfterSubtract = polynomialAfterSubtract.subList(0, polynomialAfterSubtract.size() - amountOfZeros); return polynomialAfterSubtract; } private List subtractTwoPolynomials(List firstPoly, List secondPoly) { List subtractedPolynomial = new ArrayList<>(Collections.nCopies(firstPoly.size() + secondPoly.size(), 0)); for (int index = firstPoly.size(); index >= 0; index--) { if (index < secondPoly.size()) { subtractedPolynomial.set(index, firstPoly.get(index) - secondPoly.get(index)); parseNegativeElement(subtractedPolynomial, index); } } return subtractedPolynomial; } private void parseNegativeElement(List subtractedPolynomial, int index) { while (subtractedPolynomial.get(index) < 0) subtractedPolynomial.set(index, (subtractedPolynomial.get(index) * subtractedPolynomial.get(index)) % n); } private List generatePolyFromIndexAndValue(int size, int quotientCoefficient) { List poly = new ArrayList<>(Collections.nCopies(size + 1, 0)); poly.set(size, quotientCoefficient); return poly; } private int invElem(int a, int b) throws MultiplierNotFoundException { for (int i = 0; i < n; i++) { if (a == (b * i) % n) { return i; } } throw new MultiplierNotFoundException(); } public void printAllValuesToStandardOutput() throws DivisionErrorException, MultiplierNotFoundException { List> values = new ArrayList<>(); values.add(Arrays.asList(multiplyPolynomials(firstPolynomial, secondPolynomial))); values.add(Arrays.stream(moduloDividePolynomialsReturnQuotient(firstPolynomial, secondPolynomial)).boxed().collect(Collectors.toList())); try { values.add(gcd(firstPolynomial, secondPolynomial)); } catch (MultiplierNotFoundException e) { } System.out.println(values); } private List gcd(List polyOne, List polyTwo) throws MultiplierNotFoundException, DivisionErrorException { if (polyTwo.isEmpty()) return polyOne; List poly = Arrays.stream(moduloDividePolynomialsReturnQuotient(polyOne, polyTwo)).boxed().collect(Collectors.toList()); return gcd(polyTwo, poly); } }