Things that you can't fathom people not understanding

In a perfect world, where drivers do not make errors or text or grow old and lose their vision…sure. In this world, many bicyclists are killed because driver error. With my life on the line, I’d rather take that variable out of the equation.

If the car is going 35 and the bicycle is going 15 the vehicles will close at approximately 75 feet per second. At what point do you bail out then? When the other driver is way down the road? When it is too late? It will take a couple seconds to go “oh shit” and the jump the curb. The driver will have hit you at this point…

No.

I don’t know if I can give you the exact distance this would occur at, but its certainly not impossible to swerve out of the way of a fast moving vehicle that is bearing down on you. Just the fact that they don’t slow and begin to give you extra room would be the first clue that evasive action may be necessary.

Some cites that discuss the dangers of wrong way cycling.

http://www.bikelongbeach.org/archives/4745

http://www.santacruzlive.com/blogs/streetsmarts/2012/05/27/the-dangers-of-wrong-way-cycling/

http://bikecolli.info/collisiontype/left-turning-vehicle-wrongway-cyclist.html

Here’s a little dissertation on the comparison of recursive versus iterative algorithms. I will start by making my point(s) right up front:

(1) Recursive computations may sometimes be about as efficient as iterative, as shown in the factorial example below. Even so, there is overhead in making the function calls and returns at each step of the process. This is tolerable, and for algorithms where recursion is clearly a good idea, it’s an acceptable price. OTOH, recursion may be hideously inefficient as shown in the Fibonacci example below.

(2) So, Frylock, you’re right that “. . . it would be important to understand how to do things both ways at least.”
And this is my bitch about the crap I’ve seen too much of coming out of CS curricula: Whole generations of students are learning to use recursion as the knee-jerk way of doing things, without learning the alternatives, and without understanding of what recursion can really do to you.

Example 1: Recursive Factorial computation isn’t so bad:



int fact ( int n ) 
{
    if ( n == 0 ) return 1 ;
    else if ( n == 1 ) return 1 ;
    else
      return fact(n-1) * n ;
}

Now try computing fact(6). Can you do it by hand, with pencil and paper, tracing through all the steps that this computer algorithm would end up doing?

It looks like this:



    fact(6)
        = fact(5) * 6
        = fact(4) * 5 * 6
        = fact(3) * 4 * 5 * 6
        = fact(2) * 3 * 4 * 5 * 6
        = fact(1) * 2 * 3 * 4 * 5 * 6
        = 1 * 2 * 3 * 4 * 5 * 6
        = 720

So, when all is said and done, your program has actually done the multiplications:
1 * 2 * 3 * 4 * 5 * 6 — Not too terribly inefficient.

Stay tuned my next post, Example 2: Fibonacci, in which I will trace the steps of computing fib(6).

tl;dr version: It gets ugly.

Like the OP, I had a career in programming, after a degree in biology, but my initial reaction was - Evolution…

Oh, the E-word. I’ve seen people react with visible anger at the very mention of it. I’m convinced that they understand the concept but simply don’t want to believe it.

Example 2: Recursive computation of Fibonacci numbers: It’s ugly.



int fib ( int n )
{
    if ( n == 0 ) return 0 ;
    else if ( n == 1 ) return 1 ;
    else
      return fib(n-2) + fib(n-1) ;
}

Now that you’ve had a good warm-up practice computing fact(6) by hand, try computing fib(6) by hand, tracing through all the steps. It goes like this:



    fib(6)
      = fib(4) + fib(5)
      = fib(2) + fib(3) + fib(3) + fib(4)
      = fib(0) + fib(1) + fib(1) + fib(2) + fib(1) + fib(2) + fib(2) + fib(3)
      = 0 + 1 + 1 + fib(0) + fib(1) + 1 + fib(0) + fib(1) + fib(0) + fib(1) + fib(1) + fib(2)
      = 0 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 1 + 1 + fib(0) + fib(1)
      = 0 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 1 + 1 + 0 + 1
      = 8

Note that to compute fib(6) = 8, the computation ultimately ends up adding 1 (one) over and over, a total of 8 times, with a bunch of 0’s added as well for good measure, for a total of 12 additions. Perhaps with some cleverness, you could eliminate all the 0’s.

Whereas, if you compute this iteratively, the additions you do will be simply:


0 + 1 = 1
1 + 1 = 2
1 + 2 = 3
2 + 3 = 5
3 + 5 = 8

and if your code is half clever, it won’t even do that first 0+1, for a total of 4 additions instead of 12.

Now try computing fib(99) = 218922995834555169026 that way. You will end up adding 1 (yes, one again) over and over, a total of 218922995834555169026 times (not to mention a whole bunch of zeroes)! You can bet that the Straight Dope Message Board will have many more Infinite Crises before your algorithm is done. (Not to mention that it will have 218922995834555169026 function calls, for a maximum stack depth (at any one time) of 99 frames.)

(ETA: Conclusion: If you think you need to be using recursion, be sure you have a good reason for it.)

Stay tuned for an anecdote . . .

A Fibonacci anecdote:

I mentioned above that I first learned recursion in an assembly language class. For our very first assignment in that class, we had a simple warm-up assignment to be written in FORTRAN, that being the language that was then taught in the prerequisite programming class.

The assignment was to compute Fibonacci(999) and Fibonacci(1000), and the product of those.

As integers. Not approximations. Accurate to the units digit.

Recursion was not an option. Even if we were doing this in a language that supports recursion (which, of course, FORTRAN doesn’t), it’s not an option.

A vaguely amusing story…

I was playing a wargame with a stranger at a convention. The game involves ships at sea. Before ships can have combat, they have to detect each other. Ships with better radar/sonar are better at detection. Once one ship detects another, it can fire guns or launch missiles.

When playing the game, the ship counters are right there on the board.

My partner couldn’t cope. “Why do I need to detect what I can clearly see?” I explained, “The people on that ship can’t see the other ship. It’s night, or it’s foggy or the waves are too high.”

He never did get it. (Autism, perhaps?)

So… I said, “Ships have to shoot each other twice. First the have to hit with their radar beams…then they get to shoot guns or launch missiles.”

He got that! Phrasing it in terms of the “thoughts” of cardboard counters on a map didn’t work, but the abstraction of “shooting them” with “radar beams” worked fine.

A story of incomprehension with a happy ending!

(And…he beat the snot out of me. Sunk my fleet with embarrassing ease. So it goes!)

Not as efficient as



int fact(int n)
{
   int result = 1;
   for (i = n ; i > 1 ; i-- ) result *= i;
   return result;
}


For those if you that think riding the wrong way is a good idea check desertmonk’s link. Over a 10 year span riding the wrong way was the leading cause of bicycle accidents. Not number 2 or 3. #1.
Get a clue, ride with traffic.

True of course: The iterative and recursive approaches end up doing the same arithmetic steps, while the recursive way has the additional overhead of doing a function call at each step (stacking the args, making the call, making the return, unstacking the args), and also the additional step of computing n-1 at each level. The iterative approach avoids all that. (ETA: Well, on second thought, the iterative approach does include incrementing (or decrementing) a variable at each step, so that’s equivalent to the n-1 computation at each level in the recursion.)

Yet, for all that, it’s not what’s really bad (sometimes) about recursion, and that is something that a lot of CS students just aren’t getting, I think. So the point I was really trying to make was to show that some recursive methods are really really bad, in ways that the naive CS student might not understand.

And this was all in response, largely, to Frylock’s observation that it’s useful to really understand how recursion works and when it’s good to use, as opposed to just using it as the knee-jerk algorithm-of-first-choice all the time – which seems to be how it’s often taught!

I do admit I have prejudices against people who count actual, real objects starting at zero. These are the sorts of things one should not expose to the user/non-tech people :p.

Perhaps he didn’t have a good idea of the difference between the document being in memory and stored on the drive?

I’ve known several people that knew that struggled a bit with that. And if he didn’t have that foundation, then the difference between Save and Save As might be rendered strangely in his intuition.

I think a big hurdle to understanding Save vs Save As is that the first time you Save a given file in most programs, Save functions exactly like Save As by necessity, so the difference gets muddled.

And, in fact, if a file is deleted/moved while open in the program any attempt to save will often be met with a Save As prompt. It’s reasonable, I’d say, to dismiss the behaviour as capricious and arbitrary if you’re not apt to pay enough attention to realize the general rule of file already exists => Save, file is missing => Save As.

You know, when I am driving and see a wrong-way cyclist I automatically think, “Oh dear, there goes an idiot. I’d better be extra careful.” Most of the time it’s a good thing I am.

Nothing says crazy like riding the wrong way on a bike. People avoid crazy.

All is going as planned.