2018-06-29 16:10:38 +02:00
|
|
|
class Polynomial {
|
2018-07-01 11:35:43 +02:00
|
|
|
constructor(mod, coefArray) {
|
|
|
|
this.mod = mod;
|
|
|
|
this.degree = (coefArray.length - 1);
|
2018-06-29 16:10:38 +02:00
|
|
|
this.coefficients = coefArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.Class = Polynomial;
|
|
|
|
|
2018-07-01 11:43:24 +02:00
|
|
|
function get_mod(p1, p2) {
|
2018-07-01 11:35:43 +02:00
|
|
|
let n;
|
|
|
|
if (p1.mod !== p2.mod) {
|
|
|
|
throw "different modulo"
|
|
|
|
} else {
|
2018-07-01 11:43:24 +02:00
|
|
|
return p1.mod;
|
2018-07-01 11:35:43 +02:00
|
|
|
}
|
2018-07-01 11:43:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function prepare(p1, p2) {
|
|
|
|
let n = get_mod(p1, p2);
|
2018-07-01 11:35:43 +02:00
|
|
|
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);
|
|
|
|
}
|
2018-07-01 11:43:24 +02:00
|
|
|
return {
|
|
|
|
result,
|
|
|
|
n
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function add(p1, p2) {
|
|
|
|
|
|
|
|
let {
|
|
|
|
result,
|
|
|
|
n
|
|
|
|
} = prepare(p1, p2);
|
2018-07-01 11:35:43 +02:00
|
|
|
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;
|
2018-07-01 11:36:07 +02:00
|
|
|
|
|
|
|
function sub(p1, p2) {
|
2018-07-01 11:43:24 +02:00
|
|
|
let {
|
|
|
|
result,
|
|
|
|
n
|
|
|
|
} = prepare(p1, p2);
|
2018-07-01 11:36:07 +02:00
|
|
|
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) {
|
2018-07-01 11:43:24 +02:00
|
|
|
let n = get_mod(p1, p2);
|
2018-07-01 11:36:07 +02:00
|
|
|
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;
|
2018-06-29 16:10:38 +02:00
|
|
|
|
2018-07-01 11:35:43 +02:00
|
|
|
function multiply(p1, p2) {
|
2018-07-01 11:43:24 +02:00
|
|
|
let n = get_mod(p1, p2);
|
2018-06-29 16:10:38 +02:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
2018-07-01 11:35:43 +02:00
|
|
|
return new Polynomial(n, result.map(x => (x % n) + (x < 0 ? n : 0)));
|
2018-06-29 16:10:38 +02:00
|
|
|
}
|
2018-07-01 11:35:43 +02:00
|
|
|
exports.multiply = multiply;
|
2018-06-29 16:10:38 +02:00
|
|
|
|
2018-07-01 11:43:24 +02:00
|
|
|
function power(p1, pow) {
|
|
|
|
let result = p1;
|
|
|
|
for (let i = 1; i < pow; i++) {
|
|
|
|
result = multiply(result, p1);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
exports.power = power;
|
|
|
|
|
2018-07-01 11:35:43 +02:00
|
|
|
function divide(p1, p2) {
|
|
|
|
let n;
|
|
|
|
if (p1.mod !== p2.mod) {
|
|
|
|
throw "different modulo"
|
|
|
|
} else {
|
|
|
|
n = p1.mod;
|
|
|
|
}
|
2018-06-29 16:10:38 +02:00
|
|
|
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);
|
2018-07-01 11:35:43 +02:00
|
|
|
tmp_poly = new Polynomial(n, tmp);
|
2018-06-29 16:10:38 +02:00
|
|
|
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();
|
|
|
|
|
|
|
|
}
|
2018-07-01 11:35:43 +02:00
|
|
|
return new Polynomial(n, f);
|
2018-06-29 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2018-07-01 11:35:43 +02:00
|
|
|
exports.divide = divide;
|
|
|
|
|
|
|
|
function gcd(p1, p2) {
|
2018-06-29 16:10:38 +02:00
|
|
|
if (p2.coefficients.length === 0) {
|
|
|
|
return p1;
|
|
|
|
}
|
2018-07-01 11:35:43 +02:00
|
|
|
return gcd(p2, divide(p1, p2));
|
2018-06-29 16:10:38 +02:00
|
|
|
}
|
|
|
|
|
2018-07-01 11:35:43 +02:00
|
|
|
|
2018-06-29 16:10:38 +02:00
|
|
|
exports.gcd = gcd;
|