John the User
John the User

Reputation: 640

How can I find the prime factors of an integer in JavaScript?

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

Answers (21)

Alan Judi
Alan Judi

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

sergdenisov
sergdenisov

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

Ayan Saha
Ayan Saha

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

sayinmehmet47
sayinmehmet47

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

vitaly-t
vitaly-t

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

TheChiporpoise
TheChiporpoise

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

ashish siddhu
ashish siddhu

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

Luthfi Unnimoyin
Luthfi Unnimoyin

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

php and js
php and js

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

War10ck
War10ck

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

Dino
Dino

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

x7R5fQ
x7R5fQ

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

capote1789
capote1789

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

apollovishwas
apollovishwas

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

xgreed
xgreed

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

Hmorv
Hmorv

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

Xaqron
Xaqron

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

user42723
user42723

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

Flaming_Dorito
Flaming_Dorito

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

Vinayaka B R
Vinayaka B R

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

Matthieu Veillon
Matthieu Veillon

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

Related Questions