class Polynomial { constructor(mod, coefArray) { this.mod = mod; this.degree = (coefArray.length - 1); this.coefficients = coefArray; } } exports.Class = Polynomial; function get_mod(p1, p2) { let n; if (p1.mod !== p2.mod) { throw "different modulo" } else { return p1.mod; } } function prepare(p1, p2) { let n = get_mod(p1, p2); let len_p1 = p1.coefficients.length; let len_p2 = p2.coefficients.length; result = new Array(Math.max(len_p1, len_p2)).fill(0); if (len_p1 > len_p2) { for (let x = 0; x < len_p1 - len_p2; x++) p2.coefficients.push(0); } else { for (let x = 0; x < len_p2 - len_p1; x++) p1.coefficients.push(0); } return { result, n }; } function add(p1, p2) { let { result, n } = prepare(p1, p2); for (let i = 0; i < result.length; i++) { result[i] = (p1.coefficients[i] + p2.coefficients[i]) % n; } return new Polynomial(n, result); } exports.add = add; function sub(p1, p2) { let { result, n } = prepare(p1, p2); for (let i = 0; i < result.length; i++) { result[i] = (p1.coefficients[i] - p2.coefficients[i]) % n; } return new Polynomial(n, result); } exports.sub = sub; function sub(p1, p2) { let n = get_mod(p1, p2); let len_p1 = p1.coefficients.length; let len_p2 = p2.coefficients.length; result = new Array(Math.max(len_p1, len_p2)).fill(0); if (len_p1 > len_p2) { for (let x = 0; x < len_p1 - len_p2; x++) p2.coefficients.push(0); } else { for (let x = 0; x < len_p2 - len_p1; x++) p1.coefficients.push(0); } for (let i = 0; i < result.length; i++) { result[i] = (p1.coefficients[i] - p2.coefficients[i]) % n; } return new Polynomial(n, result); } exports.add = add; function multiply(p1, p2) { let n = get_mod(p1, p2); let f = p1.coefficients; let g = p2.coefficients; result = new Array(f.length + g.length - 1).fill(0); let tmp = []; for (let i = 0; i < f.length; i++) { for (let j = 0; j < g.length; j++) { result[i + j] += f[i] * g[j]; } } return new Polynomial(n, result.map(x => (x % n) + (x < 0 ? n : 0))); } exports.multiply = multiply; function power(p1, pow) { let result = p1; for (let i = 1; i < pow; i++) { result = multiply(result, p1); } return result; } exports.power = power; function divide(p1, p2) { let n; if (p1.mod !== p2.mod) { throw "different modulo" } else { n = p1.mod; } let inverse = (x) => { for (let i = 1; i < 2; i++) { let r = (i * x) % 2; if (r == 1) return i else throw "divisionError" } } if (p1.degree < p2.degree) return p1; let f = p1.coefficients; let g = p2.coefficients; let g_lead_coef = g[g.length - 1]; let g_deg = p2.degree; while (f.length >= g.length) { let f_lead_coef = f[f.length - 1]; let tmp_coef = f_lead_coef * inverse(g_lead_coef); let tmp_exp = f.length - 1 - g_deg; let tmp = []; for (let i = 0; i < tmp_exp; i++) { tmp.push(0); } tmp.push(tmp_coef); tmp_poly = new Polynomial(n, tmp); let sub = multiply(p2, tmp_poly, n); let tmp_f = []; for (let i = 0; i < f.length; i++) { for (let j = 0; j < sub.coefficients.length; j++) { if (i == j) tmp_f.push(f[i] - sub.coefficients[j]); } } f = tmp_f.map(x => (x % n) + (x < 0 ? n : 0)); while (f && f[f.length - 1] === 0) f.pop(); } return new Polynomial(n, f); } exports.divide = divide; function gcd(p1, p2) { if (p2.coefficients.length === 0) { return p1; } return gcd(p2, divide(p1, p2)); } exports.gcd = gcd;