I agree with Jeff ... up to a point. If you can document the code using the code itself, then you absolutely should, and comments that simply reiterate what the code says are an abomination and should carry the death penalty.
Having said that, in my actual programming work I tend to use comments as commentary ... at intervals, come up for air and jot down a note on where you've got to and what the state of the system is. I would say the code describes what the program is doing, the comments describe what the programmer is doing if I didn't suspect it of being a nice but meaningless sound bite. Comments don't appear every line, but generally before a compound statement, if/switch, function call or group thereof.
The last comment I wrote, incidentally, was A push of CS in 16-bit code is taken to imply a near call to a far function. Provided the next instruction is in fact a near call, we can just ignore it. I don't think you'll make the code that does that look like the comment that describes it.
I am, occasionally, guilty of the silly:
// What do you call a function written by a chav?