Massive for loop taking too long to load - javascript

I'm working on a program designed to generate prime numbers, and I'm trying to find the 10001st prime number. Each time the loop runs, it tests variable i to see if it's divisible by variable j, which is part of another loop that goes up to half of i. If i is divisible by j then it adds one to variable prime, and when the loop's done it checks to see if variable prime is larger than two; if it is, then i is not prime. If it is prime, it gets push()ed to the variable array, which stores all the primes. Sorry if that's a little confusing.
My problem is that although this code works, whenever I set the first for loop too high (here I have it end at 100000), my browser freezes:
var prime = 0;
var array = [];
for(var i = 2; i <= 100000; i+=1) {
var prime = 0;
for(var j = 0; j <= i/2; j+=1) {
if(i % j === 0) {
prime += 1;
}
}
if(prime < 2) {
array.push(i);
}
}
console.log(array.length)
I know I could just copy and paste all the prime numbers but I want to make the program work. Any ideas to make the program stop freezing?

This is because the time complexity of your algorithm is pretty much O(n^2). Sieve of Eratosthenes created a better algorithm that will prevent your browser from freezing.
Here is one way of doing it:
var exceptions = {
2: 2,
3: 3,
5: 5,
7: 7
}
var primeSieve = function (start, end) {
var result = [];
for (start; start < end; start++) {
if (start in exceptions) result.push(start);
if (start > 1 && start % 2 !== 0 && start % 3 !== 0 && start % 5 !== 0 && start % 7 !== 0) {
result.push(start);
}
}
return result;
};
You can obviously make this look prettier, but I just did it quickly so you can get the point. I hope this helps! Let me know if you have further questions.

Related

How can I make this code faster where I have to print the total of odds of a given number?

The problem is: Print out how much odd numbers there are in a given number.
function oddCount(n) {
var odd = [];
for (i = 0; i < n; i++) {
if (i % 2 == 1) {
odd.push([i]);
}
}
return odd.length;
}
console.log(oddCount(8));
As we can see, it works properly, however, on codewars, it wants me to optimize it to run faster. Can someone show me how so I can learn it quickly please.
function oddCount(n) {
var odd = [];
for (i = 0; i < n; i++) {
if (i & 0x1 == 1) {
odd.push([i]);
}
}
return odd.length;
}
console.log(oddCount(8));
or
function oddCount(n) {
return (n - (n & 0x01)) / 2;
}
console.log(oddCount(8));
Neither "ceil" or "floor" is a correct answer as a one liner. "ceil" will make the division Base 1, "floor" will make the division Base 0. So both could be used in an implementation, but the "polarity" of n matters.
It's necessary to check whether the input number is odd or even.
function oddCount(n) {
// odd / even check
if (n % 2 == 0) {
// its even, we can divide by 2
return n / 2
}
else {
// n is odd, so we must include n as a count+1 itself
return ((n - 1) / 2) + 1
}
}
// Disclaimer: Are negative numbers odd or even? In this code they
// apparently aren't handled. So the set of numbers are integers from
// 0 to +Infinity
// Test cases:
console.log( oddCount(8) ); // 4
console.log( oddCount(9) ); // 5
But this code "breaks" if n itself is 0 or less. So we need to fix it:
Right after we say function oddCount(n) {, put:
if (n < 1) return 0;
All worries solved. But still debate on whether 0 is odd or even, and whether -1 is odd and -2 is even.
I believe this should work.
function oddCount(n) {
return Math.ceil(n/2);
}
console.log(oddCount(8));
If the number is an even number, there's n/2 odd numbers
Eg if n is 6
*1*,2,*3*,4,*5*,6
If it is an odd number, there's n/2+1 odd numbers. Because n-1 would be even
Eg if n is 5
*1*,2,*3*,4, + *5*
So basically
if (n%2==0) return n/2
else return (n-1)/2+1
The for loops aren't needed
Also like the others pointed out, ceiling is a more concise way to do it
return Math.ceil(n/2)

Why is unshift() returning a different value than push() if I am targeting the first element in the former and the last element in the latter?

I have a function for Project Euler #7. Towards the end, I changed the code from primeArray.push(i); to primeArray.unshift(i) and return primeArray[primeArray.length - 1]; to return primeArray[0];. This altered the return. In the former. It returned the correct answer, 104021, while the latter returned 20001, which is not even prime. I do not understand why that is.
function primeFinder(primeTarget) {
//since 2 is the only even prime, putting it here saves us some effort in checking primality by just iterating over the odd numbers
//it also helps the for loop since we are only interested in checking for divisors among previous primes.
let primeArray = [2];
let i = 3;
while (primeArray.length < primeTarget) {
let primeLogger = false;
//We don't need to check for divisibility by 2, so j can equal 1
for (j = 1; j < primeArray.length && primeArray[j] < Math.sqrt(i); j++) {
if (i % primeArray[j] === 0) {
primeLogger = true;
//Since we have found a divisor and changed primeLogger, we can exit the loop
break;
}
}
//Where the break goes to, and also where the for loop goes to once finishes
if (primeLogger === false) {
primeArray.push(i);
}
i += 2;
}
return primeArray[primeArray.length - 1];
}
console.log(primeFinder(10001));
Because primeArray is now in descending order but your loop still searches from start to end; now from biggest towards smaller values. Until it finds something that is >= Math.sqrt(i) which most likely will be the very first check, j=1.
Then it ends the loop with primeLogger === false
so for example, for:
i=9, j=1
primeArray === [7,5,3,2]
primeArray[j] === 5
And since the check 5 < Math.sqrt(9) is false the loop is finished.
Therefore 9 is a prime number and is now added to the start of primeArray.

Counting every 5th for loop

I'm having a hard time with this problem here:
Write a function named sumEvery5th that accepts a non-negative integer n and returns the sum of the integers divisible by 5 from 1 to n, including n itself. Use a for loop.
This is what I have so far:
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; n % 5 == 0; i++){
sum+ i
};
return sum;
}
I feel like I'm really close. Thanks for the help in advance.
You can start your loop at 5, since 1, 2... are not divisible by 5. And instead of i++, you can directly go 5 by 5, until i is greater than n:
var sumEvery5th = function(n) {
let sum = 0;
for (let i = 5; i <= n; i += 5) {
sum += i;
};
return sum;
}
console.log(sumEvery5th(10)); // 5 + 10 = 15
console.log(sumEvery5th(18)); // 5 + 10 + 15 = 30
First I think you should understand how a for loop works.
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; n % 5 == 0; i++){
sum+ i
};
return sum;
}
What you are doing, step by step, is:
Declaring a variable i with value 1.
Dividing n by 5 and taking the remainder value and comparing it with 0. In case it's true, you are skipping the code block inside the for and moving towards the return sum; line.
(In case you haven't skipped the code block in step 2) Run the code block with the new i value.
(In case you haven't skipped the code block in step 2) Incrementing the i value.
Go back to step 2.
Usually your for condition will depend in the variable declared in step 1. What you want to do is run the for code block n times.
For that, you need to change your condition from n % 5 == 0 to i <= n. This will make sure to run the code block while your i is less or equal than n, starting with a value of 1.
Now, inside your code block you add your divisible by 5 logic, checking against i value.
for(let i = 1; i <= n; i++){
if (i%5 == 0) sum += i;
};
Now let's say I called sumEvery5th(5).
Declare a variable i with value 1.
Check if i (1) is less than or equal n (5).
Go inside the code block.
Check if i%5 is 0.
It's not.
Increment i, now i = 2.
Check if i (2) is less than or equal n (5).
...And so on, until i = 6, and in that case the code block is skipped and the program will continue its course.
Ps.: There are ways to improve the performance of this algorithm, but now that you understand your for loop a bit better I'll leave it to you :)
var sumEvery5th = function(n){
let sum = 0;
for(let i = 1; i <= n; i++){
if (i % 5 === 0) {
sum += i;
}
}
return sum;
}

Largest prime factor function works too slow

I have written the function which finds largest prime factor of some number. This function works but the problem is that it is too slow. e.g when I enter 600851475143 as a parameter, the process of finding largest prime factor lasts too long. How can I modify it so that it works faster?
Here is my code:
class test {
static addArray(someArray, member) {
for (var i = 0; i <= someArray.length; i++) {
if (i == someArray.length) {
someArray[i] = member;
return someArray;
}
}
}
static someLength(someArray) {
var i = 0;
while (someArray[i] !== undefined) {
var lastItem = i;
i++;
}
return i;
}
static testPrime(i) {
for (var k=2; k < i; k++) {
if (i % k == 0) {
return false;
}
}
return true;
}
}
var primeArray = [];
function largestPrime(n) {
for (var i=2; i < n; i++) {
//var k = n / i;
if (n % i == 0 && test.testPrime(i) == true) {
test.addArray(primeArray, i);
n == n / i;
}
}
return primeArray[test.someLength(primeArray) - 1];
}
document.write(largestPrime(600851475143));
Alright, before we go into that, let's get a little bit of theory sorted. The way you measure the time a particular piece of code takes to run is, mathematically, denoted by the O(n) notation (big-o notation) where n is the size of the input.
Your test prime function is of something called linear complexity meaning that it'll become linearly slow as the size of n (in this case, your number input) gets large.
For the number 15, the execution context is as follows:
15 % 2 == 0 (FALSE)
15 % 3 == 0 (TRUE)
...
15 % 14 == 0 (FALSE)
This means that for the number 100, there will be 98 (2 - 99) steps. And this will grow with time. Let's take your number into consideration: 600851475143. The program will execute 600851475143; the for-loop will get triggered 600,851,475,141 times.
Now, let's consider a clock cycle. Say each instruction takes 1 clock cycle, and a dumbed down version of your loop takes 2, the number 600851475143 will execute 1,201,702,950,286 times. Consider each clock cycle takes 0.0000000625 seconds (for a 16-MHz platform such as the Arduino), the time taken by that code alone is:
0.0000000625 * 1201702950286 = ~75,106 seconds
Or around 20 hours.
You see where I am going with this.
Your best best to get this program to work faster is to use a probabilistic test and confirm your findings using this number (or a BigInteger variant thereof).
Your approach is more linear, in the sense that the number of iterations for the for-loop to check for primality increases with an increasing number. You can plot the CPU cycle time along with the number and you'll realize that this is a rather inefficient way to do this.
I have discrete mathematics at my Uni, so just a word of warning - primality tests and their variants get really messy as you get into the utopia of faster and faster tests. It's a path filled with thorns of mathematics and you should have a seat belt while riding through the jungle! ;)
If you need more information on this, I would be glad to assist! I hope this helped! :)

JavaScript Prime Number Generator

I'm trying to write a JavaScript prime number generator that lists every prime between 1 and 100. I know this is a common programming exercise and there's an abundance of solutions on the web. My question is why does my solution result an empty array? Here's the code:
var primeNumbers = [];
for (var x=2; x<101; x++)
if (x%2 === 0)
{
break;
}
else
{
for (var y=2; y<101; y++)
{
if (x/y > 1)
{
break;
}
else
{
primeNumbers.push(x);
}
}
}
};
console.log(primeNumbers);
Because the first thing you do is break if x % 2 === 0. Which is true immediately. break will exit the loop. I think you want continue.
Problem 1: You break when x%2 === 0, so you exit the loop at once. Reverse the condition and enter the code in the loop directly:
Replace this:
if (x%2 === 0) {
break;
}
else {
with:
if (x%2 !== 0) {
Problem 2: You are exiting the inner loop if x/y > 1. This is the same as the condition x > y, so that will always exit the inner loop immediately. Instead make the inner loop run from two and up to one less than x:
for (var y=2; y<x; y++) {
Problem 3: Instead of dividing x by y and comparing to one, you should use the modulo operator: x%y. If the result is zero, then x is not a prime number.
Problem 4: You are adding prime numbers inside the inner loop, so you will end up with most numbers multiple times, not just prime numbers once.
You need to add a variable to keep track of what's happening in the inner loop. If none of the checks in the inner loop are zero, then you can add x to the list of prime numbers.
You don't have to test every number before the limit, you just have to test the prime numbers you found before that number.
If you were looking to find all prime numbers between 1 and 10, when you are testing 7 for example you should test
7%2 === 0 false
7%3 === 0 false
7%5 === 0 false
than 7 is a prime number and your prime number array should be
[0,1,2,3,5,7]
and as you see I didn't test 4 because 4 isn't a prime number. This are the numbers you will test 8
8%2 === 0 true > return false
and you don't have to test more because you already know it isn't a prime number. So the final solution should be like
function getPrimes(x){
var ar = [];
for (var counter = 0; counter <= x; counter++) {
var notPrime = false;
for (var i = 2; i <= ar.length && !notPrime; i++) {
if (counter%ar[i]===0) {
notPrime = true;
}
}
if (notPrime === false) ar.push(counter);
}
console.log(ar)
}
getPrimes(250);
var funPrimeNumber=function(val){
var iniX=2;
var iniY=2;
var flag=1;
while(iniX<val){
iniY=2;
flag=1;
while(iniY<iniX){
if(iniX%iniY==0){
//NOT PRIME NUMBER
flag=0;
}
iniY++;
}
if(flag==1){
//PRIME NUMBER
document.write(iniX + ", ");
}
iniX++;
}
}
funPrimeNumber(100);

Categories