Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Recursion Subtraction

Tags:

javascript

Example 1

function x(num) {
  if (num == 0) {
   return 1;
  }
  else {
   return (num * x(num - 1));
 }
}

x(8);

8 * 7 * 6 * 5 * 4 * 3 * 2 * 1

Result is 40320 as expected

Example 2

function x(num) {
  if (num == 0) {
   return 0;
  }
  else {
   return (num + x(num - 1));
 }
}

x(8);

8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0

Result is 36 as expected

Example 3

function x(num) {
  if (num == 0) {
   return 0;
  }
  else {
   return (num - x(num - 1));
 }
}

x(8);

8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0

Result is 4

Can someone explain why?

Shouldn't the answer be -20?

like image 801
slashsharp Avatar asked Oct 07 '15 17:10

slashsharp


6 Answers

The calculation with your function basically goes from right to left:

  8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
= 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1
= 8 - 7 - 6 - 5 - 4 - 3 - 1
= 8 - 7 - 6 - 5 - 4 - 2
= 8 - 7 - 6 - 5 - 2
= 8 - 7 - 6 - 3
= 8 - 7 - 3
= 8 - 4
= 4

That’s because each time the function x is recursively called, the right-most expression is tried to be evaluated.

Effectively, the “stack” looks like this:

  8 - x(8 - 1)
= 8 - (7 - x(7 - 1))
= 8 - (7 - (6 - x(6 - 1)))
= 8 - (7 - (6 - (5 - x(5 - 1))))
= 8 - (7 - (6 - (5 - (4 - x(4 - 1)))))
= 8 - (7 - (6 - (5 - (4 - (3 - x(3 - 1))))))
= 8 - (7 - (6 - (5 - (4 - (3 - (2 - x(2 - 1)))))))
= 8 - (7 - (6 - (5 - (4 - (3 - (2 - (1 - x(1 - 1))))))))
= 8 - (7 - (6 - (5 - (4 - (3 - (2 - (1 - 0)))))))
= 8 - (7 - (6 - (5 - (4 - (3 - (2 - 1))))))
= 8 - (7 - (6 - (5 - (4 - (3 - 1)))))
= 8 - (7 - (6 - (5 - (4 - 2))))
= 8 - (7 - (6 - (5 - 2)))
= 8 - (7 - (6 - 3))
= 8 - (7 - 3)
= 8 - 4
= 4

JavaScript’s evaluation for a “pure” subtraction is:

8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0; // -20
like image 166
Sebastian Simon Avatar answered Sep 30 '22 13:09

Sebastian Simon


Because your function is effectively computing this right to left:

8 - (7 - (6 - (5 - (4 - (3 - (2 - (1 - 0))))))) => 4

And not:

8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 => -20
like image 35
Spencer Wieczorek Avatar answered Sep 30 '22 14:09

Spencer Wieczorek


The equation 8-7-6-5-4-3-2-1-0 written with recursion needs to have something to repeat. 8 is not part of it because it does not subtract it. So you should do something like:

= 8 + ( "recursion starting from 7")
= 8 + ( -7 + "recursion starting from 6")
...
= 8 + ( -7 + -6 + -5 + -4 + -3 + -2 + "recursion starting from 1")
= 8 + ( -7 + -6 + -5 + -4 + -3 + -2 + -1 + "recursion starting from 0")
= 8 + ( -7 + -6 + -5 + -4 + -3 + -2 + -1 + -0 /* end case */ )

The code would be something like

   function x(num, first){
      if (first){
        return num + x(num-1, false);
      } else if (num > 0){
        return -num + x (num-1, false);
      } else {
        return 0;
      }

    }
like image 42
ergonaut Avatar answered Sep 30 '22 13:09

ergonaut


The first subtraction of your recursion starts with the last two numbers and runs backwards:

x = 8-7-6-5-4-3-2-(1-0)
x = 8-7-6-5-4-3-(2-1)
x = 8-7-6-5-4-(3-1)
x = 8-7-6-5-(4-2)
x = 8-7-6-(5-2)
x = 8-7-(6-3)
x = 8-(7-3)
x = (8-4)
x = 4
like image 32
TwilightTitus Avatar answered Sep 30 '22 13:09

TwilightTitus


As others answered, the subtraction is being done sort of backwards, from right to left:

x = 8-7-6-5-4-3-2-(1-0)
x = 8-7-6-5-4-3-(2-1)
x = 8-7-6-5-4-(3-1)
x = 8-7-6-5-(4-2)
x = 8-7-6-(5-2)
x = 8-7-(6-3)
x = 8-(7-3)
x = (8-4)
x = 4

What you're looking for, is an inverse of the addition, which could be written as follows:

function addition(num) {
    if (num == 0) {
        return 0;
    }
    else {
        return (num + addition(num - 1));
    }
}

function subtraction(num) {
    return num - addition(num - 1);
}

Calling subtraction(8) would yield -20, because it is subtracting the sum of all of the lesser numbers, whereas your original function subtracted all of the lesser numbers from each other.

like image 22
Andrew Avatar answered Sep 30 '22 14:09

Andrew


To elaborate on my comment…

Subtraction (unlike multiplication and addition, which explains why your other examples work) is not commutative, and JavaScript evaluation is left-to-right, whereas your function effectively does it right-to-left.

To get the correct result with your existing code, you can use the fact that a subtraction is an addition of a negative number. In the chain, only the left-most number is positive. Re-using your sum function:

function sub(num) {
    return num - sum(num - 1)
}

A purely recursive, single-function solution would require an extra argument either to know where to stop (starting from zero), or to make a special case for the first call (adding instead of subtracting except for that first call).

Of course, if you don't mind cheating with arithmetic, you can linearize to

function sub(num){ return num - (num*(num-1)/2) }
like image 20
Touffy Avatar answered Sep 30 '22 14:09

Touffy