Last active
January 17, 2018 21:36
-
-
Save Beraliv/a5f2889d08bb4fb675ffc268dfd952a2 to your computer and use it in GitHub Desktop.
Task 62. UniLecs. Functional-like. Added BigInteger.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const BigInteger = value => { | |
const normalise = n => { | |
if ((n | 0) === 0) { | |
return '0'; | |
} | |
n = n.toString().split(''); | |
while (+n[0] === 0) { | |
n.splice(0, 1); | |
} | |
return n.join(''); | |
}; | |
return { | |
value: normalise(value), | |
sub(bi) { | |
// substract result can be positive only | |
let a = this.value, b = bi.value; | |
if ((a | 0) === 0 || (b | 0) === 0) { | |
return BigInteger(0); | |
} | |
if (this.eq(bi)) { | |
return BigInteger(0); | |
} | |
a = a.split('').reverse(); | |
b = b.split('').reverse(); | |
let result = Array(Math.max(a.length, b.length)).fill(0); | |
for (let i = 0; +a[i] >= 0 || +b[i] >= 0; i++) { | |
let diff = (+a[i] || 0) - (+b[i] || 0); | |
if (diff + result[i] >= 0) { | |
result[i] += diff; | |
} | |
else { | |
result[i] += diff + 10; | |
// no check as a >= b | |
result[i + 1] = -1; | |
} | |
} | |
return BigInteger(result.reverse().join('')); | |
}, | |
mul(bi) { | |
// solution is extracted from https://goo.gl/obVaWP | |
let a = this.value, b = bi.value; | |
if ((a | 0) === 0 || (b | 0) === 0) { | |
return BigInteger(0); | |
} | |
a = a.split('').reverse(); | |
b = b.split('').reverse(); | |
let result = []; | |
for (let i = 0; a[i] >= 0; i++) { | |
for (let j = 0; b[j] >= 0; j++) { | |
if (!result[i + j]) { | |
result[i + j] = 0; | |
} | |
result[i + j] += a[i] * b[j]; | |
} | |
} | |
for (let i = 0; result[i] >= 0; i++) { | |
if (result[i] >= 10) { | |
if (!result[i + 1]) { | |
result[i + 1] = 0; | |
} | |
result[i + 1] += parseInt(result[i] / 10); | |
result[i] %= 10; | |
} | |
} | |
return BigInteger(result.reverse().join('')); | |
}, | |
div(bi) { | |
if (bi.gt(this)) { | |
return BigInteger(0); | |
} | |
if (bi.eq(this)) { | |
return BigInteger(1); | |
} | |
let a = this.value, b = bi.value; | |
let length = b.length; | |
let results = []; | |
let chunk = a.slice(0, length); | |
let endIndex = length; | |
while (true) { | |
if (endIndex > a.length) { | |
break; | |
} | |
if (BigInteger(b).gt(BigInteger(chunk)) && endIndex < a.length) { | |
// console.log(`chunk.length <= b.length && chunk < b: ${chunk.length} <= ${b.length} && ${chunk} < ${b}`) | |
chunk = chunk + a[endIndex]; | |
// console.log(`a[endIndex]: a[${endIndex}] = ${a[endIndex]}`); | |
endIndex++; | |
results.push(0); | |
} | |
// TODO: to optimise with binary search | |
let i = 1; | |
for (; i < 10; i++) { | |
if (BigInteger(b).mul(BigInteger(i)).gt(BigInteger(chunk))) { | |
// console.log(`chunk / b = i - 1: ${chunk} / ${b} = ${i - 1}`) | |
break; | |
} | |
} | |
results.push(i - 1); | |
chunk = BigInteger(chunk).sub(BigInteger(b).mul(BigInteger(i - 1))).value; | |
// console.log(chunk); | |
if (endIndex < a.length) { | |
chunk = chunk + a[endIndex]; | |
} | |
endIndex++; | |
} | |
let result = results.join(''); | |
return BigInteger(result); | |
}, | |
mod(bi) { | |
return BigInteger(this.sub(this.div(bi).mul(bi))); | |
}, | |
gt(bi) { | |
// compare only positive numbers | |
let a = this.value, b = bi.value; | |
a = a.split(''); | |
b = b.split(''); | |
return a.length > b.length | |
|| (a.length === b.length && a > b); | |
}, | |
eq(bi) { return this.value === bi.value; }, | |
toString() { return this.value; }, | |
}; | |
}; | |
const BIG_ZERO = BigInteger(0); | |
const BIG_ONE = BigInteger(1); | |
// check if n is valid for certain m | |
const check = (n, m) => Array(m - 3).fill(0) | |
// iterate from m-1 to 2 | |
.map((_, i) => BigInteger(m - i - 1)) | |
// checks if for all i, n % i === i - 1 | |
.filter(i => !n.mod(i).eq(i.sub(BIG_ONE))) | |
.length === 0; | |
const count = (() => { | |
// greatest common divisor | |
const gcd = (m, n) => m.gt(n) | |
? gcd(n, m) | |
: m.gt(BIG_ZERO) | |
? gcd(m, n.mod(m)) | |
: n; | |
// least common multiplier | |
// = m / gcd(m, n) * n | |
const lcm = (m, n) => m | |
.div(gcd(m, n)) | |
.mul(n); | |
// upper bound for the value | |
// p is from 1 to 1000 | |
const upper = p => Array(p).fill(0) | |
// iterates from 1 to p | |
.map((_, i) => BigInteger(i + 1)) | |
.reduce(lcm, BigInteger(1)); | |
// m is from 1 to 1000 | |
return (m) => { | |
if (m <= 0) { | |
throw new Error('The number should be positive (greater than zero)'); | |
} | |
return m < 3 | |
? '1' | |
: upper(m).sub(BIG_ONE).value; | |
}; | |
})(); | |
for (let i = 1; i < 100; i++) { | |
console.log(i, count(i)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For now the maximum calculated number is 52.
The maximum correct value is 40.
The expected value is 219060189739591159, but had 219060189739591199.