theorem.js
Version:
A Math library for computation in JavaScript
1,759 lines (1,662 loc) • 64.2 kB
JavaScript
/*
** © Arthur Guiot 2017 - 2018
** TheoremJS
*/
if (!BigNumber) {
var BigNumber = require("bignumber.js");
}
class TheoremJS {
constructor(precision = 20) {
BigNumber.set({ DECIMAL_PLACES: precision });
// code
this.version = "v1.1.0";
}
exp(n) {
if (n.isComplex) {
return n.exp();
}
return new BigNumber(Math.exp(new BigNumber(n).toNumber()));
}
factorial(n) {
if (new BigNumber(n).eq(0)) {
return new BigNumber(1);
}
return new BigNumber(n).times(this.factorial(new BigNumber(n).minus(1)));
}
gamma(z) {
const g = 7;
const p = [
0.99999999999980993,
676.5203681218851,
-1259.1392167224028,
771.32342877765313,
-176.61502916214059,
12.507343278686905,
-0.13857109526572012,
9.9843695780195716e-6,
1.5056327351493116e-7
];
if (z < 0.5) {
return new BigNumber(
Number(
Math.PI / (Math.sin(Math.PI * z) * this.gamma(1 - z).toNumber())
).toFixed(10)
);
} else if (z > 100) return Math.exp(this.lngamma(z));
else {
z -= 1;
let x = p[0];
for (var i = 1; i < g + 2; i++) {
x += p[i] / (z + i);
}
const t = z + g + 0.5;
return new BigNumber(
Number(
Math.sqrt(2 * Math.PI) * Math.pow(t, z + 0.5) * Math.exp(-t) * x
).toFixed(10)
);
}
}
ln(x, n = 15) {
if (x.isComplex) {
return x.ln();
}
let buffer = new BigNumber(0);
for (let i = 0; i < Math.ceil(n + (3 / 2) * x); i++) {
const n = new BigNumber(1).div(new BigNumber(i).times(2).plus(1)).times(
new BigNumber(x)
.minus(1)
.div(new BigNumber(x).plus(1))
.pow(new BigNumber(i).times(2).plus(1))
);
buffer = buffer.plus(n);
}
return new BigNumber(buffer.times(2).toFixed(n - 1));
}
lngamma(z) {
const g_ln = 607 / 128;
const p_ln = [
0.99999999999999709182,
57.156235665862923517,
-59.597960355475491248,
14.136097974741747174,
-0.49191381609762019978,
0.33994649984811888699e-4,
0.46523628927048575665e-4,
-0.98374475304879564677e-4,
0.15808870322491248884e-3,
-0.21026444172410488319e-3,
0.2174396181152126432e-3,
-0.16431810653676389022e-3,
0.84418223983852743293e-4,
-0.2619083840158140867e-4,
0.36899182659531622704e-5
];
if (z < 0) return Number("0/0");
let x = p_ln[0];
for (var i = p_ln.length - 1; i > 0; --i) x += p_ln[i] / (z + i);
const t = z + g_ln + 0.5;
return new BigNumber(
Number(
0.5 * Math.log(2 * Math.PI) +
(z + 0.5) * Math.log(t) -
t +
Math.log(x) -
Math.log(z)
).toFixed(10)
);
}
log(x, base, n = 15) {
if (x.isComplex) {
return x.log(base);
}
return new BigNumber(
this.ln(x, n)
.div(this.ln(base, n))
.toFixed(n - 1)
);
}
pow(n, base) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(
new BigNumber(
Math.pow(
new BigNumber(n[i]).toNumber(),
new BigNumber(base).toNumber()
).toFixed(10)
)
);
}
return result.length == 1 ? result[0] : new BigNumber(result);
}
root(n, base) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(
new BigNumber(
Math.pow(
new BigNumber(n[i]).toNumber(),
new BigNumber(1).div(base).toNumber()
).toFixed(15)
)
);
}
return result.length == 1 ? result[0] : result;
}
sigmoid(x, n = 15) {
return new BigNumber(
new BigNumber(1).div(this.pow(this.c("e", n), x).plus(1)).toFixed(n)
);
}
sqrt(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
if (new BigNumber(n[i]).lt(0)) {
result.push(this.complex(0, new BigNumber(n[i]).abs().sqrt()));
} else {
result.push(new BigNumber(new BigNumber(n[i]).sqrt()));
}
}
return result.length == 1 ? result[0] : result;
}
apply(n, f) {
if (typeof n != "object") {
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(f(n[i]));
}
return result.length == 1 ? result[0] : result;
}
max() {
const sorted = this.sort(...arguments);
return sorted[sorted.length - 1];
}
min() {
const sorted = this.sort(...arguments);
return sorted[0];
}
product() {
return [...arguments].reduce((a, b) => new BigNumber(a).times(b));
}
sort() {
// https://gist.github.com/jasondscott/7073857
const t = this;
Array.prototype.quickSort = function() {
var r = this;
if (this.length <= 1) {
return this;
}
var less = [],
greater = [];
var pivot = r.splice(t.floor(new BigNumber(r.length).div(2)), 1);
for (var i = r.length - 1; i >= 0; i--) {
if (new BigNumber(r[i]).lte(new BigNumber(pivot))) {
less.push(r[i]);
} else {
greater.push(r[i]);
}
}
var c = [];
return c.concat(less.quickSort(), pivot, greater.quickSort());
};
return [...arguments].quickSort();
}
sum() {
return [...arguments].reduce((a, b) => new BigNumber(a).plus(b));
}
average() {
const summed = this.sum(...arguments);
const average = new BigNumber(summed).div(arguments.length);
return average;
}
correlation(array1, array2) {
if (array1.length != array2.length) {
throw "[TheoremJS]: Correlation error, arrays are not the same size";
}
const average1 = this.average(...array1).toNumber();
const average2 = this.average(...array2).toNumber();
let up = 0;
let down1 = 0;
let down2 = 0;
for (var i = 0; i < array1.length; i++) {
up += (array1[i] - average1) * (array2[i] - average2);
down1 += Math.pow(array1[i] - average1, 2);
down2 += Math.pow(array2[i] - average2, 2);
}
const result = up / Math.sqrt(down1 * down2);
return new BigNumber(Math.round(result * 10 ** 10) / 10 ** 10);
}
median() {
let array = [...arguments];
if (typeof array[0] == "object") {
array = array[0];
}
array.sort((a, b) => new BigNumber(a).minus(b).toNumber());
if (array.length == 0) return 0;
const half = Math.floor(array.length / 2);
if (array.length % 2) {
return new BigNumber(array[half]);
} else {
return new BigNumber((array[half - 1] + array[half]) / 2);
}
}
quantile() {
let array = [...arguments];
let n = array[0];
array.shift();
if (typeof array[0] == "object") {
array = array[0];
}
if (n > 1 || n < 0) {
throw "[TheoremJS] n should be a Float between 0 and 1";
}
array.sort((a, b) => a - b);
if (array.length == 0) return 0;
const index = (array.length - 1) * n;
const floor = Math.floor(index);
const diff = index - floor;
if (array[index + 1] !== undefined) {
const out = array[floor] + diff * (array[floor + 1] - array[floor]);
return new BigNumber(out);
} else {
return array[floor];
}
}
regression(data, deg) {
if (deg == 1) {
return this.linreg(data);
} else {
return this.polyreg(data, deg);
}
}
linreg(array) {
const x = Object.keys(array);
const y = Object.values(array);
const n = y.length;
let sum_x = 0;
let sum_y = 0;
let sum_xy = 0;
let sum_xx = 0;
let sum_yy = 0;
for (let i = 0; i < y.length; i++) {
sum_x += parseFloat(x[i]);
sum_y += parseFloat(y[i]);
sum_xy += parseFloat(x[i] * y[i]);
sum_xx += parseFloat(x[i] * x[i]);
sum_yy += parseFloat(y[i] * y[i]);
}
const slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
const intercept = (sum_y - slope * sum_x) / n;
return this.polynomial(slope, intercept);
}
polyreg(data, deg) {
const x = Object.keys(data);
for (let i in x) {
x[i] = parseFloat(x[i]);
}
const y = Object.values(data);
for (let i in y) {
y[i] = parseFloat(y[i]);
}
const lhs = [];
const rhs = [];
let a = 0;
let b = 0;
let c;
let k;
var i;
let j;
let l;
const len = x.length;
let results;
let equation;
let string;
if (typeof deg === "undefined") {
k = 3;
} else {
k = deg + 1;
}
for (i = 0; i < k; i++) {
for (l = 0; l < len; l++) {
if (y[l] !== null) {
a += x[l] ** i * y[l];
}
}
lhs.push(a);
a = 0;
c = [];
for (j = 0; j < k; j++) {
for (l = 0; l < len; l++) {
if (y[l] !== null) {
b += x[l] ** (i + j);
}
}
c.push(b);
b = 0;
}
rhs.push(c);
}
rhs.push(lhs);
equation = this.gaussElimination(rhs, k);
return this.polynomial(...equation.reverse());
}
acos(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.acos(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
acosh(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.acosh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
angle2Vec(rad) {
return [this.cos(rad), this.sin(rad)];
}
asin(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.asin(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
asinh(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.asinh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
atan(n) {
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.atan(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
atan2(x, y) {
x = [BigNumber(x).toNumber()];
y = [BigNumber(y).toNumber()];
let result = [];
for (var i = 0; i < x.length; i++) {
result.push(Math.atan2(x[i], y[i]));
}
return result.length == 1 ? result[0] : result;
}
atanh(n) {
if (typeof n != "object") {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.atanh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
cos(n) {
if (n.isComplex) {
const a = n.a.toNumber();
const b = n.b.toNumber();
const re = Math.cos(a) * Math.cosh(b);
const im = Math.sin(a) * Math.sinh(b);
return this.complex(re, -im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.cos(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
cosh(n) {
if (n.isComplex) {
const a = n.a.toNumber();
const b = n.b.toNumber();
const re = Math.cos(b) * Math.cosh(a);
const im = Math.sin(b) * Math.sinh(a);
return this.complex(re, im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.cosh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
deg2rad(x) {
return new BigNumber(x).times(this.pi).div(180);
}
drawCircularPoints(n, r = 1, start = [-r, 0], complex = false) {
const angle = this.pi.times(2).div(n);
let buffer = {};
buffer[start[0]] = start[1];
let angleState = this.atan2(...start.reverse()) + angle.toNumber();
for (var i = 0; i < n - 1; i++) {
const x = new BigNumber(r).times(this.cos(angleState)).toString();
const y = new BigNumber(r).times(this.sin(angleState)).toNumber();
if (complex === true) {
buffer[i] = this.complex(x, y);
} else {
buffer[x] = y;
}
angleState += angle.toNumber();
}
if (complex === true) {
return Object.values(buffer);
}
return buffer;
}
rad2deg(x) {
return new BigNumber(x).times(180).div(this.pi);
}
sin(n) {
if (n.isComplex) {
const a = n.a.toNumber();
const b = n.b.toNumber();
const re = Math.cosh(b) * Math.sin(a);
const im = Math.cos(a) * Math.sinh(b);
return this.complex(re, im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.sin(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
sinh(n) {
if (n.isComplex) {
const a = n.a.toNumber();
const b = n.b.toNumber();
const re = Math.cos(b) * Math.sinh(a);
const im = Math.cosh(a) * Math.sin(b);
return this.complex(re, im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.sinh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
tan(n) {
if (n.isComplex) {
const Ta = n.a.times(2).toNumber();
const Tb = n.b.times(2).toNumber();
const sin = Math.sin(Ta);
const cos = Math.cos(Ta);
const cosh = Math.cosh(Tb);
const sinh = Math.sinh(Tb);
const re = sin / (cos + cosh);
const im = sinh / (cos + cosh);
return this.complex(re, im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.tan(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
tanh(n) {
if (n.isComplex) {
const Ta = n.a.times(2).toNumber();
const Tb = n.b.times(2).toNumber();
const sin = Math.sin(Tb);
const cos = Math.cos(Tb);
const cosh = Math.cosh(Ta);
const sinh = Math.sinh(Ta);
const re = sinh / (cos + cosh);
const im = sin / (cos + cosh);
return this.complex(re, im);
}
if (typeof n != "object" || BigNumber.isBigNumber(n)) {
n = BigNumber.isBigNumber(n) == true ? n.toNumber() : n;
n = [n];
}
let result = [];
for (var i = 0; i < n.length; i++) {
result.push(Math.tanh(n[i]).toFixed(15));
}
return result.length == 1 ? result[0] : result;
}
derivate(poly) {
if (poly.type != "polynomial") {
throw "TheoremJS: Derivative: Not a polynomial";
}
let values = [];
const arr = poly.values.reverse();
for (let i = 0; i < arr.length; i++) {
values.push(i * arr[i]);
}
values.reverse();
values.pop();
const out = values.filter(a => !isNaN(a));
return this.polynomial(...out);
}
f(v, func) {
if (typeof v == "function") {
return {
type: "function",
core: v
};
}
return {
type: "function",
v: v,
f: func,
core: x => {
let regex = new RegExp(v);
let newStr = func.replace(regex, `(${x})`);
return eval(newStr).toFixed(14);
}
};
}
findRoots(f) {
let exp = [];
if (f.type == "polynomial") {
switch (f.values.length - 1) {
case 1: {
exp.push(
`${new BigNumber(f.values[1]).isNegative() ? "" : "-"}${
f.values[1]
} / ${f.values[0]}`
);
break;
}
case 2: {
const delta = new BigNumber(f.values[1])
.pow(2)
.minus(new BigNumber(4).times(f.values[0]).times(f.values[2]))
.toNumber();
if (delta > 0) {
exp.push(
`(${
new BigNumber(f.values[1]).isNegative() ? "" : "-"
}${new BigNumber(
f.values[1]
).abs()} + Math.sqrt(${delta})) / ${new BigNumber(
f.values[0]
).times(2)}`
);
exp.push(
`(${
new BigNumber(f.values[1]).isNegative() ? "" : "-"
}${new BigNumber(
f.values[1]
).abs()} - Math.sqrt(${delta})) / ${new BigNumber(
f.values[0]
).times(2)}`
);
}
break;
}
case 3: {
let a = new BigNumber(f.values[0]).toNumber();
let b = new BigNumber(f.values[1]).toNumber();
let c = new BigNumber(f.values[2]).toNumber();
let d = new BigNumber(f.values[3]).toNumber();
// Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a)
var p = (3 * a * c - b * b) / (3 * a * a);
var q =
(2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
var roots;
if (Math.abs(p) < 1e-8) {
// p = 0 -> t^3 = -q -> t = -q^1/3
roots = [Math.cbrt(-q)];
} else if (Math.abs(q) < 1e-8) {
// q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0
roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []);
} else {
var D = (q * q) / 4 + (p * p * p) / 27;
var u; // no-redeclare
if (Math.abs(D) < 1e-8) {
// D = 0 -> two roots
roots = [(-1.5 * q) / p, (3 * q) / p];
} else if (D > 0) {
// Only one real root
u = Math.cbrt(-q / 2 - Math.sqrt(D));
roots = [u - p / (3 * u)];
} else {
// D < 0, three roots, but needs to use complex numbers/trigonometric solution
u = 2 * Math.sqrt(-p / 3);
var t = Math.acos((3 * q) / p / u) / 3; // D < 0 implies p < 0 and acos argument in [-1..1]
var k = (2 * Math.PI) / 3;
roots = [
u * Math.cos(t),
u * Math.cos(t - k),
u * Math.cos(t - 2 * k)
];
}
}
// Convert back from depressed cubic
for (var i = 0; i < roots.length; i++) roots[i] -= b / (3 * a);
exp = roots;
break;
}
default: {
exp = [this.numeralSolve(f, 0)[0]];
}
}
} else {
exp = [this.numeralSolve(f, 0)[0]];
}
return exp;
}
gaussElimination(input, order) {
const matrix = input;
const n = input.length - 1;
const coefficients = [order];
for (let i = 0; i < n; i++) {
let maxrow = i;
for (let j = i + 1; j < n; j++) {
if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][maxrow])) {
maxrow = j;
}
}
for (let k = i; k < n + 1; k++) {
const tmp = matrix[k][i];
matrix[k][i] = matrix[k][maxrow];
matrix[k][maxrow] = tmp;
}
for (let j = i + 1; j < n; j++) {
for (let k = n; k >= i; k--) {
matrix[k][j] -= (matrix[k][i] * matrix[i][j]) / matrix[i][i];
}
}
}
for (let j = n - 1; j >= 0; j--) {
let total = 0;
for (let k = j + 1; k < n; k++) {
total += matrix[k][j] * coefficients[k];
}
coefficients[j] = (matrix[n][j] - total) / matrix[j][j];
}
return coefficients;
}
gradient(p1, p2) {
const x1 = Number(Object.keys(p1)[0]);
const y1 = Number(Object.values(p1)[0]);
const x2 = Number(Object.keys(p2)[0]);
const y2 = Number(Object.values(p2)[0]);
const slope = (y2 - y1) / (x2 - x1);
return slope;
}
graph(f, from = -100, to = 100, step = 0.1) {
let array = {};
for (
var i = new BigNumber(from);
i.lessThanOrEqualTo(new BigNumber(to));
i = i.plus(new BigNumber(step))
) {
array[i.toString()] = f.core(i).toFixed(15);
}
return array;
}
integrate(poly) {
if (poly.type != "polynomial") {
throw "TheoremJS: Integrate: Not a polynomial";
}
let values = [];
for (let i in poly.values.reverse()) {
values.push(poly.values[i] / (parseInt(i) + 1));
}
values.reverse();
values.push(0);
const out = values.filter(a => !isNaN(a));
return this.polynomial(...out);
}
numeralSolve(f, end, from = -100, to = 100, step = 0.1) {
let buffer = [];
let index = [];
for (let i = new BigNumber(from); i.lt(to); i = i.plus(step)) {
buffer.push(this.run(f, i.toNumber()));
index.push(i.toNumber());
}
function closest(num, arr) {
let curr = arr[0];
let diff = Math.abs(num - curr);
for (let val = 0; val < arr.length; val++) {
const newdiff = Math.abs(num - arr[val]);
if (newdiff < diff) {
diff = newdiff;
curr = arr[val];
}
}
return curr;
}
const close = closest(end, buffer.filter(x => !isNaN(x)));
return index[buffer.indexOf(close)];
}
polynomial() {
const arg = [...arguments];
const args = this.reverse(arg);
let buffer = "";
for (let i = 0; i < args.length; i++) {
buffer += `${args[i]} * x**${i} ${i == args.length - 1 ? "" : "+ "}`;
}
return {
type: "polynomial",
v: "x",
f: buffer,
values: arg,
core: x => {
let regex = new RegExp("x");
let newStr = buffer.replace(regex, `(${x})`);
return eval(newStr).toFixed(14);
}
};
}
run(f, x) {
x = new BigNumber(x).toNumber();
let out = 0;
try {
out = f.core(x);
} catch (e) {
throw `[TheoremJS]: ${e}`;
}
return out;
}
slope(f, x = 0, i = 1e-10) {
const f1 = f.core(x);
const x1 = x;
const f2 = f.core(x + i);
const x2 = x + i;
return new BigNumber(f2).minus(f1).div(new BigNumber(x2).minus(x1));
}
y_intercept(f) {
return f.core(0);
}
toDec() {
const args = [...arguments];
if (typeof args[0] == "object") {
if (args[0].length != 2) {
throw "Require 2 numbers";
}
return new BigNumber(args[0][0]).div(args[0][1]);
}
if (args.length != 2) {
throw "Require 2 numbers";
}
return new BigNumber(args[0]).div(args[1]);
}
toFraction(x, p = 15) {
const BN = BigNumber.clone({ DECIMAL_PLACES: 20 });
return new BN(x.toFixed(15)).toFraction(p);
}
*collatz(n) {
while (n != 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
yield n;
}
}
*fibonacci() {
let fn1 = 0;
let fn2 = 1;
while (true) {
const current = fn1;
fn1 = fn2;
fn2 = fn1 + current;
const reset = yield current;
if (reset) {
fn1 = 0;
fn2 = 1;
}
}
}
*sieve() {
let n = 2;
while (true) {
if (this.isPrime(n)) yield n;
n++;
}
}
convert(value, type, a, b) {
class Units {
area(v, a, b) {
const authorized = [
"mm2",
"cm2",
"dm2",
"m2",
"dam2",
"hm2",
"ha",
"km2",
"in2",
"ft2",
"yd2",
"mi2"
];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Area: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to square meters
const factor = [
new BigNumber(1).div(1000000),
new BigNumber(1).div(10000),
new BigNumber(1).div(100),
1,
100,
10000,
10000,
1000000,
"0.00064516",
"0.09290304",
"0.83612736",
"2589988.110336"
];
const g = new BigNumber(v).times(factor[ia]);
const out = g.div(factor[ib]);
return out;
}
distance() {
return this.length(...arguments);
}
length(v, a, b) {
const authorized = [
"mm",
"cm",
"dm",
"m",
"dam",
"hm",
"km",
"yd",
"ft",
"mi",
"in",
"li",
"au",
"ly",
"Nm"
];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Length: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to m
const factor = [
1 / 1000,
1 / 100,
1 / 10,
1,
10,
100,
1000,
new BigNumber(0.9144),
new BigNumber(0.3048),
new BigNumber(1609.344),
new BigNumber(25.4).div(1000),
new BigNumber(6.35).times("0.0001"),
new BigNumber("149597870700"),
new BigNumber("9460730472580.8").times(1000),
1852
];
const m = new BigNumber(v).times(factor[ia]);
const out = m.div(factor[ib]);
return out;
}
mass(v, a, b) {
const authorized = [
"mg",
"cg",
"dg",
"g",
"dag",
"hg",
"kg",
"t",
"oz",
"lb"
];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Mass: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to gram
const factor = [
1000,
100,
10,
1,
new BigNumber(1).div(10),
new BigNumber(1).div(100),
new BigNumber(1).div(1000),
new BigNumber(1).div(1000000),
new BigNumber(1).div("28.349523125"),
new BigNumber(1).div("453.59237")
];
const g = new BigNumber(v).div(factor[ia]);
const out = new BigNumber(g).times(factor[ib]);
return out;
}
speed(v, a, b) {
const authorized = ["m/s", "km/h", "m/h", "knot", "ft/s"];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Speed: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to ms
const factor = [
new BigNumber(1),
new BigNumber(1).div(3.6),
new BigNumber(0.44704),
new BigNumber(0.514444),
new BigNumber(0.3048)
];
const ms = new BigNumber(v).times(factor[ia]);
const out = ms.div(factor[ib]);
return out;
}
temperature(v, a, b) {
const authorized = ["c", "f", "k"];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Temperature: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to celsius
const add = [0, -32, -273.15];
const factor = [1, new BigNumber(5).div(9), 1];
const g = new BigNumber(v).plus(add[ia]).times(factor[ia]);
const out = g.div(factor[ib]).minus(add[ib]);
return out;
}
time(v, a, b) {
const authorized = ["ms", "s", "m", "h", "d", "w", "mo", "y"];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Time: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to gram
const factor = [
new BigNumber(1).div(1000),
1,
60,
3600,
86400,
604800,
"2592000",
new BigNumber("365.2421891").times(24).times(3600)
];
const g = new BigNumber(v).times(factor[ia]);
const out = g.div(factor[ib]);
return out;
}
volume(v, a, b) {
const authorized = [
"mm3",
"ml",
"cm3",
"cl",
"dl",
"dm3",
"l",
"hl",
"m3",
"dam3",
"hm3",
"km3",
"gal",
"floz"
];
if (!authorized.includes(a) || !authorized.includes(b)) {
throw "[TheoremJS] Volume: wrong units";
}
const ia = authorized.indexOf(a);
const ib = authorized.indexOf(b);
// to cubic meters
const factor = [
new BigNumber(1).div(1000000000), // mm3
new BigNumber(1).div(1000000), // ml
new BigNumber(1).div(1000000), // cm3
new BigNumber(10).div(1000000), // cl
"0.0001", // dl
new BigNumber(1).div(1000), // dm3
new BigNumber(1).div(1000), // l
0.1, // hl
1, // m3
1000, // dam3
1000000, // hm3
1000000000, //km3
"0.003785411784", // gal,
"2.95735295625e-5" // floz
];
const g = new BigNumber(v).times(factor[ia]);
const out = g.div(factor[ib]);
return out;
}
}
const u = new Units();
return u[type](value, a, b);
}
units() {
return this.convert(...arguments);
}
abs(n) {
return new BigNumber(n).abs();
}
c(name, n = 15) {
const numbers = {
alphaParticleMass: "6.64465675e-27",
atomicMass: "1.660538921e-27",
Avogadro: "6.02214129e23",
Boltzmann: "1.3806488e-23",
conductanceQuantum: "7.7480917346e-5",
e:
"2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668",
"earth-moon": "384401",
"earth-sun": "1.496e8",
earthMass: "5.974e+24",
earthRadius: "6378",
electric: "8.854187e-12",
electronMass: "9.10938291e-31",
elementaryCharge: "1.602176565e-19",
EulerGamma:
"0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495146314472498070824809605040144865428362241739976449235362535003337429373377376739427925952582470949160087352039481656708532331517766115286211995015080",
Faraday: "96485.3365",
fineStructure: "7.2973525698e-3",
goldenRatio:
"1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137484754088075386891752126633862223536931793180060766726354433389086595939582905638322661319928290267880675208766892501711696207032221043216269548626296",
gravity: "9.80665",
inverseFineStructure: "137.035999074",
magnetic: "12.566370614e-7",
magneticFluxQuantum: "2.067833758e-15",
molarGas: "8.3144621",
moonMass: "7.348e22",
moonRadius: "1738",
neutronMass: "1.674927351e-27",
NewtonGravitation: "6.67384e-11",
pi:
"3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909",
Planck: "6.62606957e-34",
"proton-electronMassRatio": "1836.15267245",
"proton-neutronMassRatio": "0.99862347826",
protonMass: "1.672621777e-27",
Rydberg: "10973731.568539",
speedOfLight: "299792458",
speedOfSound: "340.27",
"sqrt(2)":
"1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641572735013846230912297024924836055850737212644121497099935831413222665927505592755799950501152782060571470109559971605970274534596862014728517418640889199",
"Stefan-Boltzmann": "5.670373e-8",
sunMass: "1.989e30",
sunRadius: "695500",
TheRockMass: "124.73790175",
ThomsonCrossSection: "0.6652458734e-28",
UltimateAnswer: "42",
zeroKelvin: "-273.15"
};
const BN = BigNumber.clone({
DECIMAL_PLACES: n
});
const num = numbers[name].split("e");
if (num.length > 1) {
return new BN(`${num[0].slice(0, n + 2)}e${num[1]}`);
}
return new BN(num[0].slice(0, n + 2));
}
ceil(n) {
return new BigNumber(n).integerValue(BigNumber.ROUND_CEIL);
}
get e() {
const n = 15;
const BN = BigNumber.clone({ DECIMAL_PLACES: n });
let zero = new BN(0);
let one = new BN(1);
let rval;
for (let i = 0; i <= n * 10; i++) {
let fval = this.factorial(i);
let invert = one.div(fval);
zero = zero.plus(invert);
}
return new BN(zero);
}
floor(n) {
return new BigNumber(n).integerValue(BigNumber.ROUND_FLOOR);
}
get goldenRatio() {
const n = 15;
const BN = BigNumber.clone({ DECIMAL_PLACES: n + 1 });
return new BN(
BN(1)
.plus(this.sqrt(5))
.div(2)
.toFixed(n + 1)
);
}
isPrime(n) {
n = new BigNumber(n).abs();
const leastFactor = this.leastFactor(n);
if (n.eq(leastFactor) && n.gte(2)) {
return true;
}
return false;
}
leastFactor(n) {
n = new BigNumber(n).abs().toNumber();
if (Number.MAX_SAFE_INTEGER < n)
throw `${n} is superior to ${Number.MAX_SAFE_INTEGER}`;
let out = false;
if (isNaN(n) || !isFinite(n)) out = out !== false ? out : NaN;
if (n == 0) out = out !== false ? out : 0;
if (n % 1 || n * n < 2) out = out !== false ? out : 1;
if (n % 2 == 0) out = out !== false ? out : 2;
if (n % 3 == 0) out = out !== false ? out : 3;
if (n % 5 == 0) out = out !== false ? out : 5;
const m = Math.sqrt(n);
for (let i = 7; i <= m; i += 30) {
if (n % i == 0) out = out !== false ? out : i;
if (n % (i + 4) == 0) out = out !== false ? out : i + 4;
if (n % (i + 6) == 0) out = out !== false ? out : i + 6;
if (n % (i + 10) == 0) out = out !== false ? out : i + 10;
if (n % (i + 12) == 0) out = out !== false ? out : i + 12;
if (n % (i + 16) == 0) out = out !== false ? out : i + 16;
if (n % (i + 22) == 0) out = out !== false ? out : i + 22;
if (n % (i + 24) == 0) out = out !== false ? out : i + 24;
}
out = out !== false ? out : n;
return new BigNumber(out);
}
n(n, base = 10) {
return new BigNumber(n, base);
}
nPrime(n) {
n = new BigNumber(n).toNumber();
if (n < 1) {
throw "[TheoremJS]: n is less than 1";
}
if (n > Number.MAX_SAFE_INTEGER) {
throw `[TheoremJS] Input was larger than ${Number.MAX_SAFE_INTEGER}`;
}
const gen = this.sieve();
let out = 0;
for (var i = 0; i < n; i++) {
out = gen.next().value;
}
return new BigNumber(out);
}
get pi() {
const digits = 15;
const Decimal = BigNumber.clone({ DECIMAL_PLACES: digits });
function arctan(x) {
var y = x;
var yPrev = NaN;
var x2 = x.times(x);
var num = x;
var sign = -1;
for (var k = 3; !y.eq(yPrev); k += 2) {
num = num.times(x2);
yPrev = y;
y = sign > 0 ? y.plus(num.div(k)) : y.minus(num.div(k));
sign = -sign;
}
return y;
}
// Machin: Pi / 4 = 4 * arctan(1 / 5) - arctan(1 / 239)
// http://milan.milanovic.org/math/english/pi/machin.html
// we calculate pi with a few decimal places extra to prevent round off issues
var DecimalPlus = BigNumber.clone({ DECIMAL_PLACES: digits + 4 });
var pi4th = new DecimalPlus(4)
.times(arctan(new DecimalPlus(1).div(5)))
.minus(arctan(new DecimalPlus(1).div(239)));
// the final pi has the requested number of decimals
return new Decimal(4).times(new Decimal(pi4th));
}
primeFactors(n) {
n = new BigNumber(n).toNumber();
if (n < 2) {
throw "[TheoremJS] Number should be greater or equal to 2";
}
if (n > Number.MAX_SAFE_INTEGER) {
throw `[TheoremJS] Input was larger than ${Number.MAX_SAFE_INTEGER}`;
}
let list = [];
for (var i = 2; i <= n; i++) {
if (n % i == 0) {
if (this.isPrime(i)) {
n /= i;
list.push(new BigNumber(i));
i = i - 1; // check for number twice (example 100 = 2*2*5*5)
}
}
}
return list;
}
primePi(n) {
n = new BigNumber(n).toNumber();
if (n < 2) {
throw "[TheoremJS] Number should be greater or equal to 2";
}
if (n > Number.MAX_SAFE_INTEGER) {
throw `[TheoremJS] Input was larger than ${Number.MAX_SAFE_INTEGER}`;
}
const gen = this.sieve();
let out = 0;
for (var i = 0; i < n; i = gen.next().value) {
out += 1;
}
return new BigNumber(out - 1);
}
round(n, precision = 0) {
const tenPow = this.pow(10, precision);
return new BigNumber(n)
.times(tenPow)
.integerValue(BigNumber.ROUND_HALF_CEIL)
.div(tenPow);
}
rand(n = 1, crypto = false) {
const BN = BigNumber.clone({ CRYPTO: crypto });
let out = [];
for (var i = 0; i < n; i++) {
out.push(BN.random());
}
return out.length == 1 ? out[0] : out;
}
config(obj) {
BigNumber.set(obj);
}
convertToBase(x, n) {
const BN = BigNumber.clone({
ALPHABET:
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
});
return new BN(x).toString(n);
}
get fn() {
return this.prototype;
}
toBase10(n, base) {
return new BigNumber(n, base);
}
flatten(array) {
return array.reduce((a, b) => a.concat(b), []);
}
linspace(start, end, n) {
const diff = end - start;
const step = diff / n;
return this.arange(start, end, step);
}
arange(start, end, step, offset) {
const len = (Math.abs(end - start) + (offset || 0) * 2) / (step || 1) + 1;
const direction = start < end ? 1 : -1;
const startingPoint = start - direction * (offset || 0);
const stepSize = direction * (step || 1);
return Array(len)
.fill(0)
.map((_, index) => startingPoint + stepSize * index);
}
range(n) {
return this.arange(0, n, 1);
}
reshape(array, part) {
const tmp = [];
for (let i = 0; i < array.length; i += part) {
tmp.push(array.slice(i, i + part));
}
return tmp;
}
reverse(array) {
return array.slice(0).reverse(); // duplicate and reverse to duplicate the array
}
bin2str(txt) {
return txt.replace(/\s*[01]{8}\s*/g, function(bin) {
return String.fromCharCode(parseInt(bin, 2));
});
}
huffmanEncode(str) {
const tree = createTree(str);
const codebook = createCodebook(tree);
return {
string: [...str].map(c => codebook[c]).join(""),
tree,
codebook
};
function createTree(str) {
const chars = [...str];
const charCounts = chars.reduce((counts, char) => {
counts[char] = (counts[char] || 0) + 1;
return counts;
}, {});
const nodes = Object.entries(charCounts).map(([key, weight]) => ({
key,
weight
}));
// This queue implementation is horribly inefficient, but a proper, heap-based implementation would
// be longer that the algorithm itself
function makeQueue(iterable) {
return {
data: [...iterable].sort((a, b) => a.weight - b.weight),
enqueue(value) {
const target = this.data.findIndex(x => x.weight > value.weight);
if (target === -1) {
this.data.push(value);
} else {
this.data = [
...this.data.slice(0, target),
value,
...this.data.slice(target)
];
}
},
dequeue() {
return this.data.shift();
}
};
}
const priorityQueue = makeQueue(nodes);
while (priorityQueue.data.length > 1) {
const left = priorityQueue.dequeue();
const right = priorityQueue.dequeue();
priorityQueue.enqueue({
weight: left.weight + right.weight,
left,
right
});
}
return priorityQueue.dequeue();
}
function createCodebook(tree) {
return recurse(tree, "", {});
function recurse(node, bitstring, dict) {
if (!node.left && !node.right) {
dict[node.key] = bitstring;
} else {
if (node.left) {
recurse(node.left, `${bitstring}0`, dict);
}
if (node.right) {
recurse(node.right, `${bitstring}1`, dict);
}
}
return dict;
}
}
}
huffmanDecode(bitstring, tree) {
const result = [];
let node = tree;
for (const bit of [...bitstring]) {
node = bit === "0" ? node.left : node.right;
if (!node.left && !node.right) {
result.push(node.key);
node = tree;
}
}
return result.join("");
}
md5(s) {
if (BigNumber.isBigNumber(s) || (!isNaN(parseFloat(s)) && isFinite(s))) {
s = s.toString();
}
let string = s;
function RotateLeft(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
}
function AddUnsigned(lX, lY) {
let lX4;
let lY4;
let lX8;
let lY8;
let lResult;
lX8 = lX & 0x80000000;
lY8 = lY & 0x80000000;
lX4 = lX & 0x40000000;
lY4 = lY & 0x40000000;
lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff);
if (lX4 & lY4) {
return lResult ^ 0x80000000 ^ lX8 ^ lY8;
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return lResult ^ 0xc0000000 ^ lX8 ^ lY8;
} else {
return lResult ^ 0x40000000 ^ lX8 ^ lY8;
}
} else {
return lResult ^ lX8 ^ lY8;
}
}
function F(x, y, z) {
return (x & y) | (~x & z);
}
function G(x, y, z) {
return (x & z) | (y & ~z);
}
function H(x, y, z) {
return x ^ y ^ z;
}
function I(x, y, z) {
return y ^ (x | ~z);
}
function FF(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
}
function GG(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
}
function HH(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
}
function II(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
}
function ConvertToWordArray(string) {
let lWordCount;
const lMessageLength = string.length;
const lNumberOfWords_temp1 = lMessageLength + 8;
const lNumberOfWords_temp2 =
(lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
const lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
const lWordArray = Array(lNumberOfWords - 1);
let lBytePosition = 0;
let lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] =
lWordArray[lWordCount] |
(string.charCodeAt(lByteCount) << lBytePosition);
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
}
function WordToHex(lValue) {
let WordToHexValue = "";
let WordToHexValue_temp = "";
let lByte;
let lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = `0${lByte.toString(16)}`;
WordToHexValue =
WordToHexValue +
WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
}
return WordToHexValue;
}
function Utf8Encode(string) {
string = string.replace(/\r\n/g, "\n");
let utftext = "";
for (let n = 0; n < string.length; n++) {
const c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
let x = Array();
let k;
let AA;
let BB;
let CC;
let DD;
let a;
let b;
let c;
let d;
const S11 = 7;
const S12 = 12;
const S13 = 17;
const S14 = 22;
const S21 = 5;
const S22 = 9;
const S23 = 14;
const S24 = 20;
const S31 = 4;
const S32 = 11;
const S33 = 16;
const S34 = 23;
const S41 = 6;
const S42 = 10;
const S43 = 15;
const S44 = 21;
string = Utf8Encode(string);
x = ConvertToWordArray(string);
a = 0x67452301;
b = 0xefcdab89;
c = 0x98badcfe;
d = 0x10325476;
for (k = 0; k < x.length; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = FF(a, b, c, d, x[k + 0], S11, 0xd76aa478);
d = FF(d, a, b, c, x[k + 1], S12, 0xe8c7b756);
c = FF(c, d, a, b, x[k + 2], S13, 0x242070db);
b = FF(b, c, d, a, x[k + 3], S14, 0xc1bdceee);
a = FF(a, b, c, d, x[k + 4], S11, 0xf57c0faf);
d = FF(d, a, b, c, x[k + 5], S12, 0x4787c62a);
c = FF(c, d, a, b, x[k + 6], S13, 0xa8304613);
b = FF(b, c, d, a, x[k + 7], S14, 0xfd469501);
a = FF(a, b, c, d, x[k + 8], S11, 0x698098d8);
d = FF(d, a, b, c, x[k + 9], S12, 0x8b44f7af);
c = FF(c, d, a, b, x[k + 10], S13, 0xffff5bb1);
b = FF(b, c, d, a, x[k + 11], S14, 0x895cd7be);
a = FF(a, b, c, d, x[k + 12], S11, 0x6b901122);
d = FF(d, a, b, c, x[k + 13], S12, 0xfd987193);
c = FF(c, d, a, b, x[k + 14], S13, 0xa679438e);
b = FF(b, c, d, a, x[k + 15], S14, 0x49b40821);
a = GG(a, b, c, d, x[k + 1], S21, 0xf61e2562);
d = GG(d, a, b, c, x[k + 6], S22, 0xc040b340);
c = GG(c, d, a, b, x[k + 11], S23, 0x265e5a51);
b = GG(b, c, d, a, x[k + 0], S24, 0xe9b6c7aa);
a = GG(a, b, c, d, x[k + 5], S21, 0xd62f105d);
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = GG(c, d, a, b, x[k + 15], S23, 0xd8a1e681);
b = GG(b, c, d, a, x[k + 4], S24, 0xe7d3fbc8);
a = GG(a, b, c, d, x[k + 9], S21, 0x21e1cde6);
d = GG(d, a, b, c, x[k + 14], S22, 0xc33707d6);
c = GG(c, d, a, b, x[k + 3], S23, 0xf4d50d87);
b = GG(b, c, d, a, x[k + 8], S24, 0x455a14ed);
a = GG(a, b, c, d, x[k + 13], S21, 0xa9e3e905);
d = GG(d, a, b, c, x[k + 2], S22, 0xfcefa3f8);
c = GG(c, d, a, b, x[k + 7], S23, 0x676f02d9);
b = GG(b, c, d, a, x[k + 12], S24, 0x8d2a4c8a);
a = HH(a, b, c, d, x[k + 5], S31, 0xfffa3942);
d = HH(d, a, b, c, x[k + 8], S32, 0x8771f681);
c = HH(c, d, a, b, x[k + 11], S33, 0x6d9d6122);
b = HH(b, c, d, a, x[k + 14], S34, 0xfde5380c);
a = HH(a, b, c, d, x[k + 1], S31, 0xa4beea44);
d = HH(d, a, b, c, x[k + 4], S32, 0x4bdecfa9);
c = HH(c, d, a, b, x[k + 7], S33, 0xf6bb4b60);
b = HH(b, c, d, a, x[k + 10], S34, 0xbebfbc70);
a = HH(a, b, c, d, x[k + 13], S31, 0x289b7ec6);
d = HH(d, a, b, c, x[k + 0], S32, 0xeaa127fa);
c = HH(c, d, a, b, x[k + 3], S33, 0xd4ef3085);
b = HH(b, c, d, a, x[k + 6], S34, 0x4881d05);
a = HH(a, b, c, d, x[k + 9], S31, 0xd9d4d039);
d = HH(d, a, b, c, x[k + 12], S32, 0xe6db99e5);
c = HH(c, d, a, b, x[k + 15], S33, 0x1fa27cf8);
b = HH(b, c, d, a, x[k + 2], S34, 0xc4ac5665);
a = II(a, b, c, d, x[k + 0], S41, 0xf4292244);
d = II(d, a, b, c, x[k + 7], S42, 0x432aff97);
c = II(c, d, a, b, x[k + 14], S43, 0xab9423a7);
b = II(b, c, d, a, x[k + 5], S44, 0xfc93a039);
a = II(a, b, c, d, x[k + 12], S41, 0x655b59c3);
d = II(d, a, b, c, x[k + 3], S42, 0x8f0ccc92);
c = II(c, d, a, b, x[k + 10], S43, 0xffeff47d);
b = II(b, c, d, a, x[k + 1], S44, 0x85845dd1);
a = II(a, b, c, d, x[k + 8], S41, 0x6fa87e4f);
d = II(d, a, b, c, x[k + 15], S42, 0xfe2ce6e0);
c = II(c,