18

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]);
}
double-beep
  • 5,031
  • 17
  • 33
  • 41
John the User
  • 620
  • 2
  • 5
  • 13

21 Answers21

41

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!

Gershom Maes
  • 7,358
  • 2
  • 35
  • 55
Alan Judi
  • 1,074
  • 1
  • 16
  • 32
  • 3
    `while(n>=2)` to include 2 as well – ViES Jul 06 '20 at 22:53
  • `primeFactors(2*3*4) = [2, 2, 2, 3]` so another step to remove duplicate with hash needed – YoniXw Jun 08 '21 at 20:10
  • 1
    to complete my comment, the changes are: `const factors = {[prime]:true}` and then mark a prime found with `factors[divisor]=true;` and finally return `Object.keys(factors)` – YoniXw Jun 08 '21 at 20:18
  • The algorithm is incorrect and leads to an infinity loop with some numbers, for example `42243669067` – Denis L Sep 08 '21 at 21:27
  • 1
    This doesn't work well for large, complex numbers. JavaScript allows up to 2^53 of integer precision. I tried `primeFactors(2**50 - 2)`, had it run for an hour, and it didn't finish. – vitaly-t Nov 02 '21 at 08:32
  • oneliner - `var f = n => { let r = [], d = 2; while (n >= 2) { if (n % d == 0) { r.push(d); n = n / d; } else d++; } return r; }` – Dave Ankin Feb 02 '23 at 23:12
12

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].

double-beep
  • 5,031
  • 17
  • 33
  • 41
War10ck
  • 12,387
  • 7
  • 41
  • 54
9

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)
Matthieu Veillon
  • 150
  • 1
  • 2
  • 13
5

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]
ashish siddhu
  • 179
  • 4
  • 5
  • The time complexity remains O(n) because the code runs only one loop. this should be faster than many of the codes that I have seen here. great job. – Adesoft Apr 14 '22 at 08:51
  • The fact that it's a single loop doesn't guarantee it's `O(n)` - but in this case it is `O(n)` (because it will always do better than checking every number between 0 and `n`) – Gershom Maes Apr 27 '23 at 19:43
3

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)
    }
  }
}
Xaqron
  • 29,931
  • 42
  • 140
  • 205
3

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.

  • `haven't found one that runs consistently faster than it yet` - [this one run significantly faster](https://github.com/vitaly-t/prime-lib/blob/main/src/prime-factors.ts). – vitaly-t Nov 03 '21 at 06:02
  • `num /= 2` is probably slower than `num = num >> 1` – Gershom Maes Apr 28 '23 at 00:34
2

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}`)
Flaming_Dorito
  • 486
  • 3
  • 11
2

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))
Seph Reed
  • 8,797
  • 11
  • 60
  • 125
apollovishwas
  • 117
  • 1
  • 2
  • 1
    While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Nic3500 Sep 06 '18 at 10:57
1

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]

vitaly-t
  • 24,279
  • 15
  • 116
  • 138
1

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);
sergdenisov
  • 8,327
  • 9
  • 48
  • 63
0

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);
}
user42723
  • 467
  • 3
  • 8
0

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;
Hmorv
  • 156
  • 1
  • 14
0

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.

Community
  • 1
  • 1
capote1789
  • 76
  • 6
0

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 ]
x7R5fQ
  • 949
  • 2
  • 13
  • 27
0

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;
    }
  }
}
Praveen Soni
  • 771
  • 8
  • 21
Dino
  • 1
  • 2
  • 1
    It would be better if you can explain the logic also. It will be better for users who will come here in search of better explanation or code :) – Himanshu Bansal May 08 '20 at 17:21
  • Suppose integer is 88, aka 2*2*2*11. The i = i-1 statement makes it print 2 three times, by counteracting the i++ in the for loop. It will then (pointlessly) check 4 and 8, but will not print them because by then integer will be 11. Checking for non-primes is not mathematcially wrong, just wasteful. – Pete Lomax Jun 02 '21 at 13:09
0

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).

php and js
  • 867
  • 1
  • 6
  • 13
0

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));
Keegan Murphy
  • 767
  • 3
  • 14
sayinmehmet47
  • 490
  • 5
  • 21
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 15 '22 at 15:29
0

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));
Ayan Saha
  • 1
  • 1
-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);
-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);
                        } 
                } 
            }
        }
    }
}
xgreed
  • 1
  • 1
-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);
Majid Hajibaba
  • 3,105
  • 6
  • 23
  • 55