Adding up all the primes up to a certain number - javascript

I am supposed to write an algorithm that returns the sum of all the primes up to a certain number(argument), including the argument itself. This code seems to be working just fine(I tested it on smaller numbers),however there must be a bug because when I pass 977 as an argument, the programs returns 108789, which is supposedly not correct. According to freecodecamp.org, it should return 73156. I have already checked the array before adding the values but I can't see the problem here.
function sumPrimes(num) {
function isPrime(n){
return ((n/2 === 1 || n/3 === 1 || n/5 === 1 || n/7 === 1)?true:
(n%2===0 || n%3 === 0 || n%5 ===0 || n%7 === 0)?
false:true);
};
let result = [];
let final;
for(let i = 2; i <= num; i++){
if(isPrime(i)){
result.push(i);
}
}
final = result.reduce((x,y) => x + y);
console.log(final); // returns 108789
}
sumPrimes(977);

Your isPrime() method is incorrect. You can do some thing like below instead.
Edit: Complexity of the algorithm is decreased from O(n) to O(sqrt(n)) as pointed out by #Amadan
function sumPrimes(num) {
function isPrime(n){
for(let i = 2, k = Math.sqrt(n); i <= k; i++)
if(n % i === 0)
return false;
return true;
};
let result = [];
let final;
for(let i = 2; i <= num; i++){
if(isPrime(i)){
result.push(i);
}
}
final = result.reduce((x,y) => x + y);
console.log(final); // returns 73156
}

Your isPrime is completely wrong. First of all, you only check divisibility by first four primes; you should check divisibility by all primes up to square root of the number you're testing to be sure. (You can test with non-prime numbers too if you don't want to bother sorting primes from non-primes at this point.) Secondly, whether a remainder is 1 or not makes no difference - it's only between 0 and not 0 that is important.
The algorithms for primality testing are very well-known and described all over the Web; for start, take a look at Wikipedia on prime numbers for overview, and here for the specific algorithm I assume you were going for, though for your specific use case (sum of all primes less than N), the Sieve of Eratosthenes should be much better.

Your isPrime() function is incorrect. If you want to handle anything beyond trivially small primes you cannot simply hardcode the primes to check. For instance isPrime(143) will return true, but 143 = 11*13 so is not prime.

Your prime function doesn't work properly, you might want to read this post about building one. The rest of your function, however, seems to be acting as expected.

The method you are using is wrong as it only checks for a certain number of values which would be problematic for large numbers.
As mentioned in one of the answers above, looping through all the numbers till the square root of that number is also a valid method however there's an even faster and more efficient method named Sieve of Eratosthenes.
This method works on removing results that we already know as false and not computing on them.
You may read about it more over here -
Sieve of Eratosthenes

Related

Can someone explain canSum to me please

The question states:
Write a function canSum(targetSum, numbers) that takes in a targetSum and an array of numbers as arguments. The function should return a boolean indicating whether or not it is possible to generate the targetSum using numbers from the array. You may use an element of an array as many times as needed. You may assume that all numbers are nonnegative.
In the dynamic programming video I am watching the solution is:
const canSum = (targetSum, numbers) => {
if (targetSum === 0) return true;
if (targetSum < 0) return false;
for (let num of numbers) {
const remainder = targetSum - num;
if (canSum(remainder, numbers) === true) {
return true;
}
}
return false;
}
I understand how this code works with many scenarios like canSum(7, [2, 3]). However I don't understand this piece: if (targetSum === 0) return true; that means canSum(0, [2, 3]) will result in true. That's not how this code should work according to the question. What am I missing here?
Thank you
console.log(canSum(7, [2, 4]))
resulted in false
however
console.log(canSum(0, [2]))
resulted in true
When it says you can use any numbers as many times as you want, that includes using all of them zero times, and when you do this the sum is 0. Using this as the base case of the recursion simplifies the algorithm, since you just keep subtracting until you get to 0.
An alternative way would be to use numbers.includes(targetSum) as the base case. They're equivalent because when this is true, one of the iterations of the for loop will set remainder to 0, and the recursive call will have targetSum === 0.

Javascript- How to write a function that finds the max number in any set of numerical arguments

I am completing an exercise on JavaScript Hero (https://www.jshero.net/en/success.html) and I was able to get the function to work, however, I'm hoping someone could tell me WHY it works. I'd really appreciate it.
The challenge is...
"Write a function max that calculates the maximum of an arbitrary number of numbers.
Example: max(1, 2) should return 2 and max(2, 3, 1) should return 3."
My answer is...
function max (){
let ans=0;
for (let i = 0; i < arguments.length; i++) {
if (arguments[i] > ans){
ans= arguments[i];
}
}
return ans;
}
What I don't understand is setting ans to zero and then saying if arguments[i] is greater than zero then that is the answer. Wouldn't theoretically the first argument over zero be returned as the answer? Also, what if your passed in arguments are negative numbers, (-1,-5,-15) for example? Would the function not work then?
I would really appreciate any input on this. Even though I got the right answer, I want to understand what is going on in the code. Thanks! :)
You could take the first paramter as local max value and iterate from the second parameter.
function max() {
let ans = arguments[0];
for (let i = 1; i < arguments.length; i++) {
if (arguments[i] > ans) {
ans = arguments[i];
}
}
return ans;
}
console.log(max());
console.log(max(3, 2, 1));
Looks like ans is only 0 initially. The value of ans changes on each comparison.
So, say you pass the array [1,2,5,4] to the max function, this is how it will go down:
Is 1 bigger than 0? Yes, so ans becomes 1.
Is 2 bigger than 1? Yes, so ans becomes 2.
Is 5 bigger than 2? Yes, so ans becomes 5.
Is 4 bigger than 5? No, so ans stays 5 and is returned to the user as the largest number.
The logic is to compare two numbers at a time to determine which number is greater.
The code that you provided would only work if all the numbers in the argument are positive integers.
function max_val(arr){
for (let i=0;i<arr.length;i++){
for (let j=0;j<arr.length;j++){
if (arr[i]>arr[j]){
arr[j]=arr[i];
}
}
}
console.log(arr[1]);
}

can you use do-while instead of while(true) in this textbook exercise?

Textbook exercise:
Write the function sumInput() that:
Asks the user for values using prompt and stores the values in the array.
Finishes asking when the user enters a non-numeric value, an empty string, or presses “Cancel”.
Calculates and returns the sum of array items.
P.S. A zero 0 is a valid number, please don’t stop the input on zero.
Textbook solution:
function sumInput() {
let numbers = [];
while (true) {
let value = prompt("A number please?", 0);
// should we cancel?
if (value === "" || value === null || !isFinite(value)) break;
numbers.push(+value);
}
let sum = 0;
for (let number of numbers) {
sum += number;
}
return sum;
}
Personally I dislike while (true) because it doesn't seem as intuitive. Would it be wrong to try to rewrite as a do--while? (Even if there's a special gotcha that makes do--while NOT work in this case, I'd STILL like to know if while (true) is just some... very accepted universal usage or not)
Something like:
function sumInput() {
let numbers = [];
do {
let value = prompt("A number please?", 0);
numbers.push(+value);
}
while ( (value !== "" || value !== null) && isFinite(value) );
let sum = 0;
for (let number of numbers) {
sum += number;
}
return sum;
}
In this case, you can’t really use a do-while loop cleanly because the “push” statement might have to be executed zero times (if for example the user quits before entering any numbers). However, without the break you’re trying to avoid, every statement in the loop body is going to execute at least once. In your solution, you end up pushing the final invalid value onto the array every time, which could corrupt your result.
In general, I find do-while loops rarely useful, because (as with this example) you often need to break in the middle to avoid some final repeated bit (e.g. processing input).

how does the comparison against Infinity in JS finds the largest number?

Pardon my confusion ... I'm going through the entirety of W3School of JS as a quick reference to get oriented to all that is JS ...
Came across this code, and while I understand the mechanisms of it, I don't understand how it works, i.e., finding the largest number.
Any help would be appreciated on the how it works to find the largest number by comparing against the negative infinity?
Code: (link of where it came from)
<!DOCTYPE html>
<html>
<body>
<p>Finding the largest number.</p>
<p id="demo"></p>
<script>
function findMax() {
var i;
var max = -Infinity;
for(i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
document.getElementById("demo").innerHTML = findMax(4, 5, 6);
</script>
</body>
</html>
-Infinity is the neutral element for the < operator.
This means that:
-∞ > T = false for every T
If you loop starting with -∞, you always get the first element as maximum.
If you want to find the maximum using a chain (which the mathematical equivalent to a loop):
s1 = max of e1,e2
s2 = max of s1,e3
s3 = max of s2,e4
...
You can rewrite as:
s1 = max of e1,-∞
s2 = max of s1,e2
s3 = max of s2,e3
...
Here s1 = e1.
Any help would be appreciated on the how it works to find the largest number by comparing against the negative infinity?
The code is not always comparing to negative Infinity here:
var max = -Infinity;
But instead it's just initializing the max variable to -Infinity so it guarantees that when we loop the array values, there won't be any value lower than it.
Analysis:
For example when we call findMax(4, 5, 6), we will have three iterations:
In the first iteration, if(arguments[0] > max) <==> 4>-Infinity is true so max=4.
In the second iteration, if(arguments[1] > max) <==> 5>4 is true so max=5.
In the third iteration, if(arguments[2] > max) <==> 6>5 is true so max=6.
Conclusion:
So you can see here that max value will be always updated with the first element in the array as any passed number will be higher than -Infinity, even if we passed negative values like -1240000, -9999999 or -102457933210they will always be higher than-Infinity`.
The example uses -Infinity as the absolute smallest number to begin comparing with. So, if for example, you passed it all negative numbers, and they were all relatively large negative numbers, your max function would work.
e.g. findMax(-123456, -123459, -1234832383483)
In this example, it's a good initial value to use as opposed to something like zero. In that case, zero would be the result of findMax since all the numbers from the previous example are less than zero.
function findMax() {
console.log(arguments)
var i;
var max = -Infinity;
for(i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
console.log(i, max);
}
return max;
}
console.log(findMax(1, 2, 3, 4));
As you can see (1, 2, 3, 4) are passed in the array [arguments]. At each iteration if arguments[i] > max then max = arguments[i]
Note -Infinity is the smallest number, so initially max would be initialised to -Infinity
The answer can become clear when you try to determine how else you would do this. Here's another candidate solution:
function findMax() {
var i;
var max = arguments[0];
for (i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
This one seems simpler. You don't need an initial value, taking instead the first value of the arguments.
And it seems to work:
findMax(8, 6, 7, 5, 3, 0, 9, 8, 6, 7, 5); //=> 9
It works even if you only supply a single value:
findMax(42); //=> 42
Can you see where it fails? There is a serious problem with this implementation.
Did you find it?
findMax(); //=> undefined
When you pass it no arguments at all, you get undefined, a non-numerical result.
With the other version, it would return -Infinity. This answer has a numeric type; so the function always returns a number. Having consistent return types makes programming with the system much easier.
And if you really want to understand the basic idea more deeply, imagine a concatenateAllStrings function. You could do this much the same way, adding to your final value each new string your encounter. But you would need to start with something. There's only one reasonable choice: the empty string. That's because for any string s, '' + s //=> s. In your case, you want the value x such that for any number n, n >= x. What's less than every number? Really only -Infinity.
For a still deeper look, you might investigate "folding over a Semigroup".
I've actually used a related fact in interviewing JS developers. This is only once the user has shown herself to be reasonably competent. I ask something like this:
This sounds a bit like a trick question, but the goal is to see how you might try to understand existing systems. It's an odd quirk of Javascript that Math.max() < Math.min(). Can you discuss how max and min might be implemented to make this happen?
And then I guide her through it, offering as many hints as necessary until she has explained it in full. No one has ever known the answer right off. How much guidance the candidate needs, and how well she seems to understand the explanation, helps me determine something useful about the her.

Range using recursion, how to output a new array Javascript

How do you output a new array using recursion without declaring an empty array outside of the function? Another way of doing it will be creating an inner function and then return newFunction(), but it is not allowed as the task is to call the function itself. Here's what I have so far:
var newArr=[];
var range = function(x, y) {
if(x === y-1){
return newArr;
}
if(x < y){
newArr.push(x+1);
newArr = range(x+1,y);
}
else{
newArr.push(x-1);
newArr = range(x-1,y);
}
return newArr;
};
range(2,10) //[3,4,5,6,7,8,9]
So the key to this kind of thinking is understanding that you should be creating a lot of arrays.
Looking at a slightly different example...
A factorial is a number which goes backwards, through positive integers, multiplying each term with the term below it, and is written like 5!.
These are helpful when you find yourself asking questions like:
"How many permutations of ____ are there?"
"Given these 5 things, how many permutations can I arrange them in, from left to right?"
5! // =>
5 x 4 x 3 x 2 x 1 // =>
120
You could see how we could build a loop and set a variable for a counter, and a variable for the total, and multiply the current total by the current value of the counter we're decrementing.
But instead of doing that, we can try to use recursion.
First, think about how we could simplify that 5 x 4 x ... into one repeated step.
Really, 2! is 2 x 1. 3! is 3 x 2 x 1, which happens to be 3 x 2!.
So the general case might be something like: n! == n x (n - 1)!
So I might write a generalized function which does something like this:
// DO NOT RUN THIS FUNCTION!
function factorial (n) {
return n * factorial(n - 1);
}
So if I run factorial(5) and use my imagination, we can see that the program is doing something like:
factorial(5)
=> return 5 * factorial(5-1)
=> return 4 * factorial(4-1)
=> return 3 * factorial(3-1)
=> ...
Can you see any problems with the function as-is?
I said at the beginning that factorials (in this simplified case) are over positive integers.
How does my function know to stop when the integers stop being positive?
It doesn't, currently. Which is why the above implementation attempts to run forever, and will freeze the browser, while it tries to, until it gets thousands or tens of thousands of functions deep, before it says that you've reached the maximum depth of the call stack and explodes.
What we really need is a condition or a set of conditions, which we use to determine when we're done.
This is a base-case.
if (shouldStop(n)) {
return defaultValue;
}
Or in our case:
function factorial (n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
Now, when we run the function, we have:
factorial(5)
=> 5 * factorial(5 - 1)
=> 4 * factorial(4 - 1)
=> 3 * factorial(3 - 1)
=> 2 * factorial(2 - 1)
=> 1
=> 2 * 1
=> 3 * 2
=> 4 * 6
=> 5 * 24
=> 120
This is recursion.
And because of where the call is (returned at the very end of whatever branch you're in) it's a special kind of recursion (tail recursion), which allows some languages to optimize the code, replacing the function call with the contents of the function call, and thus skip adding to the call-stack like the first version (future versions of JS will support this power).
In more modern JS, I might rewrite it to look something like
const factorial = n => n <= 1 ? 1 : factorial(n - 1);
So now, what about other cases?
Well, sometimes, you need to make sure you're passing more things in.
Think about what your problem is, and what kinds of counters or flags or collectors you need, in order to do your job.
Here's one:
function makeNumberString (current, max, initialString) {
var str = initialString || ""; // maybe I don't have one yet
var currentString = str.concat(current.toString());
if (current > max) {
return initialString;
}
return makeNumberString(current + 1, max, currentString);
}
makeNumberString(0, 9); // "0123456789"
There are other ways of filling that function out, to make it do the same thing.
Note that currentString there is always a brand new string, made by joining the string that I was given with the new value I was passed. I'm not actually modifying the original string, but creating a new copy [HINT!!].
I hope that helps you.
you can simply do like this;
var range = (x,y,a=[]) => (++x < y && (a = range(x,y,a.concat(x))),a),
arr = range(2,10);
console.log(arr);
Note that the returned array is a parameter of the function and is passed to successive recursive calls.
There are many ways to skin this cat.
The simple way: create an array with the first value in it, then
concatenate the remaining values to it.
var range = function(x,y){
return x+1 >= y ? [] : [x+1].concat(range(x+1, y));
}
console.log(JSON.stringify(range(1, 10)));
The array is being constructed from right to left. Notice how the
recursive call to range is not the last thing the function does
before it returns: concatenation of the array follows.
We can also rewrite the function to be tail recursive with an accumulator as a parameter.
var range2 = function(x,y,a){
a = a || [];
return x+1 >= y ? a : range2(x+1, y, a.concat(x+1));
}
console.log(JSON.stringify(range2(1, 10)));
Now the call to range2 is the last thing the function does before
it returns. ES6 compliant JS engines are required to
optimise
calls in tail position (in strict mode) by discarding the execution
context from the stack.
Notice how we're now constructing the array from left to right.
You can avoid the extra parameter by using a helper function.
I've used an inner function, but it doesn't have to be.
var range3 = function(x,y){
var r = function(x,y,a){
return x+1 >= y ? a : r(x+1, y, a.concat(x+1));
}
return r(x, y, []);
}
console.log(JSON.stringify(range3(1, 10)));
Tail recursive using continuation passing style.
var range4 = function(x,y){
var r = function(x,y,c){
return x+1 >= y ? c([]) : r(x+1, y, function(a){
return c([x+1].concat(a));
});
}
return r(x, y, function(a){return a;});
}
console.log(JSON.stringify(range4(1, 10)));
Notice the similarity with the original range: the array is
constructed in reverse. This is trickier to get your head around and
may be something you never need, but it doesn't hurt to be aware of
it.
Try this:
function rangeRecursive(start, end) {
if(start === end){
return end;
} else if(start > end){
return [];
} else {
return [start].concat(rangeRecursive(++start, end));
}
}
console.log(rangeRecursive(4, 15));

Categories

Resources