Reputation: 640
I was trying to find the prime factors of a number, recorded below as 'integer' using a for loop in javascript. I can't seem to get it working and I'm not sure whether it's my JavaScript or my calculation logic.
//integer is the value for which we are finding prime factors
var integer = 13195;
var primeArray = [];
//find divisors starting with 2
for (i = 2; i < integer/2; i++) {
if (integer % i == 0) {
//check if divisor is prime
for (var j = 2; j <= i / 2; j++) {
if (i % j == 0) {
isPrime = false;
} else {
isPrime = true;
}
}
//if divisor is prime
if (isPrime == true) {
//divide integer by prime factor & factor store in array primeArray
integer /= i
primeArray.push(i);
}
}
}
for (var k = 0; k < primeArray.length; k++) {
console.log(primeArray[k]);
}
Upvotes: 18
Views: 40380
Reputation: 1092
Here is an answer with O(N) complexity.
function primeFactors(n) {
const factors = [];
let divisor = 2;
while (n >= 2) {
if (n % divisor == 0) {
factors.push(divisor);
n = n / divisor;
} else {
divisor++;
}
}
return factors;
}
const randomNumber = Math.floor(Math.random() * 10000);
console.log('Prime factors of', randomNumber + ':', primeFactors(randomNumber).join(' '))
You can filter for duplicates as you please!
Upvotes: 42
Reputation: 8572
The answer with O(sqrt(n)) complexity, it's faster than O(n):
const number = 13195;
let divisor = 2;
const result = [];
let n = number;
while (divisor * divisor <= number) {
if (n % divisor === 0) {
result.push(divisor);
n /= divisor;
} else {
divisor++;
}
}
if (n > 1) {
result.push(n);
}
console.log(result);
Upvotes: 2
Reputation: 1
function primeFactorization(n) {
let factors = [];
while (n % 2 === 0) {
factors.push(2);
n = n / 2;
}
for (let i = 3; i <= Math.sqrt(n); i += 2) {
while (n % i === 0) {
factors.push(i);
n = n / i;
}
}
if (n > 2) {
factors.push(n);
}
return factors;
}
console.log(primeFactorization(100));
Upvotes: 0
Reputation: 551
Here is the solution with the nested function using the filter method.
function primeFactors(params) {
function prime(number) {
for (let i = 2; i < number + 1; ) {
if (number === 2) {
return true;
}
if (number % i === 0 && number !== i) {
return false;
} else if (i < number) {
i++;
} else {
return true;
}
}
}
let containerPrime = [];
let containerUnPrime = [];
for (let i = 0; i < params; i++) {
if (prime(i)) {
containerPrime.push(i);
} else {
containerUnPrime.push(i);
}
}
return containerPrime.filter((e) => params % e === 0);
}
console.log(primeFactors(13195));
Upvotes: 0
Reputation: 25840
In case somebody is looking for the fastest solution, here's one based on my library prime-lib. It can calculate prime factors for any number between 2 and 2^53 - 1, in under 1ms. The function source code is available here.
import {primeFactors} from 'prime-lib';
const factors = primeFactors(600851475143);
//=> [71, 839, 1471, 6857]
Upvotes: 1
Reputation: 45
I've refined this function over time, trying to get it as fast as possible (racing it against others' functions that I've found online, haven't found one that runs consistently faster than it yet).
function primFact(num) {
var factors = [];
/* since 2 is the only even prime, it's easier to factor it out
* separately from the odd factor loop (for loop doesn't need to
* check whether or not to add 1 or 2 to f).
* The condition is essentially checking if the number is even
* (bitwise "&" operator compares the bits of 2 numbers in binary
* and outputs a binary number with 1's where their digits are the
* same and 0's where they differ. In this case it only checks if
* the final digit for num in binary is 1, which would mean the
* number is odd, in which case the output would be 1, which is
* interpreted as true, otherwise the output will be 0, which is
* interpreted as false. "!" returns the opposite boolean, so this
* means that '!(num & 1)' is true when the num is not odd)
*/
while (!(num & 1)) {
factors.push(2);
num /= 2;
}
// 'f*f <= num' is faster than 'f <= Math.sqrt(num)'
for (var f = 3; f*f <= num; f += 2) {
while (!(num % f)) { // remainder of 'num / f' isn't 0
factors.push(f);
num /= f;
}
}
/* if the number is already prime, then this adds it to factors so
* an empty array isn't returned
*/
if (num != 1) {
factors.push(num);
}
return factors;
}
This performs very well at large numbers compared to functions I've run it against, especially when the number is prime, (rarely runs slower than 10ms when I've run it in an online compiler like OneCompiler) so if you want speed I'd say this is a pretty good way to go about it.
Still working on making it even faster, but only way to include all primes without adding new conditions to check is to iterate through all odd numbers.
Upvotes: 4
Reputation: 219
We can find the prime factor numbers up to n with only one loop. It is a very simple solution without any nested loop.
Time complexity would be less than O(n) because we are dividing "n" by "i".
function primeFactors(n) {
let arr=[];
let i = 2;
while(i<=n){
if(n%i == 0) {
n= n/i;
arr.push(i);
} else {
i++;
}
}
return arr;
}
// primeFactors(10) [2,5]
// primeFactors(10) [2,2,5,5]
// primeFactors(2700) [2, 2, 3, 3, 3, 5, 5]
Upvotes: 5
Reputation: 1
var n = 100, arr =[],primeNo = [],priFac=[];
for(i=0;i<=n;i++){
arr.push(true);
}
//console.log(arr)
let uplt = Math.sqrt(n)
for(j=2;j<=uplt;j++){
if(arr[j]){
for(k=j*j;k<=n;k+=j){
arr[k] = false;
}
}
}
for(l=2;l<=n;l++){
if(arr[l])
primeNo.push(l)
}
for(m=0;m<primeNo.length;m++){
if(n%primeNo[m]==0)
priFac.push(primeNo[m])
}
console.log(...priFac);
Upvotes: -1
Reputation: 971
I checked the algorithm with yield, but that is a lot slower than recursive calls.
function rootnth(val, power=2) {
let o = 0n; // old approx value
let x = val;
let limit = 100;
let k = BigInt(power);
while(x**k!==k && x!==o && --limit) {
o=x;
x = ((k-1n)*x + val/x**(k-1n))/k;
}
return x;
}
// Example: 24 -> 2, 2, 2, 3
function repeatedPrimeFactors (n,list) {
if (arguments.length == 1) list = "";
if (n % 2n == 0) return repeatedPrimeFactors(n/2n, list + "*2")
else if (n % 3n == 0) return repeatedPrimeFactors(n/3n, list + "*3")
var sqrt = rootnth(n);
let k = 5n;
while (k <= sqrt) {
if (n % k == 0) return repeatedPrimeFactors(n/k, list + "*" + k)
if (n % (k+2n) == 0) return repeatedPrimeFactors(n/(k+2n), list + "*" + (k+2n))
k += 6n;
}
list = list + "*" + n;
return list;
}
var q = 11111111111111111n; // seventeen ones
var t = (new Date()).getTime();
var count = repeatedPrimeFactors(BigInt(q)).substr(1);
console.log(count);
console.log(("elapsed=" + (((new Date()).getTime())-t)+"ms");
Here I try for the factors 2 and 3, followed by alternatingly adding 2 anf 4 (5,7,11,13,17,...) until the square root of the number. Seventeen ones (which is not prime) takes about 1 second and nineteen ones (which is prime) eight seconds (Firefox).
Upvotes: 0
Reputation: 12508
Here's a working solution:
function getPrimeFactors(integer) {
const primeArray = [];
let isPrime;
// Find divisors starting with 2
for (let i = 2; i <= integer; i++) {
if (integer % i !== 0) continue;
// Check if the divisor is a prime number
for (let j = 2; j <= i / 2; j++) {
isPrime = i % j !== 0;
}
if (!isPrime) continue;
// if the divisor is prime, divide integer with the number and store it in the array
integer /= i
primeArray.push(i);
}
return primeArray;
}
console.log(getPrimeFactors(13195).join(', '));
You were very much on the right track. There were two minor mistakes. The evaluation of integer - 1
seemed to be incorrect. I believe the more appropriate evaluation is <= integer
in your outer for
loop. This is because when you divide your integer below integer /= i
, this results in the final integer evaluation to be 29
. The final prime divisor in this case is also 29
and as such will need to be evaluated as <=
as oppose to < integer - 1
.
As for why the final log statement isn't working, there was a simple typo of primeArray[i]
as oppose to primeArray[k]
.
Upvotes: 12
Reputation: 1
I found this solution by chance when i was trying to simplify several solutions that i saw here. Although it doesn't check if the divisor is a prime number somehow it seems to work, i tested it with miscellaneous numbers but i could not explain how this was possible.
function start() {
var integer = readInt("Enter number: ");
println("The prime factorization is: ");
for(var i = 2; i <= integer; i++) {
if (integer % i == 0) {
println(i);
integer = integer / i;
i = i - 1;
}
}
}
Upvotes: 0
Reputation: 1029
Here is a solution using recursion
function primeFactors(num, primes){
let i = 2;
while(i < num){
if(num % i === 0){
primes.push(i);
return primeFactors(num/i, primes);
}
i++
}
primes.push(num);
return primes;
}
console.log(primeFactors(55, []))
console.log(primeFactors(15, []))
console.log(primeFactors(40, []))
console.log(primeFactors(13, []))
// [ 5, 11 ]
// [ 3, 5 ]
// [ 2, 2, 2, 5 ]
// [ 13 ]
Upvotes: 0
Reputation: 76
With so many good solutions above, wanted to make a little bit of improvement by using this theorem in the Math Forum Finding prime factors by taking the square root .
function primeFactors(n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
console.log(2);
n = n/2;
}
// n must be odd at this point. So we can skip
// one element (Note i = i +2)
for (var i = 3; i <= Math.sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
console.log(i);
n = n/i;
}
}
// This condition is to handle the case when n
// is a prime number greater than 2
if (n > 2)
console.log(n);
}
primeFactors(344);
console.log("--------------");
primeFactors(4);
console.log("--------------");
primeFactors(10);
Hope this answer adds value.
Upvotes: 0
Reputation: 137
If you work up from the bottom there's no need to check if any following factor is prime. This is because any lower primes will have already been divided out.
function getPrimeFactorsFor(num) {
const primes = [];
for (let factor = 2; factor <= num; factor++) {
while ((num % factor) === 0) {
primes.push(factor);
num /= factor;
}
}
return primes;
}
console.log("10 has the primes: ", getPrimeFactorsFor(10));
console.log("8 has the primes: ", getPrimeFactorsFor(8));
console.log("105 has the primes: ", getPrimeFactorsFor(105))
console.log("1000 has the primes: ", getPrimeFactorsFor(1000))
console.log("1155 has the primes: ", getPrimeFactorsFor(1155))
Upvotes: 2
Reputation: 1
This is my solution
function prime(n) {
for (var i = 1; i <= n; i++) {
if (n%i===0) {
myFact.push(i);
var limit = Math.sqrt(i);
for (var j = 2; j < i; j++) {
if (i%j===0) {
var index = myFact.indexOf(i);
if (index > -1) {
myFact.splice(index, 1);
}
}
}
}
}
}
Upvotes: -1
Reputation: 146
My solution avoids returning not prime factors:
let result = [];
let i = 2;
let j = 2;
let number = n;
for (; i <= number; i++) {
let isPrime = number % i === 0;
if (isPrime) {
result.push(i);
number /= i;
}
while (isPrime) {
if (number % i === 0) {
result.push(i);
number /= i;
} else {
isPrime = false;
}
}
}
return result;
Upvotes: 0
Reputation: 30837
When factorizing an integer (n
) to its prime factors, after finding the first prime factor, the problem in hand is reduced to finding prime factorization of quotient (q
).
Suppose n
is divisible to prime p1
then we have n = p1 * q1
so after finding p1
the problem is reduced to factorizing q1
(quotient). If the function name is primeFactorizer
then we can call it recursively and solution for n
would be:
n = p1 * primeFactorizer(q1)
n = p1 * p2 * primeFactorizer(q2)
...
Until
qn
is prime itself.
Also I'm going to use a helper generator function which generates primes for us:
function * primes () {
let n = 2
while (true) {
let isPrime = true
for (let i = 2; i <= n / 2; i++) {
if (n % i === 0) {
isPrime = false
break
}
}
if (isPrime) {
yield n
}
n++
}
}
And function to factorize n
would be:
function primeFactorizer (n, result = []) {
for (const p of primes()) {
if (n === p) {
result.push(p)
return result
}
if (n % p === 0) {
result.push(p)
return primeFactorizer(n / p, result)
}
}
}
Upvotes: 3
Reputation: 589
Here an other implementation to find prime factors, in three variations. It's more efficient than the other implementations, worst case sqrt(n)
, because it stops earlier.
The function*
means it's a generator function. So a generator is returned instead of an array and the next prime factor is only calculated as soon as it is requested.
// Example: 24 -> 2, 3
function* singlePrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
if (n % k == 0) {
yield k
do {n /= k} while (n % k == 0)
}
}
if (n > 1) yield n
}
// Example: 24 -> 2, 2, 2, 3
function* repeatedPrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
while (n % k == 0) {
yield k
n /= k
}
}
if (n > 1) yield n
}
// Example: 24 -> {p: 2, m: 3}, {p: 3, m: 1}
function* countedPrimeFactors (n) {
for (var k = 2; k*k <= n; k++) {
if (n % k == 0) {
var count = 1
for (n /= k; n % k == 0; n /= k) count++
yield {p: k, m: count}
}
}
if (n > 1) yield {p: n, m: 1}
}
// Test code
for (var i=1; i<=100; i++) {
var single = JSON.stringify(Array.from(singlePrimeFactors(i)))
var repeated = JSON.stringify(Array.from(repeatedPrimeFactors(i)))
var counted = JSON.stringify(Array.from(countedPrimeFactors(i)))
console.log(i, single, repeated, counted)
}
// Iterating over a generator
for (var p of singlePrimeFactors(24)) {
console.log(p)
}
// Iterating over a generator, an other way
var g = singlePrimeFactors(24)
for (var r = g.next(); !r.done; r = g.next()) {
console.log(r.value);
}
Upvotes: 0
Reputation: 486
I just started JavaScript but i managed to come up with my own solution for this while working on a school project with a similar objective.
Only issue is that it takes a very long time for large numbers, its not v ery efficient. But it works perfectly.
function isPrime(n){
if (n === 1){
return false;
}
else if (n === 2){
return true;
}
else{
for (let x = 2; x < n; x ++){
if (n % x === 0){
return false;
}
}
return true;
}
}
let primeFac = []
let num = 30
for (let x = 0; x <= num; x++){
if (num % x === 0 && isPrime(x) === true){
primeFac.push(x);
}
}
console.log(`${primeFac}`)
Upvotes: 2
Reputation: 1
The above code (the code which has while loop) is correct, but there is one small correction in that code.
var num, i, factorsArray = [];
function primeFactor(num) {
for (i = 2; i <= num; i++) {
while (num % i == 0) {
factorsArray.push(i);
num = num / 2;
}
}
}
primeFactor(18);
var newArray = Array.from(new Set(factorsArray));
document.write(newArray);
Upvotes: -1
Reputation: 180
I do believe there is a mistake in both code above. If you replace the integer by 100 the prime factorization won't work anymore as the factor 2 cannot be considered with those for loops. As j = 2, i = 2 and j<=i/2 in the condition - meaning the loop will never run for i=2, which is a prime factor.
Tried to make it work this way but couldn't figure out.
Had to rely on a different approach with a while loop here :
function getAllFactorsFor(remainder) {
var factors = [], i;
for (i = 2; i <= remainder; i++) {
while ((remainder % i) === 0) {
factors.push(i);
remainder /= i;
}
}
return factors;
}
https://jsfiddle.net/JamesOR/RC7SY/
You could also go with something like that :
let findPrimeFactors = (num) => {
let arr = [];
for ( var i = 2; i < num; i++) {
let isPrime
if (num % i === 0) {
isPrime = true;
for (var j = 2; j <= i; j++) {
if ( i % j === 0) {
isPrime == false;
}
}
}if (isPrime == true) { arr.push(i)}
}console.log(arr)
}
findPrimeFactors(543)
Upvotes: 10