diff --git a/Algorithms.ts b/Algorithms.ts index 1a2fecd..a5e34c3 100644 --- a/Algorithms.ts +++ b/Algorithms.ts @@ -21,6 +21,10 @@ Copyright (C) 2020 Matthew Ellison */ +import { kMaxLength } from "buffer"; +import { InvalidResult } from "./InvalidResult"; + + export function arrayEquals(array1: any[], array2: any[]): boolean{ //If they aren't the same type they aren't equal if((typeof array1) != (typeof array2)){ @@ -42,6 +46,25 @@ export function arrayEquals(array1: any[], array2: any[]): boolean{ return true; } } + +export function sqrtBig(value: bigint): bigint{ + if(value < 0n){ + throw "Negative numbers are not supported"; + } + + let k = 2n; + let o = 0n; + let x = value; + let limit = 100; + + while(x ** k !== k && x !== o && --limit){ + o = x; + x = ((k - 1n) * x + value / x ** (k - 1n)) / k; + } + + return x; +} + export function getAllFib(goalNumber: number): number[]{ //Setup the variables let fibNums: number[] = []; @@ -76,14 +99,14 @@ export function getAllFibBig(goalNumber: bigint): bigint[]{ if(goalNumber <= 0){ return fibNums; } - else if(goalNumber == BigInt(1)){ - fibNums.push(BigInt(1)); + else if(goalNumber == 1n){ + fibNums.push(1n); return fibNums; } //This means that at least 2 1's are elements - fibNums.push(BigInt(1)); - fibNums.push(BigInt(1)); + fibNums.push(1n); + fibNums.push(1n); //Loop to generate the rest of the Fibonacci numbers while(fibNums[fibNums.length - 1] <= goalNumber){ @@ -95,3 +118,172 @@ export function getAllFibBig(goalNumber: bigint): bigint[]{ return fibNums; } +export function getPrimes(goalNumber: number): number[]{ + let primes: number[] = []; //Holds the prime numbers + let foundFactor: boolean = false; //A flag for whether a factor of the current number has been found + + //If the number is 0 or a negative return an empty list + if(goalNumber <= 1){ + return primes; + } + //Optherwise the number is at least 2, so 2 should be added to the list + else{ + primes.push(2); + } + + //We can now start at 3 and skip all even numbers, because they cannot be prime + for(let possiblePrime: number = 3;possiblePrime <= goalNumber;possiblePrime += 2){ + //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor + let topPossibleFactor: number = Math.ceil(Math.sqrt(possiblePrime)); + //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this + for(let primesCnt: number = 0;primes[primesCnt] <= topPossibleFactor;){ + if((possiblePrime % primes[primesCnt]) == 0){ + foundFactor = true; + break; + } + else{ + ++primesCnt; + } + //Check if the index has gone out of range + if(primesCnt >= primes.length){ + break; + } + } + + //If you didn't find a factor then the current number must be prime + if(!foundFactor){ + primes.push(possiblePrime); + } + else{ + foundFactor = false; + } + } + + //Sort the list before returning it + primes = primes.sort((n1, n2) => n1 - n2); + return primes; +} +export function getPrimesBig(goalNumber: bigint): bigint[]{ + let primes: bigint[] = []; //Holds the prime numbers + let foundFactor: boolean = false; //A flag for whether a factor of the current number has been found + + //If the number is 0 or a negative return an empty list + if(goalNumber <= 1){ + return primes; + } + //Optherwise the number is at least 2, so 2 should be added to the list + else{ + primes.push(2n); + } + + //We can now start at 3 and skip all even numbers, because they cannot be prime + for(let possiblePrime: bigint = 3n;possiblePrime <= goalNumber;possiblePrime += 2n){ + //Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor + let topPossibleFactor: bigint = sqrtBig(possiblePrime); + //We can safely assume that there will be at least 1 element in the primes list because of 2 being added before this + for(let primesCnt: number = 0;primes[primesCnt] <= topPossibleFactor;){ + if((possiblePrime % primes[primesCnt]) == 0n){ + foundFactor = true; + break; + } + else{ + ++primesCnt; + } + //Check if the index has gone out of range + if(primesCnt >= primes.length){ + break; + } + } + + //If you didn't find a factor then the current number must be prime + if(!foundFactor){ + primes.push(possiblePrime); + } + else{ + foundFactor = false; + } + } + + //Sort the list before returning it + primes = primes.sort(function(n1, n2){ + if(n1 > n2){ + return 1; + } + else if(n1 < n2){ + return -1; + } + else{ + return 0; + } + }); + return primes; +} + +export function getFactors(goalNumber: number): number[]{ + //You need to get all the primes that could be factors of this number so you can test them + let topPossiblePrime: number = Math.ceil(Math.sqrt(goalNumber)); + let primes: number[] = getPrimes(topPossiblePrime); + let factors: number[] = []; + + //You need to step through each prime and see if it is a factor in the number + for(let cnt: number = 0;cnt < primes.length;){ + //If the prime is a factor you need to add it to the factor list + if((goalNumber % primes[cnt]) == 0){ + factors.push(primes[cnt]); + goalNumber /= primes[cnt]; + } + //Otherwise advance the location in primes you are looking at + //By not advancing f the prime is a factor you allow for multiple of the same prime number as a factor + else{ + ++cnt; + } + } + + //If you didn't get any factors the number itself must be a prime + if(factors.length == 0){ + factors.push(goalNumber); + goalNumber /= goalNumber; + } + + //If for some reason the goalNumber is not 1 throw an exception + if(goalNumber != 1){ + throw new InvalidResult("The factor was not 1: " + goalNumber); + } + + //Return the list of factors + return factors; +} +export function getFactorsBig(goalNumber: bigint): bigint[]{ + //You need to get all the primes that could be factors of this number so you can test them + let topPossiblePrime: bigint = sqrtBig(goalNumber); + let primes: bigint[] = getPrimesBig(topPossiblePrime); + let factors: bigint[] = []; + + //You need to step through each prime and see if it is a factor in the number + for(let cnt: number = 0;cnt < primes.length;){ + //If the prime is a factor you need to add it to the factor list + if((goalNumber % primes[cnt]) == 0n){ + factors.push(primes[cnt]); + goalNumber /= primes[cnt]; + } + //Otherwise advance the location in primes you are looking at + //By not advancing f the prime is a factor you allow for multiple of the same prime number as a factor + else{ + ++cnt; + } + } + + //If you didn't get any factors the number itself must be a prime + if(factors.length == 0){ + factors.push(goalNumber); + goalNumber /= goalNumber; + } + + //If for some reason the goalNumber is not 1 throw an exception + if(goalNumber != 1n){ + throw new InvalidResult("The factor was not 1: " + goalNumber); + } + + //Return the list of factors + return factors; +} diff --git a/TestAlgorithms.ts b/TestAlgorithms.ts index bf72bfc..3969cee 100644 --- a/TestAlgorithms.ts +++ b/TestAlgorithms.ts @@ -21,7 +21,7 @@ Copyright (C) 2020 Matthew Ellison */ import assert = require("assert"); -import { arrayEquals, getAllFib, getAllFibBig } from "./Algorithms"; +import { arrayEquals, getAllFib, getAllFibBig, getFactors, getFactorsBig, getPrimes, getPrimesBig } from "./Algorithms"; function testGetAllFib(){ @@ -29,22 +29,61 @@ function testGetAllFib(){ let correctAnswer = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]; let highestNumber = 100; let answer = getAllFib(highestNumber); - assert.ok(arrayEquals(answer, correctAnswer), "getAllFib Integer 1 failed"); + assert.ok(arrayEquals(answer, correctAnswer), "getAllFib number 1 failed"); //Test 2 correctAnswer = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987] highestNumber = 1000; answer = getAllFib(highestNumber); - assert.ok(arrayEquals(answer, correctAnswer), "getAllFib Integer 2 failed"); + assert.ok(arrayEquals(answer, correctAnswer), "getAllFib number 2 failed"); //Test 3 - let bigCorrectAnswer = [BigInt(1), BigInt(1), BigInt(2), BigInt(3), BigInt(5), BigInt(8), BigInt(13), BigInt(21), BigInt(34), BigInt(55), BigInt(89)]; - let bigHighestNumber = BigInt(100); + let bigCorrectAnswer = [1n, 1n, 2n, 3n, 5n, 8n, 13n, 21n, 34n, 55n, 89n]; + let bigHighestNumber = 100n; let bigAnswer = getAllFibBig(bigHighestNumber); assert.ok(arrayEquals(bigAnswer, bigCorrectAnswer), "getAllFibBig failed"); console.log("testGetAllFib passed"); } +function testGetPrimes(){ + //Test1 + let correctAnswer = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]; + let topNum = 100; + let answer = getPrimes(topNum); + assert.ok(arrayEquals(answer, correctAnswer), "getPrimes number failed"); + + //Test 2 + let bigCorrectAnswer = [2n, 3n, 5n, 7n, 11n, 13n, 17n, 19n, 23n, 29n, 31n, 37n, 41n, 43n, 47n, 53n, 59n, 61n, 67n, 71n, 73n, 79n, 83n, 89n, 97n]; + let bigTopNum = 100n; + let bigAnswer = getPrimesBig(bigTopNum); + assert.ok(arrayEquals(bigAnswer, bigCorrectAnswer), "getPrimesBig failed"); + + console.log("getPrimes passed"); +} + +function testGetFactors(){ + //Test 1 + let correctAnswer = [2, 2, 5, 5]; + let number = 100; + let answer = getFactors(number); + assert.ok(arrayEquals(answer, correctAnswer), "getFactor number 1 failed"); + //Test 2 + correctAnswer = [2, 7, 7]; + number = 98; + answer = getFactors(number); + assert.ok(arrayEquals(answer, correctAnswer), "getFactor number 2 failed"); + + //Test 3 + let bigCorrectAnswer = [2n, 7n, 7n]; + let bigNumber = 98n; + let bigAnswer = getFactorsBig(bigNumber); + assert.ok(arrayEquals(answer, correctAnswer), "getFactors BigInt failed"); + + console.log("getFactors passed"); +} + //Run all of the tests -testGetAllFib(); \ No newline at end of file +testGetAllFib(); +testGetPrimes(); +testGetFactors();