Exercise: Write a multiple (a, b) function that multiplies the number a by the number b without using the "*" operator or the Math.imul method.
multiple(1, 1) // 1
multiple(1, 2) // 2
multiple(0, 0) // 0
Code:
export default function multiple(a, b) {
if (a === Infinity && b === 0 || a === -Infinity && b === 0 || a === 0 && b === Infinity || a === 0 && b === -Infinity) {
return NaN;
}
if (b === Infinity) {
if (a < 0) {
return -Infinity;
}
return Infinity;
} if (b === -Infinity) {
if (a < 0) {
return Infinity;
}
return -Infinity;
}
if (b === 1 || b === -1) {
if (a < 0 && b < 0 || a > 0 && b < 0) {
return -a;
}
return a;
}
if (b < 0) {
return -a multiple(a, b 1);
}
return a multiple(a, b - 1);
}
Ok, I write this code and it passes the tests. But eslint
complains about over complexity function: Function 'multiple' has a complexity of 15. Maximum allowed is 10. eslint (complexity)
How to reduce complexity my function?
UPDATE
const multiple = (a, b) => a / (1 / b);
Yes its really worked, but if look on my code, where I can short a repeated operations, I looks blind, but I want to understand it.
UPDATE 2
Solution must goes all tests:
const random = () => Math.floor(Math.random() * 100) * (Math.random() < 0.5 ? -1 : 1)
const cases = [
[0, 1],
[1, 0],
[1, 1],
[1, 2],
[0, 0],
[5, 5],
[5, -5],
[290, -41],
[-5, 5],
[-5, -5],
[random(), random()],
[random(), random()],
[random(), random()],
[random(), random()],
[random(), random()],
[10, -Infinity],
[10, Infinity],
[-10, Infinity],
[-10, -Infinity],
[Infinity, 10],
[-Infinity, -10],
[Infinity, -10],
[-Infinity, 10],
[0, Infinity],
[0, -Infinity],
[Infinity, 0],
[-Infinity, 0]
]
cases.forEach(([a, b]) => {
console.log(`\na:${a} b:${b}`)
console.log('my:', multiple(a, b), 'Fact:', a * b)
})
CodePudding user response:
You can reduce the number of tests where you test the sign. You could instead translate the call with a negative number to a call with a positive number and negate the result.
Here is a more compact version.
NB: I assume the spirit of the exercise was to not use /
either, as otherwise it is trivial to use the fact that a*b === a/(1/b)
function multiple(a, b) {
return a < b ? multiple(b, a)
: b < 0 ? -multiple(a, -b)
: a === Infinity ? (b ? a : NaN)
: b === Infinity || !b ? b
: a multiple(a, b - 1);
}
// Tests:
const random = () => Math.floor(Math.random() * 200) - 100;
const cases = [
[0, 1],
[1, 0],
[1, 1],
[1, 2],
[0, 0],
[5, 5],
[5, -5],
[290, -41],
[-5, 5],
[-5, -5],
[random(), random()],
[random(), random()],
[random(), random()],
[random(), random()],
[random(), random()],
[10, -Infinity],
[10, Infinity],
[-10, Infinity],
[-10, -Infinity],
[Infinity, 10],
[-Infinity, -10],
[Infinity, -10],
[-Infinity, 10],
[0, Infinity],
[0, -Infinity],
[Infinity, 0],
[-Infinity, 0]
]
cases.forEach(([a, b]) => {
let result = multiple(a, b);
if (!Object.is(result, a*b)) {
console.log(`\na:${a} b:${b} my result: ${result}, expected: ${a*b}`);
}
})
console.log("all done");
CodePudding user response:
You could use the identity |a*b|=exp(ln(|a|) ln(|b|)
or 0 iff a==0 or b==0.