views:

107

answers:

3

Hi folks,

I'm learning PHP. Having trouble understanding why this piece of code isn't working.

In particular: why is the result of array_sum($x) (1596) greater than $cap? Perhaps I'm not understanding the nature of while loops, but it seems to me (looking at a print_r($x)), the loop should cut out a step before it actually does.

<?php

function fibonacci_sum($cap = 1000){

list( $cur, $nxt, $seq ) = array( 0, 1, array() );

while ( array_sum($seq) < $cap ) {

 $seq[] = $cur;    
 $add = $cur + $nxt;  
 $cur = $nxt;   
 $nxt = $add;  
 }

return $seq;

}

$x = fibonacci_sum();
echo array_sum($x);

?>

Any insight is appreciated.

Best, matt

A: 

The sum is less than cap the last time the body of the while loop is entered. That's how while loops work in all major languages. In this case, the sum is greater than cap when the loop is exited for the last time.

Matthew Flaschen
+2  A: 

Look at it this way: if array_sum($x) were less than $cap, then the body of the while loop would be executed again. Therefore, when the while loop has stopped executing, by definition the condition at the top of the while will be false. (*) I think you want to say:

while ( array_sum($seq) + $cur < $cap ) {

That will stop just before you exceed $cap, which is what you seem to want to do.

(*) Yeah, yeah, disclaimer about the effect of break statements.

Daniel Martin
Thanks for that, Daniel.
m477
+2  A: 

Simple order of execution.

If you add a little variable watcher it's easy to see how this happens

  while ( array_sum( $seq ) < $cap )
  {
    echo $cur, ' : ', array_sum( $seq ), '<br>';
    $seq[] = $cur;
    $add = $cur + $nxt;
    $cur = $nxt;
    $nxt = $add;
  }

If you run this, the last output shows 610 : 986. So, 986 is less than 1000, which is why that iteration of the loop executes, but the very first line of the loop pushes $cur onto $seq anyway - completely oblivious to the fact that it just made the sum creater than the cap. So when you do array_sum() outside the function, that 610 is part of it, hence the 1596.

So what you really want is when the array sum plus the next value is less than the cap.

while ( array_sum( $seq ) + $cur < $cap )

But, it's a bit weird that your function returns an array at all. Why not just have it return the sum directly?

Peter Bailey
Thanks Peter, that makes perfect sense. Appreciate the clarity. And you're right, in the end the function should just return the sum.
m477