From 7ee074f928b4858ecbb32633b98b9af7c00f8838 Mon Sep 17 00:00:00 2001 From: Michael Flynn Date: Tue, 6 Feb 2018 19:05:17 -0500 Subject: [PATCH 1/3] Factorial First pass at creating a factorial function. --- lib/factorial.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 lib/factorial.js diff --git a/lib/factorial.js b/lib/factorial.js new file mode 100644 index 0000000..73ae2a9 --- /dev/null +++ b/lib/factorial.js @@ -0,0 +1,40 @@ +// https://stackoverflow.com/a/3959275 + +const { isPositiveInteger } = require('./isPositiveInteger'); + +const factorialCache = [1, 1]; + +const caclulateFactorial = (num) => { + if (typeof factorialCache[num] !== 'undefined') { + return factorialCache[num]; + } + + const start = factorialCache.length <= num ? factorialCache.length - 1 : num - 1; + for (let i = start + 1; i <= num; i += 1) { + factorialCache[i] = factorialCache[i - 1] * i; + } + + return factorialCache[num]; +}; + +exports.factorial = (...params) => { + handleErrors(params); + + return params.map(caclulateFactorial); +}; + +const handleErrors = (params) => { + if (params.length === 0) throw new Error('Must provide one or more paramters'); + if (params.some(param => !Number.isInteger(param))) { + throw new Error('One of your parameters does not evaluate to a integer'); + } + // Has to be a non negative integer + if (params.some(param => !isPositiveInteger(param))) { + throw new Error('One of your parameters does not evaluate to a positive integer'); + } + // JS can only safely represent and compare integers between + // Number.MAX_SAFE_INTEGER and Number.MAX_SAFE_INTEGER + if (params.some(param => param > Number.MAX_SAFE_INTEGER || param < Number.MIN_SAFE_INTEGER)) { + throw new Error('Cannot reliably test primality of numbers larger than 9,007,199,254,740,991 or smaller than -9,007,199,254,740,991'); + } +}; From 1ef8d677bb9b333150e20960bf4d377fa7c4716e Mon Sep 17 00:00:00 2001 From: Michael Flynn Date: Thu, 8 Feb 2018 17:15:18 -0500 Subject: [PATCH 2/3] Writing test spec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason my use of the ternary operator resulting a line being considered uncovered. Upon further reflection, the ternary wasn’t needed and no more Uncovered lines. --- lib/factorial.js | 13 ++++++------- spec/factorialSpec.js | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 spec/factorialSpec.js diff --git a/lib/factorial.js b/lib/factorial.js index 73ae2a9..e706269 100644 --- a/lib/factorial.js +++ b/lib/factorial.js @@ -9,8 +9,8 @@ const caclulateFactorial = (num) => { return factorialCache[num]; } - const start = factorialCache.length <= num ? factorialCache.length - 1 : num - 1; - for (let i = start + 1; i <= num; i += 1) { + const start = factorialCache.length; + for (let i = start; i <= num; i += 1) { factorialCache[i] = factorialCache[i - 1] * i; } @@ -29,12 +29,11 @@ const handleErrors = (params) => { throw new Error('One of your parameters does not evaluate to a integer'); } // Has to be a non negative integer - if (params.some(param => !isPositiveInteger(param))) { + if (params.some(param => !isPositiveInteger(param) && param !== 0)) { throw new Error('One of your parameters does not evaluate to a positive integer'); } - // JS can only safely represent and compare integers between - // Number.MAX_SAFE_INTEGER and Number.MAX_SAFE_INTEGER - if (params.some(param => param > Number.MAX_SAFE_INTEGER || param < Number.MIN_SAFE_INTEGER)) { - throw new Error('Cannot reliably test primality of numbers larger than 9,007,199,254,740,991 or smaller than -9,007,199,254,740,991'); + // JS can only safely represent integers less than Number.MAX_SAFE_INTEGER + if (params.some(param => param > 18)) { + throw new Error('Cannot reliably return numbers larger than 9,007,199,254,740,991'); } }; diff --git a/spec/factorialSpec.js b/spec/factorialSpec.js new file mode 100644 index 0000000..ac3fe00 --- /dev/null +++ b/spec/factorialSpec.js @@ -0,0 +1,24 @@ +const { factorial } = require('../lib/factorial'); + +describe('factorial', () => { + it('should return the factorial of all parameters, given that all parameters evaluate to numbers', () => { + const result = factorial(0, 1, 2, 3, 4); + expect(result).toEqual([1, 1, 2, 6, 24]); + }); + + it('should throw an error when no parameters are provided', () => { + expect(factorial).toThrow(); + }); + + it('should throw an error when at least one parameter does not evaluate to a number', () => { + expect(() => factorial(1, 2, 'yo')).toThrow(); + }); + + it('should throw an error when at least one parameter evaluates to a negative number', () => { + expect(() => factorial(1, 2, -1)).toThrow(); + }); + + it('should throw an error when at least one parameter evaluates to a number larger than 18', () => { + expect(() => factorial(1, 2, Number.MAX_SAFE_INTEGER)).toThrow(); + }); +}); From faf5e2df13791abb6924a35daa97002a4f295d18 Mon Sep 17 00:00:00 2001 From: Michael Flynn Date: Fri, 9 Feb 2018 09:00:25 -0500 Subject: [PATCH 3/3] Fix linting problem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit moved handleErrors up to avoid ‘no-use-before define’. Coding style changed on me. --- lib/factorial.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/factorial.js b/lib/factorial.js index e706269..f0b5229 100644 --- a/lib/factorial.js +++ b/lib/factorial.js @@ -2,6 +2,21 @@ const { isPositiveInteger } = require('./isPositiveInteger'); +const handleErrors = (params) => { + if (params.length === 0) throw new Error('Must provide one or more paramters'); + if (params.some(param => !Number.isInteger(param))) { + throw new Error('One of your parameters does not evaluate to a integer'); + } + // Has to be a non negative integer + if (params.some(param => !isPositiveInteger(param) && param !== 0)) { + throw new Error('One of your parameters does not evaluate to a positive integer'); + } + // JS can only safely represent integers less than Number.MAX_SAFE_INTEGER + if (params.some(param => param > 18)) { + throw new Error('Cannot reliably return numbers larger than 9,007,199,254,740,991'); + } +}; + const factorialCache = [1, 1]; const caclulateFactorial = (num) => { @@ -22,18 +37,3 @@ exports.factorial = (...params) => { return params.map(caclulateFactorial); }; - -const handleErrors = (params) => { - if (params.length === 0) throw new Error('Must provide one or more paramters'); - if (params.some(param => !Number.isInteger(param))) { - throw new Error('One of your parameters does not evaluate to a integer'); - } - // Has to be a non negative integer - if (params.some(param => !isPositiveInteger(param) && param !== 0)) { - throw new Error('One of your parameters does not evaluate to a positive integer'); - } - // JS can only safely represent integers less than Number.MAX_SAFE_INTEGER - if (params.some(param => param > 18)) { - throw new Error('Cannot reliably return numbers larger than 9,007,199,254,740,991'); - } -};