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

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.

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]);
}

Adding up all the primes up to a certain number

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

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

(JS) Why is my While Loop not working!? Perhaps I don't understand the basic concept

Here's the code:
var n = 4;
while(n) {
console.log("Hey!");
n = 5;
}
Am I right here:
n is a variable, with value 4.
while n = 4, print "Hey" in console.
change value of n to 5.
check if n = 4.
n is not equal to 4, so stop executing the code!
Where am I wrong? I'm really frustrated! Edited it a million times! And the worst thing, browser crashes every time!
Please correct me!
Am I right here:
n is a variable, with value 4.
while n = 4, print "Hey" in console.
while(n) doesn't check to see if n is 4, it checks to see if n is truthy*. Both 4 and 5 are truthy values.
To check if it's 4, use == or ===:
while (n === 4) {
console.log("Hey!");
n = 5;
}
(For more about == vs. ===, see this question and its answers.)
* JavaScript uses type coercion in many places, including when testing conditions for while loops and similar. So we talk about values being "truthy" (they coerce to true) or "falsey" (they coerce to false). Truthy values are all values that aren't falsey. The falsey values are 0, "", null, undefined, NaN, and of course, false.

Categories

Resources