Why does this count up and not just down?

I saw this question posted on YouTube and I was curious why it happened as well. Does anyone know why this counts down and then back up again to 10? It seems to be due to the console.log(num) number 2 that causes the swing up. What I can’t figure out is why it turns positive

var countDown = function(num) {
    if (num === 0) {
        return;
    }
    console.log(num);        //10-1
    countDown(num - 1);
    console.log(num);        //1-10
}
countDown(10);

Maybe don’t read the following part before you look at the function, because you are reasoning it out; you don’t automatically know the answer my thoughts may corrupt your inspiration. Anyway here is what I’m reading above for what it’s worth.

I’m looking at it the function and I see a conditional if statement that checks to see if the number is zero. If it’s zero return, if not continue along downwards. Then the first console sees the 10 and logs it, then the count inputs the 10 as num - 1 and computes 9 calling the function (itself) countDown again, testing for zero and logging the number. Meanwhile the last console.log I wouldn’t have even thought it sees anything because once the function hits 0 it halts and so it never goes past console.log(num) //1-10. At least that is how I’m reasoning it after being stumped and trying to figure it out.

So it’s a baffle. Detailed assistance would be awesome!!

This is recursion. I’m going to step through it, but I’ll use 3 instead of 10.

countDown(3)
    // num is not 0
    console.log(3) // print 3
    countDown(2) // now we have to go execute this.  We don't move to the next command until the function is done executing.
        // num is not 0
        console.log(2) // print 2
        countDown(1) // follow the white rabbit
            // num is not 0
            console.log(1) // print 1
            countDown(0) // once more with feeling
                // num is 0 so we return.
            console.log(1) // because we've moved up from executing countDown(0)
            // countDown(1) is done now so we move up again
        console.log(2) // now we're done with countDown(2)
    console.log(3) // now our original function call is done
3 Likes

This is recursion.
The number 10 gets past to the countDown function, it prints out the number 10 and then that same number 10 get decremented by 1 as input to the function again as number 9.

So you have.
Print 10
10 -1 // Pass the result to itself
Print 9
9 - 1 // Pass the result to itself, etc.

When the function returns, it all returns to the point of countDown( ), because the original function that started this cycle had never ended. This gets stack up 10 times start from the number 1. This is call “Call Stack”.

Think of it like this.

countDown( 10 );
countDown( 9 );
countDown( 8 );
countDown( 7 );
countDown( 6 );
countDown( 5 );
countDown( 4 );
countDown( 3 );
countDown( 2 );
countDown( 1 ); // Except this is in reverse order, it stacks up.

Right after the number reach 0, the function returns.
Starting from the top stack, which is countDown( 1 ).

Then you get 1 - 10.

If you look into the developer tools, you’ll noticed that when it generates an error it starts from the bottom up.

2 Likes

Interesting…I am still confused.
Just for kicks I tried it with countDown(num - 0.1); instead, expecting it to do:
10
9.9
9.8


0.1
0.1
0.2
0.3


10

so like 200 lines instead of 20, but instead it went on for tens of thousands of lines until the console crashed at -1388.999999 !
How so?

Also, why if (num === 0) and not if (num !== 0)?

In a recursive function it’s common to check for the base case than to check for the recursive case.

That’s the thing with floating point numbers. What you know as 0.1 cannot be represented exactly in binary, and it’s actual value is just an approximation of the decimal number 0.1. This slight deviation from 0.1 is tiny, but when you continually subtract 0.1 from a number, these deviations add up.

Even if in the console:

   x = num - 0.1 * 100;
  x === 0             // true```
?

I don’t really know how JS numbers work, but maybe it’s because 0.1 * 100 qualifies as a safe integer, so num - 0.1 * 100 evaluates exactly to 0.

1 Like

Never mind, I see what happens now. I just tried this:

    if (num === 0) {
        return;
    }
    console.log(num);        
    countDown(num - 0.1);
    console.log(num);        
}
countDown(1);```

console results are as expected until the fourth line...
line 1:      1
line 2:      0.9
line 3:      0.8
line 4:      0.7000000000000001
line 5:     0.6000000000000001
line 6:     0.5000000000000001
line 7:       0.40000000000000013
line 8:     0.30000000000000016
line 9:     0.20000000000000015
line 10:     0.10000000000000014
line 11:     1.3877787807814457e-16

So exact zero is never reached.
1 Like

Try this challenge that I found posted a few days ago. Don’t know where it is from, but is a good challenge when it comes to decimal number. It runs into the same problem with 0.01 not being 0.01.
https://forum.freecodecamp.org/t/exact-change-so-messy/

Order of operations. Multiplication happens before subtraction, so your equation works out to 10 - 10, which is 0.

Thanks, I know about order of operations - I was using this to show that the console is able to properly arrive at 10 by multiplying 0.1 * 100, yet it can’t subtract 0.1 from 10 a hundred times to arrive at 0. Strange behaviour.

My bad. Many apologies for the misreading!

1 Like

It’s all good. I know very little so I feel the need to show that I know at least basic math.
Cheers

1 Like