Discussion:
Iteration vs. Recursion
(too old to reply)
Sathyaish
2006-05-08 07:33:36 UTC
Permalink
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?

I tried one example, and am in the process of trying out more examples,
increasing their complexity as I go. Here's a simple one I tried out:

#include<stdio.h>


/* To compare the the time and space cost of iteration against
recursion*/

const int SOME_CONST = 10;
void ifoo();
void rfoo(int, int, int);


int main(void)
{
ifoo();
rfoo(0, 0, 5);
printf("\n");
return 0;
}

void ifoo()
{
int i = 0, x = 0, y = 5;
for(; i < SOME_CONST; i++)
{
x += y;
printf("%d\t%d\t%d\t\n", i, x, y);
}
}


void rfoo(int i, int x, int y)
{
x += y;
printf("\n%d\t%d\t%d", i, x, y);

if (i < SOME_CONST - 1)
rfoo(++i, x, y);
}


I noted the following:

a. While iteration is linear in time and constant in space, recursion
is exponential in space.

b. Iteration preserves state, recursion does not.
Richard Heathfield
2006-05-08 07:52:39 UTC
Permalink
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
Yes. Iteration and recursion are just two different ways of saying "if we're
not finished yet, let's do it some more". Recursion is one way of
implementing iteration. Iteration is one way of implementing recursion.
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
Not necessarily. It depends what you're doing and how you're doing it.
Post by Sathyaish
b. Iteration preserves state, recursion does not.
It certainly /can/, if that is what is required.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Alan
2006-05-08 08:17:02 UTC
Permalink
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
Matter of basic meaning of the two words.
Post by Sathyaish
I tried one example, and am in the process of trying out more examples,
You can not test a hypothesis merely by increasing the complexity.
Post by Sathyaish
#include<stdio.h>
/* To compare the the time and space cost of iteration against
recursion*/
const int SOME_CONST = 10;
void ifoo();
void rfoo(int, int, int);
int main(void)
{
ifoo();
rfoo(0, 0, 5);
printf("\n");
return 0;
}
void ifoo()
{
int i = 0, x = 0, y = 5;
for(; i < SOME_CONST; i++)
{
x += y;
printf("%d\t%d\t%d\t\n", i, x, y);
}
}
void rfoo(int i, int x, int y)
{
x += y;
printf("\n%d\t%d\t%d", i, x, y);
if (i < SOME_CONST - 1)
rfoo(++i, x, y);
}
You have shown an example of an iteration and an example of recursion. Just
because the latter performs the same as the former does not mean that EVERY
iteration can be expressed as a recursion.

The following is an iteration that cannot be expressed as a recursion

printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
In what way? What do you mean by space? Computer memory? This statement
would seem to be meaningless.

An iterated process would not necessarily be linear in time on a
multitasking computer - which most are these days.

I think you are getting lost over a simple matter.
Post by Sathyaish
b. Iteration preserves state, recursion does not.
State of what? Recursion will preserve a return value. In the stack frame
of each iteration of a recursive function is preserved the "state" of the
function at that time. This would not be "exponential".

Try to simplify by going to the basic meaning of the two words -

"Iterate: repeat, state repeatedly (Latin: iterum - again)"

Iteration is a process that is repeated a number of times without
necessarily returning to anything.
Loops are iterative processes. But iteration is not necessarily confined
to loops - vide my example above.

"Recursion: the act or an instance of returning (Latin: recurrere - run
again)" Concise Oxford Dictionary.

Recursion is a process that calls itself, ie. returns to itself.
A "function" that calls itself is recursion.

The definition of the words show they are NOT synonymous - ie. things may be
repeated without necessarily involving any idea of "returning".

Simple!

Was it really necessary to cross post??

Alan
Vladimir Oka
2006-05-08 08:45:45 UTC
Permalink
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
Wrong.

#include <stdio.h>
#include <stdlib.h>

void my_printf(void)
{
printf("%d", rand());
my_printf();
}

int main(void)
{
my_printf();
return 0;
}

does exactly the same as your example provided you use elipses to mean
"repeat the above" (strictly speaking, you did not use elipses, as
these consist of three, not four dots, so I may be wrong).
Richard Bos
2006-05-08 08:46:39 UTC
Permalink
Post by Alan
You have shown an example of an iteration and an example of recursion. Just
because the latter performs the same as the former does not mean that EVERY
iteration can be expressed as a recursion.
It can, though.
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
That is not an iteration, that is a sequence of statements. _This_ is an
iteration:

while (some_condition)
printf("%d", rand());

and it can be turned into a recursion like this:

void recurse_rand()
{
if (some_condition) {
printf("%d", rand());
recurse_rand();
}
}

Richard
Richard Heathfield
2006-05-08 09:49:31 UTC
Permalink
[clc restored]
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
void pewtinace(int i) /* Please Explain Why This Is Not A Counter-Example */
{
if(i > 0)
{
pewtinace(i - 1);
printf("%d", rand());
}
}
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Dave
2006-05-08 09:55:35 UTC
Permalink
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
void display_random(int depth)
{
if (depth>0)
{
printf("%d",rand());
display_random(depth-1);
}
}

void test()
{
display_random(5);
}
A. Melinte
2006-05-08 13:00:43 UTC
Permalink
Post by Alan
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
Matter of basic meaning of the two words.
...
Post by Alan
You have shown an example of an iteration and an example of recursion.
Just
Post by Alan
because the latter performs the same as the former does not mean that EVERY
iteration can be expressed as a recursion.
Aren't thosee two affirmations contradicting each other?
Ron Jeffries
2006-05-08 20:38:15 UTC
Permalink
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
That appears to me to be repetition, not iteration. It could be turned to
iteration via:

for ( i = 0; i < 5; i++): printf("%d", rand());

And to recursion via:

print_n_times(5);
...

print_n_times(int n) {
if (n==0) return;
printf("%d", rand());
print_n_times(n - 1);
}

Any iteration can be converted to recursion that way, as previous respondents
have said.

Regards,
--
Ron Jeffries
www.XProgramming.com
I'm giving the best advice I have. You get to decide if it's true for you.
Logan Shaw
2006-05-09 02:05:16 UTC
Permalink
Post by Alan
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
Matter of basic meaning of the two words.
Post by Sathyaish
I tried one example, and am in the process of trying out more examples,
You can not test a hypothesis merely by increasing the complexity.
If you mean to say that you cannot prove a theory that way, then I agree.

However, there is nothing wrong with testing out an idea by working through
a variety of different examples. It isn't ever going to yield formal proof
of anything, but the process can be constructive and can help you get your
bearings. Even if formal proof is what you are seeking, some concrete
examples might help you get your head around an idea enough so that you
reach the point where you can do the formal reasoning.

- Logan
August Karlstrom
2006-05-09 21:43:58 UTC
Permalink
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
....
?

void show_random_numbers(void)
{
printf("%d", rand());
show_random_numbers();
}
Post by Alan
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
In what way? What do you mean by space? Computer memory? This statement
would seem to be meaningless.
As far as I know `space' (and `time') are standard terminology in
complexity theory.
Robert Maas, see http://tinyurl.com/uh3t
2006-12-13 18:15:23 UTC
Permalink
Post by Alan
The following is an iteration that cannot be expressed as a recursion
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
printf("%d", rand());
That's not an iteration, it's just a sequence of inline code.
If you want an iteration, put a *single* printf/rand combo into
a loop. If you want a recursion, put a printf and rand into
a recursive loop, which can be done several different ways:
- Tail-recursive loop: On the way down, do the whole printf/rand
combo and decrement the levels-remaining counter. When the
counter reaches zero, return all the way up immediately.
- Ordinary recursive loop: On the way down, merely decrement the
counter. On the way back up, do the printf/rand combo.
- Split recursive loop: On the way down, do the rand and save the
result locally. On the way back up, print the saved value. Note
this method will print the random numbers in reverse of the
sequence they were generated. This cannot be emulated by a
finite-state iterative loop running in fixed memory.
- Optimal log(n)-depth recursion: On the way down, divide the total
remaining by two, rounding up and down so the two halves add to
the total. Recursively call for each of the two halves. Whenever
the count is only 1 coming in, do the printf/rand combo instead
of recursing deeper.
Torben Ægidius Mogensen
2006-05-08 08:04:42 UTC
Permalink
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
Yes. The converse is true only if you allow extra variables (of
unbounded size) to be introduced, essentially emulating a recursion
stack.
Post by Sathyaish
I tried one example, and am in the process of trying out more examples,
#include<stdio.h>
/* To compare the the time and space cost of iteration against
recursion*/
const int SOME_CONST = 10;
void ifoo();
void rfoo(int, int, int);
int main(void)
{
ifoo();
rfoo(0, 0, 5);
printf("\n");
return 0;
}
void ifoo()
{
int i = 0, x = 0, y = 5;
for(; i < SOME_CONST; i++)
{
x += y;
printf("%d\t%d\t%d\t\n", i, x, y);
}
}
void rfoo(int i, int x, int y)
{
x += y;
printf("\n%d\t%d\t%d", i, x, y);
if (i < SOME_CONST - 1)
rfoo(++i, x, y);
}
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
How did you arive at that conclusion? Your rfoo function will in C
use space linear in the number of recursice calls, but even that is
only because your C compiler doesn't do tail-recursion optimisation
(which any sensible compiler will), which would make the above run in
constant space.
Post by Sathyaish
b. Iteration preserves state, recursion does not.
On the contrary: Iteration works by transforming state while recursion
can work by creating new local values (while preserving the global
state). That is the essense of value-oriented (functional)
programming: You never destructively overwrite values, you just create
new ones and reuse the space for the old ones only when they are
guarateed not to be used anymore.

Torben
a***@gmail.com
2006-05-08 10:02:29 UTC
Permalink
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
b. Iteration preserves state, recursion does not.
certainly not in the case of backtracking algorithms.
Julian V. Noble
2006-05-08 11:58:23 UTC
Permalink
Post by Sathyaish
Can every problem that has an iterative solution also be expressed in
terms of a recursive solution?
[ snipped ]
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
Two remarks:

1. You can read all about recursion in my Computing Prescriptions
column in Computing in Science and Engineering (May/June 2003,
pp. 76-81 (a color version may be found at

http://galileo.phys.virginia.edu/classes/551.jvn.fall01/Cprogs.htm


2. Assuming recursion employs a stack, the growth of memory usage
with problem size is logarithmic, not exponential, unless you
are using recursion in a foolish context (to compute Fibonacci
numbers or the like).


--
Julian V. Noble
Professor Emeritus of Physics
University of Virginia
Torben Ægidius Mogensen
2006-05-08 12:28:06 UTC
Permalink
Post by Julian V. Noble
1. You can read all about recursion in my Computing Prescriptions
column in Computing in Science and Engineering (May/June 2003,
pp. 76-81 (a color version may be found at
http://galileo.phys.virginia.edu/classes/551.jvn.fall01/Cprogs.htm
Hardly _all_ about recursion. :-)
Post by Julian V. Noble
2. Assuming recursion employs a stack, the growth of memory usage
with problem size is logarithmic, not exponential, unless you
are using recursion in a foolish context (to compute Fibonacci
numbers or the like).
That is a very imprecise statement. The largest number of stack
frames that are active at any one point can be anywhere between
constant to linear in the total number of recursive calls, but the
number of recursive calls does not need to be linear in the problem
size (as measured by the input size). For example, the recursive
solution to The Towers of Hanoi for N disks uses 2^N-1 calls but stack
depth only N. Additionally, the size of each stack frame may depend
on the input size, so the total space used can be larger than linear
in the number of calls.

Torben
SM Ryan
2006-05-09 03:00:28 UTC
Permalink
# Sathyaish said:
#
# Can every problem that has an iterative solution also be expressed in
# terms of a recursive solution?

Iterative constructions can be easily transformed into recursive ones.
Some recursive constructs cannot be transformed into iterative without
additional variables to simulate the stack.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
We found a loophole; they can't keep us out anymore.
r***@gmail.com
2006-05-09 06:19:45 UTC
Permalink
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
b. Iteration preserves state, recursion does not.
Missing Basic Stuff,
Question why it would require more time (then linear)?
why required more space ? (coz to preserve the state on stake )

Simple ex. fibonacci

fib(1) = fib(2) = 1
fib(n) = fib(n-1)+fib(n-2), if n>2

for fib(6)=fib(5)+fib(4)=[fib(4)+fib(3)] + [fib(3)+fib(2)] =-........


the basic thing is that fib(3) is calculated two times above.
Normally (not always) recursive one is slow(compare to linear) and/or
would require (more space) because
1. repeated computation done. (as in ex. fib(3) called twice,
2. and same result is stored more than once.

Before using recursive fun. Estimate how much space/time it would take
extra, ?
that is the best way to decide recursive is usable in particular case
or not ?

--
Raxit Sheth
Richard Heathfield
2006-05-09 06:31:03 UTC
Permalink
Post by r***@gmail.com
Simple ex. fibonacci
fib(1) = fib(2) = 1
fib(n) = fib(n-1)+fib(n-2), if n>2
for fib(6)=fib(5)+fib(4)=[fib(4)+fib(3)] + [fib(3)+fib(2)] =-........
the basic thing is that fib(3) is calculated two times above.
Normally (not always) recursive one is slow(compare to linear) and/or
would require (more space) because
1. repeated computation done. (as in ex. fib(3) called twice,
2. and same result is stored more than once.
Exercise for the reader: write an iterative version of fib() that is even
less efficient than the recursive version explained above, and use it to
prove that iteration is slow (compared to recursion) and would require more
space.

Exercise for the undergraduate student (or bright 12-year-old): write a
version that calculates fib() without iterating or recursing, thus proving
that both iteration and recursion require unnecessary amounts of space and
time.

Exercise for the post-graduate student: make the non-iterative non-recursive
version less efficient than the least efficient of the versions so far
discussed, thus proving that both iteration and recursion are massively
superior to O(1) techniques.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Alf P. Steinbach
2006-05-09 06:59:13 UTC
Permalink
Post by Richard Heathfield
Post by r***@gmail.com
Simple ex. fibonacci
fib(1) = fib(2) = 1
fib(n) = fib(n-1)+fib(n-2), if n>2
for fib(6)=fib(5)+fib(4)=[fib(4)+fib(3)] + [fib(3)+fib(2)] =-........
the basic thing is that fib(3) is calculated two times above.
Normally (not always) recursive one is slow(compare to linear) and/or
would require (more space) because
1. repeated computation done. (as in ex. fib(3) called twice,
2. and same result is stored more than once.
Exercise for the reader: write an iterative version of fib() that is even
less efficient than the recursive version explained above, and use it to
prove that iteration is slow (compared to recursion) and would require more
space.
Exercise for the undergraduate student (or bright 12-year-old): write a
version that calculates fib() without iterating or recursing, thus proving
that both iteration and recursion require unnecessary amounts of space and
time.
Exercise for the post-graduate student: make the non-iterative non-recursive
version less efficient than the least efficient of the versions so far
discussed, thus proving that both iteration and recursion are massively
superior to O(1) techniques.
The last one stumps me.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
James Dow Allen
2006-05-11 06:12:33 UTC
Permalink
Post by Richard Heathfield
Exercise for the post-graduate student: make the non-iterative non-recursive
version less efficient than the least efficient of the versions so far
discussed, ...
Not overly impressed with Comp Sci doctorates, eh?

James
Richard Heathfield
2006-05-11 06:24:07 UTC
Permalink
Post by James Dow Allen
Post by Richard Heathfield
Exercise for the post-graduate student: make the non-iterative
non-recursive version less efficient than the least efficient of the
versions so far discussed, ...
Not overly impressed with Comp Sci doctorates, eh?
When you've had to teach 'em to program, you don't tend to be too impressed
by the bits of paper that said they already could.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
b***@myrealbox.com
2006-05-11 11:13:35 UTC
Permalink
Post by Richard Heathfield
Post by James Dow Allen
Post by Richard Heathfield
Exercise for the post-graduate student: make the non-iterative
non-recursive version less efficient than the least efficient of the
versions so far discussed, ...
Not overly impressed with Comp Sci doctorates, eh?
When you've had to teach 'em to program, you don't tend to be too impressed
by the bits of paper that said they already could.
Point taken, but ....

Do PhD programs in CS even claim to be producing good programmers?
I mean, I can easily imagine legitimate dissertation research that
involves no programming at all, and while you could argue that the
degree program should include a breadth requirement that includes
programming skills, hm .... No, I don't think I would (argue that,
beyond a minimal level that I suspect would still leave the person
in a state in which you would have to "teach 'em to program").
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
Richard Heathfield
2006-05-11 14:05:21 UTC
Permalink
Post by b***@myrealbox.com
Post by Richard Heathfield
When you've had to teach 'em to program, you don't tend to be too
impressed by the bits of paper that said they already could.
Point taken, but ....
Do PhD programs in CS even claim to be producing good programmers?
If CS grads at least knew a bit of CS, that would be a start. :-)

(I accept that my sample set is probably statistically insignificant, but
they were *all* useless, and 100% is 100% in anybody's language!)
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
b***@myrealbox.com
2006-05-11 15:09:39 UTC
Permalink
Post by Richard Heathfield
Post by b***@myrealbox.com
Post by Richard Heathfield
When you've had to teach 'em to program, you don't tend to be too
impressed by the bits of paper that said they already could.
Point taken, but ....
Do PhD programs in CS even claim to be producing good programmers?
If CS grads at least knew a bit of CS, that would be a start. :-)
(I accept that my sample set is probably statistically insignificant, but
they were *all* useless, and 100% is 100% in anybody's language!)
They're useless for your purposes, and they don't know any CS either?
That would *really* be a sad commentary on those bits of paper.

War stories of their uselessness appreciated, too, especially
if your comment extends to people with undergrad CS degrees.
I teach undergrad CS, and while I don't think every last one of our
graduates should be a good fit in a programming job, still, *some*
of them should be.
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
Richard Heathfield
2006-05-11 15:52:20 UTC
Permalink
Post by b***@myrealbox.com
War stories of their uselessness appreciated, too, especially
if your comment extends to people with undergrad CS degrees.
I teach undergrad CS, and while I don't think every last one of our
graduates should be a good fit in a programming job, still, *some*
of them should be.
I'm sure your crop is better than average, as they have you to teach them.
And of course I know there are plenty of bright CS bunnies out there
generally. It's just that I hardly ever seem to run into them myself -
except here on Usenet, of course.

Maybe the bright ones are bright enough to know to avoid me. :-)
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
b***@myrealbox.com
2006-05-11 16:26:11 UTC
Permalink
Post by Richard Heathfield
Post by b***@myrealbox.com
War stories of their uselessness appreciated, too, especially
if your comment extends to people with undergrad CS degrees.
I teach undergrad CS, and while I don't think every last one of our
graduates should be a good fit in a programming job, still, *some*
of them should be.
I'm sure your crop is better than average, as they have you to teach them.
Actually I think they are a bit better than average, though I doubt
I can claim much if any of the credit for that -- we get some pretty
bright ones coming in. Some of them, by the time they graduate,
are pretty competent programmers, by the standards of an academic
anyway. Others -- well, we sometimes wonder how they managed to
forget so much of what they presumably learned in order to pass the
introductory programming classes. And don't get me started on the
range of mathematical backgrounds/skills ....

Possibly, though, I wasn't clear -- I wasn't so much claiming that
we *do* turn out a few who might be useful (though I hope that's
true) as saying that we *should* turn out a few such, and asking
for stories that would make it clearer what to avoid.
Post by Richard Heathfield
And of course I know there are plenty of bright CS bunnies out there
generally. It's just that I hardly ever seem to run into them myself -
except here on Usenet, of course.
Maybe the bright ones are bright enough to know to avoid me. :-)
Anything's possible, but I'd claim that the bright ones are smart
enough to recognize the value of hanging around someone knowledgeable
if irascible.
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
Richard Heathfield
2006-05-11 16:44:06 UTC
Permalink
Post by b***@myrealbox.com
Possibly, though, I wasn't clear -- I wasn't so much claiming that
we *do* turn out a few who might be useful (though I hope that's
true) as saying that we *should* turn out a few such, and asking
for stories that would make it clearer what to avoid.
Well, for starters, either teach them how to program or tell them not to
apply for programming jobs. :-)

Seriously, it's not my place to teach you how to teach. But IF IT WERE, then
I'd suggest the following:

Make sure they have a thorough understanding of an abstract machine, to the
extent that they can write non-trivial machine code programs in it. An
8-bit machine will be fine - 256 bytes of RAM ought to be enough for
anybody. 16 bits if you're feeling astoundingly generous. Make sure it has
a weird character collating sequence. I mean /really/ weird. (But keep '0'
through '9' contiguous and ascending.) If you're feeling really pleasant,
make it a two-byte machine with 11-bit bytes! Let them learn the meaning of
the word "architecture" (or "agriculture", as we read in clc recently!).

Set one of the really bright ones to write the machine code interpreter in
something like C or C++; then make sure it works, fix it if need be, and
use it forever afterwards for students to test their machine code programs
on. Then get someone else bright to write an assembler and debugger for it.

You're now in a position to teach programming at the dirty end - so make
sure they all understand about stacks and heaps and how memory works and
procedure calls, and so on ad nauseam. (Make sure they write enough machine
code programs to get the idea, before you let them graduate to assembly
language.)

This doesn't have to be hugely in-depth, but I am sick and tired of teaching
people what a pointer is, when they ought to KNOW what a pointer is. "Look,
you want this function to update the pointer, right? So you ought to be
passing a pointer-to-the-pointer into the function" + blank look = recipe
for a police caution.

Then, once they know all that, teach them programming from the clean end.
:-) High level, in other words. You should find that they pick it up rather
easily, because they understand what's going on underneath.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jonathan Bartlett
2006-05-11 18:41:46 UTC
Permalink
Post by Richard Heathfield
You're now in a position to teach programming at the dirty end - so make
sure they all understand about stacks and heaps and how memory works and
procedure calls, and so on ad nauseam. (Make sure they write enough machine
code programs to get the idea, before you let them graduate to assembly
language.)
This doesn't have to be hugely in-depth, but I am sick and tired of teaching
people what a pointer is, when they ought to KNOW what a pointer is. "Look,
you want this function to update the pointer, right? So you ought to be
passing a pointer-to-the-pointer into the function" + blank look = recipe
for a police caution.
Wow. This sounds exactly like what my book was intended to teach. This
is a shameless plug, but since you essentially stated the purpose and
outline of my book I thought it might be appropriate:

Programming from the Ground Up
http://www.cafeshops.com/bartlettpublish.8640017

It doesn't do machine code, but it covers a lot. However, when I teach
intro to programming at the local junior college, I have a "Machine
Language Game" to teach people how the computer works. I have a 16x16
board representing RAM, a whiteboard segmented into registers, a
one-line card for the display, and a stack of papers which tell how to
execute different command codes. I have one student be the data bus,
one student be the ALU, and one student be the instruction handler, and
one student be the graphics card. The instruction handler tells the
data bus to grab the next instruction. The data bus reads it from RAM
and comes back with the instruction and the next two bytes. The
instruction handler then looks up the first number in the instruction
code manual, and does what the manual says. The ALU does what the
instruction handler says, and the graphics card just watches some memory
and updates his output whenever it changes, based on the ASCII codes.

It really helps students figure out how the computer really works
underneath.

Jon
Bradley K. Sherman
2006-05-11 19:01:47 UTC
Permalink
Post by Jonathan Bartlett
code manual, and does what the manual says. The ALU does what the
instruction handler says, and the graphics card just watches some memory
and updates his output whenever it changes, based on the ASCII codes.
It really helps students figure out how the computer really works
underneath.
Which is why students should be learning C not Java in High School
AP courses.

--bks
b***@myrealbox.com
2006-05-14 17:34:56 UTC
Permalink
In article <44638567$***@news.tulsaconnect.com>,
Jonathan Bartlett <***@eskimo.com> wrote:

[ snip ]
Post by Jonathan Bartlett
However, when I teach
intro to programming at the local junior college, I have a "Machine
Language Game" to teach people how the computer works. I have a 16x16
board representing RAM, a whiteboard segmented into registers, a
one-line card for the display, and a stack of papers which tell how to
execute different command codes. I have one student be the data bus,
one student be the ALU, and one student be the instruction handler, and
one student be the graphics card. The instruction handler tells the
data bus to grab the next instruction. The data bus reads it from RAM
and comes back with the instruction and the next two bytes. The
instruction handler then looks up the first number in the instruction
code manual, and does what the manual says. The ALU does what the
instruction handler says, and the graphics card just watches some memory
and updates his output whenever it changes, based on the ASCII codes.
It really helps students figure out how the computer really works
underneath.
Cool idea. And you say this works well in practice? Hm ....
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
David Lightstone
2006-05-14 19:51:19 UTC
Permalink
Post by b***@myrealbox.com
[ snip ]
Post by Jonathan Bartlett
However, when I teach
intro to programming at the local junior college, I have a "Machine
Language Game" to teach people how the computer works. I have a 16x16
board representing RAM, a whiteboard segmented into registers, a
one-line card for the display, and a stack of papers which tell how to
execute different command codes. I have one student be the data bus,
one student be the ALU, and one student be the instruction handler, and
one student be the graphics card. The instruction handler tells the
data bus to grab the next instruction. The data bus reads it from RAM
and comes back with the instruction and the next two bytes. The
instruction handler then looks up the first number in the instruction
code manual, and does what the manual says. The ALU does what the
instruction handler says, and the graphics card just watches some memory
and updates his output whenever it changes, based on the ASCII codes.
It really helps students figure out how the computer really works
underneath.
Cool idea. And you say this works well in practice? Hm ...
I would say that it will work quite well.

When I learned programming (cerca 1967), the technique was called "desk
checking". The difference being that we did it at the level of the FORTRAN
instruction, rather than the machine instruction.

For those not familiar with the era, batch processing was the norm.
Turnaround time was measured in days, not seconds. It has to compile
correctly the first time. It has to execute correctly the first time.
otherwise you loose several days


.
Post by b***@myrealbox.com
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
Jonathan Bartlett
2006-05-15 16:35:39 UTC
Permalink
Post by b***@myrealbox.com
Post by Jonathan Bartlett
It really helps students figure out how the computer really works
underneath.
Cool idea. And you say this works well in practice? Hm ....
I had an adult Walmart stocking clerk who had attended my class by
mistake (she was supposed to be in the "how to use MS Word class" decide
to stay and learn to program... and did every bit as good a job as the
kid who played around with Linux in the offtime.

Because of the game/simulation, she felt she could actually understand
how it all worked together.

Jon
Andrew Poelstra
2006-05-15 19:29:55 UTC
Permalink
Post by Jonathan Bartlett
Post by b***@myrealbox.com
Post by Jonathan Bartlett
It really helps students figure out how the computer really works
underneath.
Cool idea. And you say this works well in practice? Hm ....
I had an adult Walmart stocking clerk who had attended my class by
mistake (she was supposed to be in the "how to use MS Word class" decide
to stay and learn to program... and did every bit as good a job as the
kid who played around with Linux in the offtime.
In general, if she herself decided to stay and learn how to code, she'd
be motivated enough to do a good job. Just a thought.
Post by Jonathan Bartlett
Because of the game/simulation, she felt she could actually understand
how it all worked together.
That would likely be the main reason that she was motivated. I think I
will steal your idea and use it to teach my class. Thanks!
Andrew Poelstra
2006-05-11 21:51:22 UTC
Permalink
Post by Richard Heathfield
Make sure they have a thorough understanding of an abstract machine, to the
extent that they can write non-trivial machine code programs in it. An
8-bit machine will be fine - 256 bytes of RAM ought to be enough for
anybody. 16 bits if you're feeling astoundingly generous. Make sure it has
a weird character collating sequence. I mean /really/ weird. (But keep '0'
through '9' contiguous and ascending.) If you're feeling really pleasant,
make it a two-byte machine with 11-bit bytes! Let them learn the meaning of
the word "architecture" (or "agriculture", as we read in clc recently!).
One weeks in clc is enough to figure that out. I personally think that no
computer programming class should have machines built in the past 15 years.
No, make that 20. Learning to code on a 8086 will teach people the meaning
of portability.
Post by Richard Heathfield
You're now in a position to teach programming at the dirty end - so make
sure they all understand about stacks and heaps and how memory works and
procedure calls, and so on ad nauseam. (Make sure they write enough machine
code programs to get the idea, before you let them graduate to assembly
language.)
I agree entirely. Any decent programmer should have some idea of how to
write machine code, or at least understand how it works in principle.
Post by Richard Heathfield
This doesn't have to be hugely in-depth, but I am sick and tired of teaching
people what a pointer is, when they ought to KNOW what a pointer is. "Look,
you want this function to update the pointer, right? So you ought to be
passing a pointer-to-the-pointer into the function" + blank look = recipe
for a police caution.
I spent a year working entirely in x86 assembler. I have never, ever, had
a problem figuring pointers out since. Machine language probably isn't
necessary.

Of course, if you are going to teach them Java, you might as well explain
that fairies memorize the contents of your variables so that you don't need
memory.
CBFalconer
2006-05-11 23:06:26 UTC
Permalink
Post by Richard Heathfield
Post by b***@myrealbox.com
Possibly, though, I wasn't clear -- I wasn't so much claiming that
we *do* turn out a few who might be useful (though I hope that's
true) as saying that we *should* turn out a few such, and asking
for stories that would make it clearer what to avoid.
Well, for starters, either teach them how to program or tell them
not to apply for programming jobs. :-)
Seriously, it's not my place to teach you how to teach. But IF IT
Make sure they have a thorough understanding of an abstract machine, to the
extent that they can write non-trivial machine code programs in it. An
8-bit machine will be fine - 256 bytes of RAM ought to be enough for
anybody. 16 bits if you're feeling astoundingly generous. Make sure it has
a weird character collating sequence. I mean /really/ weird. (But keep '0'
through '9' contiguous and ascending.) If you're feeling really pleasant,
make it a two-byte machine with 11-bit bytes! Let them learn the meaning of
the word "architecture" (or "agriculture", as we read in clc recently!).
Set one of the really bright ones to write the machine code interpreter in
something like C or C++; then make sure it works, fix it if need be, and
use it forever afterwards for students to test their machine code programs
on. Then get someone else bright to write an assembler and debugger for it.
You're now in a position to teach programming at the dirty end - so make
sure they all understand about stacks and heaps and how memory works and
procedure calls, and so on ad nauseam. (Make sure they write enough machine
code programs to get the idea, before you let them graduate to assembly
language.)
This doesn't have to be hugely in-depth, but I am sick and tired of teaching
people what a pointer is, when they ought to KNOW what a pointer is. "Look,
you want this function to update the pointer, right? So you ought to be
passing a pointer-to-the-pointer into the function" + blank look = recipe
for a police caution.
Then, once they know all that, teach them programming from the clean end.
:-) High level, in other words. You should find that they pick it up rather
easily, because they understand what's going on underneath.
But you would clutter their pristine young minds with all this
detail, when all they need to know is the abstract properties of an
operation! Something like teaching the basic definitions of a
limit (difference arbitrarily small as things approach arbitrarily
near, or we can find an epsilon such that, etc.) to budding
mathematicians. Or even that hot gases expand and urge pistons or
other things to move to budding automotive engineers.

In all seriousness though, the fundamental teaching problem is when
and where to draw the line between detail and abstraction, and
persuade the student to choose the appropriate view. The lack
today of simple but complete systems, such as were built around the
8080, is a drawback. A stack is a detail, automatic storage is an
abstraction.
--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
David Lightstone
2006-05-12 11:11:01 UTC
Permalink
Post by CBFalconer
Post by Richard Heathfield
Post by b***@myrealbox.com
Possibly, though, I wasn't clear -- I wasn't so much claiming that
we *do* turn out a few who might be useful (though I hope that's
true) as saying that we *should* turn out a few such, and asking
for stories that would make it clearer what to avoid.
Well, for starters, either teach them how to program or tell them
not to apply for programming jobs. :-)
Seriously, it's not my place to teach you how to teach. But IF IT
Make sure they have a thorough understanding of an abstract machine, to the
extent that they can write non-trivial machine code programs in it. An
8-bit machine will be fine - 256 bytes of RAM ought to be enough for
anybody. 16 bits if you're feeling astoundingly generous. Make sure it has
a weird character collating sequence. I mean /really/ weird. (But keep '0'
through '9' contiguous and ascending.) If you're feeling really pleasant,
make it a two-byte machine with 11-bit bytes! Let them learn the meaning of
the word "architecture" (or "agriculture", as we read in clc recently!).
Set one of the really bright ones to write the machine code interpreter in
something like C or C++; then make sure it works, fix it if need be, and
use it forever afterwards for students to test their machine code programs
on. Then get someone else bright to write an assembler and debugger for it.
You're now in a position to teach programming at the dirty end - so make
sure they all understand about stacks and heaps and how memory works and
procedure calls, and so on ad nauseam. (Make sure they write enough machine
code programs to get the idea, before you let them graduate to assembly
language.)
This doesn't have to be hugely in-depth, but I am sick and tired of teaching
people what a pointer is, when they ought to KNOW what a pointer is. "Look,
you want this function to update the pointer, right? So you ought to be
passing a pointer-to-the-pointer into the function" + blank look = recipe
for a police caution.
Then, once they know all that, teach them programming from the clean end.
:-) High level, in other words. You should find that they pick it up rather
easily, because they understand what's going on underneath.
But you would clutter their pristine young minds with all this
detail, when all they need to know is the abstract properties of an
operation! Something like teaching the basic definitions of a
limit (difference arbitrarily small as things approach arbitrarily
near, or we can find an epsilon such that, etc.) to budding
mathematicians. Or even that hot gases expand and urge pistons or
other things to move to budding automotive engineers.
In all seriousness though, the fundamental teaching problem is when
and where to draw the line between detail and abstraction, and
persuade the student to choose the appropriate view.
I thought Parnas resolved that circa the development innovation
modularization / incapsulation / data hiding.
Is a whole new bunch of programmers (and I know you are not one of them)
rediscovering the square wheel?
Post by CBFalconer
The lack
today of simple but complete systems, such as were built around the
8080, is a drawback. A stack is a detail, automatic storage is an
abstraction.
I do not consider that necessary to learn about systems. Laszlos's book
System View of the World will be adequate
Post by CBFalconer
--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
SM Ryan
2006-05-13 03:31:15 UTC
Permalink
Apparently it is okay to go off topic if you are in the Elect.



"David Lightstone" <***@prodigy.net> wrote:
#
# "CBFalconer" <***@yahoo.com> wrote in message
# news:***@yahoo.com...
# > Richard Heathfield wrote:
# >> ***@myrealbox.com said:
# >>
# >>> Possibly, though, I wasn't clear -- I wasn't so much claiming that
# >>> we *do* turn out a few who might be useful (though I hope that's
# >>> true) as saying that we *should* turn out a few such, and asking
# >>> for stories that would make it clearer what to avoid.
# >>
# >> Well, for starters, either teach them how to program or tell them
# >> not to apply for programming jobs. :-)
# >>
# >> Seriously, it's not my place to teach you how to teach. But IF IT
# >> WERE, then I'd suggest the following:
# >>
# >> Make sure they have a thorough understanding of an abstract machine, to
# >> the
# >> extent that they can write non-trivial machine code programs in it. An
# >> 8-bit machine will be fine - 256 bytes of RAM ought to be enough for
# >> anybody. 16 bits if you're feeling astoundingly generous. Make sure it
# >> has
# >> a weird character collating sequence. I mean /really/ weird. (But keep
# >> '0'
# >> through '9' contiguous and ascending.) If you're feeling really pleasant,
# >> make it a two-byte machine with 11-bit bytes! Let them learn the meaning
# >> of
# >> the word "architecture" (or "agriculture", as we read in clc recently!).
# >>
# >> Set one of the really bright ones to write the machine code interpreter
# >> in
# >> something like C or C++; then make sure it works, fix it if need be, and
# >> use it forever afterwards for students to test their machine code
# >> programs
# >> on. Then get someone else bright to write an assembler and debugger for
# >> it.
# >>
# >> You're now in a position to teach programming at the dirty end - so make
# >> sure they all understand about stacks and heaps and how memory works and
# >> procedure calls, and so on ad nauseam. (Make sure they write enough
# >> machine
# >> code programs to get the idea, before you let them graduate to assembly
# >> language.)
# >>
# >> This doesn't have to be hugely in-depth, but I am sick and tired of
# >> teaching
# >> people what a pointer is, when they ought to KNOW what a pointer is.
# >> "Look,
# >> you want this function to update the pointer, right? So you ought to be
# >> passing a pointer-to-the-pointer into the function" + blank look = recipe
# >> for a police caution.
# >>
# >> Then, once they know all that, teach them programming from the clean end.
# >> :-) High level, in other words. You should find that they pick it up
# >> rather
# >> easily, because they understand what's going on underneath.
# >
# > But you would clutter their pristine young minds with all this
# > detail, when all they need to know is the abstract properties of an
# > operation! Something like teaching the basic definitions of a
# > limit (difference arbitrarily small as things approach arbitrarily
# > near, or we can find an epsilon such that, etc.) to budding
# > mathematicians. Or even that hot gases expand and urge pistons or
# > other things to move to budding automotive engineers.
# >
# > In all seriousness though, the fundamental teaching problem is when
# > and where to draw the line between detail and abstraction, and
# > persuade the student to choose the appropriate view.
#
# I thought Parnas resolved that circa the development innovation
# modularization / incapsulation / data hiding.
# Is a whole new bunch of programmers (and I know you are not one of them)
# rediscovering the square wheel?
#
#
# >The lack
# > today of simple but complete systems, such as were built around the
# > 8080, is a drawback. A stack is a detail, automatic storage is an
# > abstraction.
#
# I do not consider that necessary to learn about systems. Laszlos's book
# System View of the World will be adequate
#
#
# >
# > --
# > "If you want to post a followup via groups.google.com, don't use
# > the broken "Reply" link at the bottom of the article. Click on
# > "show options" at the top of the article, then click on the
# > "Reply" at the bottom of the article headers." - Keith Thompson
# > More details at: <http://cfaj.freeshell.org/google/>
# > Also see <http://www.safalra.com/special/googlegroupsreply/>
# >
# >
#
#
#
#

--
SM Ryan http://www.rawbw.com/~wyrmwif/
What kind of convenience store do you run here?
Richard Heathfield
2006-05-13 04:01:13 UTC
Permalink
Post by SM Ryan
Apparently it is okay to go off topic if you are in the Elect.
(a) The discussion is on-topic in, perhaps, three (maybe four) of the five
newsgroups that are carrying it, so I think your complaint is, to a certain
degree at least, rather misplaced.

(b) As somebody famous (Kaz?) once said, writing good, solid,
well-researched, interesting, helpful, *topical* articles for a newsgroup
is like putting florins (or dimes) in the bank - and indulging in off-topic
discussion is like taking out guineas (or dollars). Long-serving,
prolifically helpful, high-quality (and unpaid!) regulars earn a certain
(but by no means unlimited) amount of tolerance with regard to topicality.

(c) TINC.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
CBFalconer
2006-05-13 04:29:30 UTC
Permalink
Post by Richard Heathfield
Post by SM Ryan
Apparently it is okay to go off topic if you are in the Elect.
(a) The discussion is on-topic in, perhaps, three (maybe four) of
the five newsgroups that are carrying it, so I think your complaint
is, to a certain degree at least, rather misplaced.
I was shocked, shocked I tell you, to see Ryan and his fouled up
quotation markers together with top-posting appear on
comp.programming. I thought I had him plonked everywhere.
--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
David Lightstone
2006-05-13 11:07:34 UTC
Permalink
Post by SM Ryan
Apparently it is okay to go off topic if you are in the Elect.
What topic? You read the subject line, you read the content and decide for
yourself if there is a correlation.

Perhaps I should have retitled the subject when I made my post. Perhaps the
author of the post to which I responded should have retitled it.
Either way it did not occur.

What to title the subject of this post. Can't decide. Perhaps - "a decision
criteria for determining when it might be wise to consider changing the
subject of the newsgroup posting" no that is just to long
Post by SM Ryan
#
# >>
# >>> Possibly, though, I wasn't clear -- I wasn't so much claiming that
# >>> we *do* turn out a few who might be useful (though I hope that's
# >>> true) as saying that we *should* turn out a few such, and asking
# >>> for stories that would make it clearer what to avoid.
# >>
# >> Well, for starters, either teach them how to program or tell them
# >> not to apply for programming jobs. :-)
# >>
# >> Seriously, it's not my place to teach you how to teach. But IF IT
# >>
# >> Make sure they have a thorough understanding of an abstract machine, to
# >> the
# >> extent that they can write non-trivial machine code programs in it. An
# >> 8-bit machine will be fine - 256 bytes of RAM ought to be enough for
# >> anybody. 16 bits if you're feeling astoundingly generous. Make sure it
# >> has
# >> a weird character collating sequence. I mean /really/ weird. (But keep
# >> '0'
# >> through '9' contiguous and ascending.) If you're feeling really pleasant,
# >> make it a two-byte machine with 11-bit bytes! Let them learn the meaning
# >> of
# >> the word "architecture" (or "agriculture", as we read in clc recently!).
# >>
# >> Set one of the really bright ones to write the machine code interpreter
# >> in
# >> something like C or C++; then make sure it works, fix it if need be, and
# >> use it forever afterwards for students to test their machine code
# >> programs
# >> on. Then get someone else bright to write an assembler and debugger for
# >> it.
# >>
# >> You're now in a position to teach programming at the dirty end - so make
# >> sure they all understand about stacks and heaps and how memory works and
# >> procedure calls, and so on ad nauseam. (Make sure they write enough
# >> machine
# >> code programs to get the idea, before you let them graduate to assembly
# >> language.)
# >>
# >> This doesn't have to be hugely in-depth, but I am sick and tired of
# >> teaching
# >> people what a pointer is, when they ought to KNOW what a pointer is.
# >> "Look,
# >> you want this function to update the pointer, right? So you ought to be
# >> passing a pointer-to-the-pointer into the function" + blank look = recipe
# >> for a police caution.
# >>
# >> Then, once they know all that, teach them programming from the clean end.
# >> :-) High level, in other words. You should find that they pick it up
# >> rather
# >> easily, because they understand what's going on underneath.
# >
# > But you would clutter their pristine young minds with all this
# > detail, when all they need to know is the abstract properties of an
# > operation! Something like teaching the basic definitions of a
# > limit (difference arbitrarily small as things approach arbitrarily
# > near, or we can find an epsilon such that, etc.) to budding
# > mathematicians. Or even that hot gases expand and urge pistons or
# > other things to move to budding automotive engineers.
# >
# > In all seriousness though, the fundamental teaching problem is when
# > and where to draw the line between detail and abstraction, and
# > persuade the student to choose the appropriate view.
#
# I thought Parnas resolved that circa the development innovation
# modularization / incapsulation / data hiding.
# Is a whole new bunch of programmers (and I know you are not one of them)
# rediscovering the square wheel?
#
#
# >The lack
# > today of simple but complete systems, such as were built around the
# > 8080, is a drawback. A stack is a detail, automatic storage is an
# > abstraction.
#
# I do not consider that necessary to learn about systems. Laszlos's book
# System View of the World will be adequate
#
#
# >
# > --
# > "If you want to post a followup via groups.google.com, don't use
# > the broken "Reply" link at the bottom of the article. Click on
# > "show options" at the top of the article, then click on the
# > "Reply" at the bottom of the article headers." - Keith Thompson
# > More details at: <http://cfaj.freeshell.org/google/>
# > Also see <http://www.safalra.com/special/googlegroupsreply/>
# >
# >
#
#
#
#
--
SM Ryan http://www.rawbw.com/~wyrmwif/
What kind of convenience store do you run here?
b***@myrealbox.com
2006-05-14 17:45:12 UTC
Permalink
In article <***@yahoo.com>,
CBFalconer <***@maineline.net> wrote:

[ snip ]
Post by CBFalconer
In all seriousness though, the fundamental teaching problem is when
and where to draw the line between detail and abstraction, and
persuade the student to choose the appropriate view. The lack
today of simple but complete systems, such as were built around the
8080, is a drawback. A stack is a detail, automatic storage is an
abstraction.
Exactly.

Too much focus on details, too early, carries the risk of creating
the impression that whatever detailed system you teach is the only
possible one. I'm not thinking of a really great example of what I
have in mind here -- something along the lines of "if all you know
is Windows, the idea of a powerful command line is unimaginable",
or equivalently, "if all you know is CLIs, the idea of a system with
menus and icons is unimaginable". Starting out with a more abstract
view supposedly avoids this "lock the students into a too-limited
mental model". Can MIT really be totally wrong to start 'em out
in Scheme? (If they're still doing that.)

Then again, too much focus on abstractions carries the risk that they
never really understand .... I think this is especially a risk for
the less-bright students, who aren't very good at abstractions and
when forced to deal with them are apt to just get confused and ....
I wonder if this is the origin of that (bad) approach to writing
code that seems to consist of trying things at random until something
seems to work.
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
b***@myrealbox.com
2006-05-14 17:33:50 UTC
Permalink
Post by Richard Heathfield
Post by b***@myrealbox.com
Possibly, though, I wasn't clear -- I wasn't so much claiming that
we *do* turn out a few who might be useful (though I hope that's
true) as saying that we *should* turn out a few such, and asking
for stories that would make it clearer what to avoid.
Well, for starters, either teach them how to program or tell them not to
apply for programming jobs. :-)
You know, my initial reaction to this was "excellent advice!" --
but one of the advantages (?) of putting off a reply is that there's
time for second thoughts ....

We do get some students who just plain don't like programming
(difficult though that may be for some of us to imagine :-) ).
These students are apt to get discouraged and drop out of CS early
on, because the introductory courses are almost 100% programming.
The ones that stick around, though .... They almost certainly
should be encouraged to find some career path that doesn't involve
programming, even as an entry-level job.

But for the ones who do enjoy programming enough to do it for a
living, at least for a few years, I don't know. I'm not sure we
*can* teach them to program -- we can teach them some rudimentary
skills, but the only way they can become good programmers is to
actually program, and our ability to make them do that is limited
given that we also want to teach them "basic principles" (i.e.,
given them a framework of basic knowledge on which they can hang the
technical details they'll learn in later years). I don't think we
should skimp on the "basic principles" stuff, because that's what
I think we do well, better than the workplace. But the result is
that only the ones who enjoy programming enough to do side projects
really graduate with more than rudimentary programming skills. I'm
not sure we can fix that.
Post by Richard Heathfield
Seriously, it's not my place to teach you how to teach. But IF IT WERE, then
Oh, no need to be so diplomatic -- I asked, right? though if you
want to say it's not your *responsibility* to teach me/us how to
teach, well, yeah ....

However. You may or may not know that how to teach beginning
programming is a topic of perennial debate among people who do it for
a living. In the most recent ACM report on undergraduate curricula
(2001, linked from http://www.acm.org/education/curricula.html),
six, count 'em six, approaches are listed. Something rather like
what you describe is one of them ("hardware first").
Post by Richard Heathfield
Make sure they have a thorough understanding of an abstract machine, to the
extent that they can write non-trivial machine code programs in it.
[ snip ]

I like your thinking here. I'm a little biased, maybe -- the first
CS course I took was introductory programming using Fortran, and
though I did well I didn't feel like I understood much, and it wasn't
until I took another course in assembly-language programming (IBM
360 ALC -- that probably dates me, right?) that I started to think
"oh, I get it now ...."
Post by Richard Heathfield
Then, once they know all that, teach them programming from the clean end.
:-) High level, in other words. You should find that they pick it up rather
easily, because they understand what's going on underneath.
Yeah .... And if you don't teach this kind of thing at some point,
I'm inclined to think that on some level the students will never
really understand what they're doing. Then again, one of my
colleagues, a fairly bright guy, claims that by doing this you're
locking them into how things are done now and making it less likely
that they can come up with fresh perspectives, and the right way
to start is with something much more abstract. (He likes J, which
is more or less a descendant of APL.) I don't know. More in responses
to other posts in this thread.

Anyway, a "thank you!" to you and everyone who replied to my question.
It's all being filed for reference next time we argue about curriculum
revisions. :-)
--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
Ben Pfaff
2006-05-12 02:51:11 UTC
Permalink
Post by Richard Heathfield
Post by b***@myrealbox.com
Post by Richard Heathfield
When you've had to teach 'em to program, you don't tend to be too
impressed by the bits of paper that said they already could.
Point taken, but ....
Do PhD programs in CS even claim to be producing good programmers?
If CS grads at least knew a bit of CS, that would be a start. :-)
I know some excellent computer scientists who are not
programmers. It is not what they do. Their papers read like
math papers. I could never do what they do, and I wouldn't try
to claim that I could.

For their part, I suspect that they wouldn't claim they are good
programmers either, at least not in languages like C. Perhaps
that's the real problem: people who claim to be what they are
not. But I wouldn't criticize computer scientists for not being
programmers, as long as they don't claim to be.
--
Bite me! said C.
Richard Heathfield
2006-05-12 03:02:22 UTC
Permalink
Post by Ben Pfaff
I know some excellent computer scientists who are not
programmers. It is not what they do. Their papers read like
math papers. I could never do what they do, and I wouldn't try
to claim that I could.
I take your point, but those people aren't applying for programming jobs,
so, for the purposes of the current discussion, they don't count. :-)
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Keith Thompson
2006-05-12 06:07:56 UTC
Permalink
Ben Pfaff <***@cs.stanford.edu> writes:
[...]
Post by Ben Pfaff
I know some excellent computer scientists who are not
programmers. It is not what they do. Their papers read like
math papers. I could never do what they do, and I wouldn't try
to claim that I could.
For their part, I suspect that they wouldn't claim they are good
programmers either, at least not in languages like C. Perhaps
that's the real problem: people who claim to be what they are
not. But I wouldn't criticize computer scientists for not being
programmers, as long as they don't claim to be.
It reminds me of an Edsger Dijkstra quotation: "Computer science is no
more about computers than astronomy is about telescopes."
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
rpost
2006-12-11 10:04:55 UTC
Permalink
Post by Keith Thompson
[...] But I wouldn't criticize computer scientists for not being
programmers, as long as they don't claim to be.
It reminds me of an Edsger Dijkstra quotation: "Computer science is no
more about computers than astronomy is about telescopes."
On the other hand, he was no stranger to computers,
claiming to be his country's first professional programmer

http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html

and having developed a multitasking operating system in the 1960s.
--
Reinier Post
TU Eindhoven
Clever Monkey
2006-12-11 15:47:14 UTC
Permalink
Post by rpost
Post by Keith Thompson
[...] But I wouldn't criticize computer scientists for not being
programmers, as long as they don't claim to be.
It reminds me of an Edsger Dijkstra quotation: "Computer science is no
more about computers than astronomy is about telescopes."
On the other hand, he was no stranger to computers,
claiming to be his country's first professional programmer
http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html
and having developed a multitasking operating system in the 1960s.
Isn't there a similar saying attributed to him about computers
science/computer music?
Torben Ægidius Mogensen
2006-05-15 08:59:17 UTC
Permalink
Post by Ben Pfaff
Post by Richard Heathfield
Post by b***@myrealbox.com
Post by Richard Heathfield
When you've had to teach 'em to program, you don't tend to be too
impressed by the bits of paper that said they already could.
Point taken, but ....
Do PhD programs in CS even claim to be producing good programmers?
If CS grads at least knew a bit of CS, that would be a start. :-)
I know some excellent computer scientists who are not
programmers. It is not what they do. Their papers read like
math papers. I could never do what they do, and I wouldn't try
to claim that I could.
Mathematicians are nearly always good programmers -- if you can
structure a proof of a complex mathematical statement, you can program
also. They might find C++ obstruse and complicated (who doesn't?),
but give them a good functional programming language, and they will
out-program most so-called "programmers".
Post by Ben Pfaff
For their part, I suspect that they wouldn't claim they are good
programmers either, at least not in languages like C. Perhaps
that's the real problem: people who claim to be what they are
not. But I wouldn't criticize computer scientists for not being
programmers, as long as they don't claim to be.
Indeed. I would rather criticise someone who calls himself a
programmer and who isn't able to program a sub-quadratic sorting
algorithm without having to consult a textbook (or use a library
routine).

Torben
Keith Thompson
2006-05-15 19:59:48 UTC
Permalink
***@app-4.diku.dk (Torben Ægidius Mogensen) writes:
[...]
Post by Torben Ægidius Mogensen
Indeed. I would rather criticise someone who calls himself a
programmer and who isn't able to program a sub-quadratic sorting
algorithm without having to consult a textbook (or use a library
routine).
I would criticize any programmer who *bothers* to implement a
sub-quadratic sorting algorithm without consulting a textbook or using
a library routine.

I can write a Quicksort function if I have to -- but I don't have to.
And if I tried it without consulting any references, it's likely the
resulting function would have some (probably subtle) bugs.

I don't remember where I read this, but I seem to recall that there
was a gap of a decade or so between the first implementation of a
binary search algorithm, and the first *correct* implementation of a
binary search algorithm.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Richard Heathfield
2006-05-16 07:27:12 UTC
Permalink
Post by Keith Thompson
I can write a Quicksort function if I have to -- but I don't have to.
And if I tried it without consulting any references, it's likely the
resulting function would have some (probably subtle) bugs.
I think that's unlikely - in the sense that I am quite confident your
function would sort correctly (after a few muffled curses and a bit more
typing, obviously).

I think it's far /more/ likely that it would in fact be a SlowSort, and that
you could easily write a Shell sort to out-perform it.

Implementing Quicksort is pretty easy. Implementing it *efficiently* is a
fair bit harder.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
David Lightstone
2006-05-16 10:31:24 UTC
Permalink
Post by Richard Heathfield
Post by Keith Thompson
I can write a Quicksort function if I have to -- but I don't have to.
And if I tried it without consulting any references, it's likely the
resulting function would have some (probably subtle) bugs.
I think that's unlikely - in the sense that I am quite confident your
function would sort correctly (after a few muffled curses and a bit more
typing, obviously).
I think it's far /more/ likely that it would in fact be a SlowSort, and that
you could easily write a Shell sort to out-perform it.
Implementing Quicksort is pretty easy. Implementing it *efficiently* is a
fair bit harder.
I guess you basic argument is something like - Efficiently is why academics
study such things. Programmers often only need concern themselves with
evaluating whether the algorithm is or is not in conflict with NP
completeness

When you define success that way, I doubt if anyone could possible disagree.

When I first started out (auto industry) success was often being able to
reduce the cost of a part by 1 cent (US). Efficency counted
Post by Richard Heathfield
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Richard Heathfield
2006-05-16 11:03:22 UTC
Permalink
Post by David Lightstone
Post by Richard Heathfield
Implementing Quicksort is pretty easy. Implementing it *efficiently* is a
fair bit harder.
I guess you basic argument is something like - Efficiently is why
academics study such things. Programmers often only need concern
themselves with evaluating whether the algorithm is or is not in conflict
with NP completeness
No, that's not what I'm saying at all. In fact, I was agreeing with the idea
that it's far better to write a call to qsort (possibly two minutes to bash
out a comparison function, and another twenty seconds to check the order of
the args in K&R) than to spend two hours getting Quicksort /wrong/. We all
know that Quicksort is faster than Shell sort, so it isn't a question of
choosing which algorithm to use. But having coded up a Shell sort just for
the hell of it, and then a Quick sort because I'm-so-smart-I-can, I was
astounded to discover that my Shell sort consistently outperformed my Quick
sort over a large range of data set sizes - tiny, through mid, and right
the way up to huge. Obviously I got my Quick sort wrong. It sorted just
fine, but it took way too long to do it.
Post by David Lightstone
When you define success that way, I doubt if anyone could possible disagree.
When I first started out (auto industry) success was often being able to
reduce the cost of a part by 1 cent (US). Efficency counted
Yeah, but if saving a cent is success, then saving a dollar is a triumph.
The best way to make your sort Quick is to use the standard library's
sorting routine. That cuts down on writing time, debugging time, and run
time.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Flash Gordon
2006-05-16 12:11:00 UTC
Permalink
Post by Richard Heathfield
Post by David Lightstone
Post by Richard Heathfield
Implementing Quicksort is pretty easy. Implementing it *efficiently* is a
fair bit harder.
I guess you basic argument is something like - Efficiently is why
academics study such things. Programmers often only need concern
themselves with evaluating whether the algorithm is or is not in conflict
with NP completeness
No, that's not what I'm saying at all. In fact, I was agreeing with the idea
that it's far better to write a call to qsort (possibly two minutes to bash
out a comparison function, and another twenty seconds to check the order of
the args in K&R) than to spend two hours getting Quicksort /wrong/. We all
<snip>
Post by Richard Heathfield
Post by David Lightstone
When you define success that way, I doubt if anyone could possible disagree.
When I first started out (auto industry) success was often being able to
reduce the cost of a part by 1 cent (US). Efficency counted
Yeah, but if saving a cent is success, then saving a dollar is a triumph.
The best way to make your sort Quick is to use the standard library's
sorting routine. That cuts down on writing time, debugging time, and run
time.
I agree completely. In addition, if after doing it you find your
libraries quicksort implementation isn't fast enough the best thing to
do is see if you can find a better one that someone else has implemented
and use that.

I'll never write code myself if I can find and legally use some written
by an expert in the field.
--
Flash Gordon, living in interesting times.
Web site - http://home.flash-gordon.me.uk/
comp.lang.c posting guidelines and intro:
http://clc-wiki.net/wiki/Intro_to_clc

Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
Robert Maas, see http://tinyurl.com/uh3t
2006-12-13 20:21:08 UTC
Permalink
Post by Flash Gordon
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard library's
sorting routine. That cuts down on writing time, debugging time, and run
time.
Nowadays, that's good advice. When I started, it wasn't so true.
Post by Flash Gordon
I agree completely. In addition, if after doing it you find your
libraries quicksort implementation isn't fast enough the best
thing to do is see if you can find a better one that someone else
has implemented and use that.
Nowadays you have such choice, with a whole InterNet and Web for
efficiently locating such alternates to the library that was
bundled with your programming system. But long ago it would have
been prohibitive to search for alternatives that you didn't code
yourself.

When I started programming in 1964 (IBM 1620, with Fortran with
Format, later Fortran IId, and with SPS = assemler), and still in
1969 (IBM 1130 with Fortran IV), the bundled FORTRAN library was
cruddy, at least the one routine I needed, random number generator,
was horrible.

In 1969 I became suspicious, and decided to test it. I didn't trust
numerical tests such as chi-squared where you're supposed to
compute this meaningless statistic and then look in a book to see
if it's good enough. So I devised a graphic presentation of
randomness. If the data was sufficiently random, I'd see a
statistically uniform filling of a rectangle. If not, I'd see some
apparent pattern to the filling.

I tested the built-in FORTRAN random-number generator. What I got
out was was horribly non-random: Images like chess pieces (rook or
bishop), or like that two-horned electric monster on the Mexican
beach in the sci-fi movie (or equivalently that ugly black
skyscraper in Chicago).

Then I wrote my own crock of a random number generator. I didn't
know anything about linear congruential or CRC generators, so I
invented my own messy algorithm for essentially hashing the
contents of memory on the computer and reading out partial hash
results. When I tested it, I got statistically uniform-density
rectangles, no apparent pattern, like snow on a TV screen. Success!

The punchcards containing my software burned up in a warehouse fire
in 1972, but I think I still have the CalComp 565 plotter output in
storage, if anybody wants to see the comparison.
pete
2006-05-16 13:09:26 UTC
Permalink
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard library's
sorting routine.
The truth of that is entirely implementation dependant.

qsort on my implementation,
goes quadratic on worst cases,
and it has more than one kind of worst case,
and it is easy to beat hand coded, for all cases.


Using
http://www.mindspring.com/~pfilandr/C/e_driver/

/* BEGIN e_driver.c program output */

Timing 4 different sorting functions.
Sorting arrays of N number of elements,
in 2 different distributions.
The elements are of type long unsigned.
sizeof (long unsigned) is 4.
The times shown are in seconds.

Distribution #1: Shuffled
N qisort qrsort m_sort qsort
199998 0.110000 0.109000 0.140000 0.156000
199999 0.110000 0.125000 0.140000 0.157000
Total times:
qisort: 0.220000 qsort interface, center pivot introspective
qrsort: 0.234000 qsort interface, random pivot introspective
m_sort: 0.280000 qsort interface, stable merge, TOO_SMALL is 10
qsort: 0.313000 standard library qsort

Distribution #2: Ramp, Drives center pivot qsorts, quadratic
N qisort qrsort m_sort qsort
199998 0.250000 0.094000 0.078000 0.922000
199999 0.266000 0.094000 0.078000 1.250000
Total times:
qisort: 0.516000 qsort interface, center pivot introspective
qrsort: 0.188000 qsort interface, random pivot introspective
m_sort: 0.156000 qsort interface, stable merge, TOO_SMALL is 10
qsort: 2.172000 standard library qsort

/* END e_driver.c program output */


/* BEGIN e_driver.c program output */

Timing 4 different sorting functions.
Sorting arrays of N number of elements.
The elements are of type long unsigned.
sizeof (long unsigned) is 4.
The times shown are in seconds.

Distribution #1: Two values, Badly written qsorts choke on this
N qisort qrsort m_sort qsort
19998 0.000000 0.000000 0.000000 1.594000
19999 0.000000 0.000000 0.000000 1.593000
Total times:
qisort: 0.000000 qsort interface, center pivot introspective
qrsort: 0.000000 qsort interface, random pivot introspective
m_sort: 0.000000 qsort interface, stable merge, TOO_SMALL is 10
qsort: 3.187000 standard library qsort

/* END e_driver.c program output */
--
pete
Richard Heathfield
2006-05-16 13:23:02 UTC
Permalink
Post by pete
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard library's
sorting routine.
The truth of that is entirely implementation dependant.
Naturally, but:

(a) mostly it's true anyway;
(b) in cases where the implementation gives you a lousy qsort, get a better
implementation!

(a) takes care of maybe 90% of the cases. (b) takes care of maybe 90% of
what remains. And even if you're in the unlucky 1%, nevertheless you can
probably still find something on Usenet, written by some guy who calls
himself Lower Case Pete, which does the job for you. So there's no real
need to write it yourself.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
CBFalconer
2006-05-16 21:25:24 UTC
Permalink
Post by pete
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard
library's sorting routine.
The truth of that is entirely implementation dependant.
It is always possible to make quicksort go quadratic solely by the
appropriate input data. See:

SOFTWARE—PRACTICE AND EXPERIENCE, VOL. 29(0), 1–4 (0 1999)
A Killer Adversary for Quicksort
M. D. MCILROY
Dartmouth College, Hanover, NH 03755, USA

I have this as a file mdmspe.pdf on my system. Not sure where I
found it.

You can use sorts with guaranteed worst case performance, such as
heapsort and mergesort. There is no guarantee that the C system
qsort is actually quicksort.
--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
Googmeister
2006-05-16 23:09:47 UTC
Permalink
Post by CBFalconer
Post by pete
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard
library's sorting routine.
The truth of that is entirely implementation dependant.
It is always possible to make quicksort go quadratic solely by the
No, that's not true. If you partition on the median element,
you can guarantee O(n log n) - admittedly finding the median
in linear time is not so practical. Alternatively, if you
partition on a random element (using a good source of
randomness), no fixed input will make it go quadratic.
Post by CBFalconer
SOFTWARE-PRACTICE AND EXPERIENCE, VOL. 29(0), 1-4 (0 1999)
A Killer Adversary for Quicksort
M. D. MCILROY
Dartmouth College, Hanover, NH 03755, USA
This is a great paper, but the technique only apply to a
certain (but broad) class of partitioning schemes.
Keith Thompson
2006-05-17 20:23:42 UTC
Permalink
Post by Googmeister
Post by CBFalconer
Post by pete
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard
library's sorting routine.
The truth of that is entirely implementation dependant.
It is always possible to make quicksort go quadratic solely by the
No, that's not true. If you partition on the median element,
you can guarantee O(n log n) - admittedly finding the median
in linear time is not so practical. Alternatively, if you
partition on a random element (using a good source of
randomness), no fixed input will make it go quadratic.
One approach I've seen is to take the median of the first, middle, and
last elements, and use that as the pivot.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
pete
2006-05-17 21:23:07 UTC
Permalink
Post by Keith Thompson
Post by Googmeister
Post by CBFalconer
Post by pete
Post by Richard Heathfield
The best way to make your sort Quick is to use the standard
library's sorting routine.
The truth of that is entirely implementation dependant.
It is always possible to make quicksort go quadratic solely by the
No, that's not true. If you partition on the median element,
you can guarantee O(n log n) - admittedly finding the median
in linear time is not so practical.
I've read about that, but never seen real C code for it.
Post by Keith Thompson
Post by Googmeister
Alternatively, if you
partition on a random element (using a good source of
randomness), no fixed input will make it go quadratic.
One approach I've seen is to take the median of the first, middle, and
last elements, and use that as the pivot.
That goes quadratic with the "ramp" pattern,
which has ascending element values until the middle
and then descending until the end.

void ramp(long *a, size_t n)
{
const size_t N = n;
const size_t mid = N / 2;

while (n != mid) {
*a++ = N - n--;
}
while (n != 0) {
*a++ = n--;
}
}
--
pete
Ben Pfaff
2006-05-17 21:14:40 UTC
Permalink
Post by Googmeister
No, that's not true. If you partition on the median element,
you can guarantee O(n log n) - admittedly finding the median
in linear time is not so practical.
It's possible, though:
http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Torben Ægidius Mogensen
2006-05-18 09:04:56 UTC
Permalink
Post by Ben Pfaff
Post by Googmeister
No, that's not true. If you partition on the median element,
you can guarantee O(n log n) - admittedly finding the median
in linear time is not so practical.
http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm
Yes, but the deterministic O(n) algorithms for median finding are so
slow that it isn't worth the effort. It is faster to first randomize
the array and then use the first element of each subarray as the
pivot. While the worst case is still quadratic, the probability of
that is very low and no fixed pattern (ascending, descending, ramp,
etc.) can defeat it.

When I want to find the median of a long sequence, I usually use a
modified quicksort algorithm:

median xs
= let (len,xs1) = randomize xs -- shuffle and find length
in
nth (len `div` 2) xs1

nth 1 (x:xs) = x
nth n (x:xs)
= let (m,ys,zs) = splitAt x xs 0 [] [x]
in
if n<=m then nth n ys
else nth (n-m) n zs

splitAt x [] m ys zs = (m,ys,zs)
splitAt x (v:vs) m ys zs
= if v<x then splitAt x vs (m+1) (v:ys) zs
else splitAt x vs m ys (v:zs)



Torben
Keith Thompson
2006-05-17 20:21:47 UTC
Permalink
Post by Richard Heathfield
Post by David Lightstone
Post by Richard Heathfield
Implementing Quicksort is pretty easy. Implementing it *efficiently* is a
fair bit harder.
I guess you basic argument is something like - Efficiently is why
academics study such things. Programmers often only need concern
themselves with evaluating whether the algorithm is or is not in conflict
with NP completeness
No, that's not what I'm saying at all. In fact, I was agreeing with the idea
that it's far better to write a call to qsort (possibly two minutes to bash
out a comparison function, and another twenty seconds to check the order of
the args in K&R) than to spend two hours getting Quicksort /wrong/. We all
know that Quicksort is faster than Shell sort, so it isn't a question of
choosing which algorithm to use. But having coded up a Shell sort just for
the hell of it, and then a Quick sort because I'm-so-smart-I-can, I was
astounded to discover that my Shell sort consistently outperformed my Quick
sort over a large range of data set sizes - tiny, through mid, and right
the way up to huge. Obviously I got my Quick sort wrong. It sorted just
fine, but it took way too long to do it.
Some things to keep in mind:

The basic Quicksort algorithm is quadratic (O(N**2)) for some inputs.
There are various ways to tweak it to avoid this problem, such as
being smarter about picking a pivot value.

The best possible performance for a sorting algorithm (using only a
certain set of operations) is O(n log n). Quicksort isn't the only
O(n log n) sorting algorithm.

Despite the name, there is no requirement for C's qsort() function to
be implemented using the Quicksort algorithm. No sane implementer
would use a quadratic algorithm for qsort(), but it would be legal.
(Perhaps the DS9K does this.)

The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison. If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup. There are
undoubtedly cases where this would be worth doing -- *if* you've
measured the actual performance and determined that it's significant.

For sufficiently small arrays, the complexity of Quicksort and other
O(n log n) algorithms can make them slower than quadratic algorithms
like insertion sort. One common approach is to use Quicksort, but
fall back to something like insertion sort for small subarrays.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
pete
2006-05-17 21:40:14 UTC
Permalink
Post by Keith Thompson
The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison. If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup.
A constant factor speedup of the comparisons
won't give you a constant speedup factor of the algorithm
unless the algorithm spends 100% of it's time doing comparisons.

If you hand code for sorting arrays of a specific element type,
then you can use an assignment operation to move the data,
(unless the element types are arrays,)
which is probably going to be faster than what qsort does,
when the type is larger than int.
I recall seeing on this newsgroup, a URL to a paper which
described a highly, if not totally,
portable way for qsort to tell if the element types
are aligned for type int.
--
pete
David Wagner
2006-05-17 21:57:08 UTC
Permalink
Post by pete
Post by Keith Thompson
The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison. If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup.
A constant factor speedup of the comparisons
won't give you a constant speedup factor of the algorithm
unless the algorithm spends 100% of it's time doing comparisons.
Huh? If the sorting algorithm spends a constant fraction of its time
doing comparisons (which it does), then speeding up the time to do
a comparison by a constant factor will speed up the algorithm by a
constant factor.

Example: If 50% of the time is spent on comparisons, then speeding up
comparisons by a factor of 10x will speed up the overall computation
time by a factor of 1.82x. To put it another way, if the original
implementation spends 0.5 N cycles on comparisons and 0.5 N cycles on
other operations, and you find some way to reduce the total cost of the
comparisons to 0.05 N cycles, then you'll have reduced the total cost
to 0.55 N cycles. Reducing the runtime from N to 0.55 N is a speedup
by a constant factor.
pete
2006-05-17 22:16:35 UTC
Permalink
Post by David Wagner
Post by pete
Post by Keith Thompson
The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison.
If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup.
A constant factor speedup of the comparisons
won't give you a constant speedup factor of the algorithm
unless the algorithm spends 100% of it's time doing comparisons.
Huh? If the sorting algorithm spends a constant fraction of its time
doing comparisons (which it does),
It doesn't.
The tendency is for the ratio of comparisons to data movements
to increase as the number of elements increases.
Post by David Wagner
then speeding up the time to do
a comparison by a constant factor will speed up the algorithm by a
constant factor.
--
pete
pete
2006-05-17 23:38:06 UTC
Permalink
Post by pete
Post by David Wagner
Post by pete
Post by Keith Thompson
The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison.
If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup.
A constant factor speedup of the comparisons
won't give you a constant speedup factor of the algorithm
unless the algorithm spends 100% of it's time doing comparisons.
Huh? If the sorting algorithm spends a constant fraction of its time
doing comparisons (which it does),
It doesn't.
The tendency is for the ratio of comparisons to data movements
to increase as the number of elements increases.
Post by David Wagner
then speeding up the time to do
a comparison by a constant factor will speed up the algorithm by a
constant factor.
I just made some measurments
on a quicksort with Sedgewick style loops.

The average comparisons/swap ratio with 1999 elements was 5.23
The average comparisons/swap ratio with 19999 elements was 5.53

... which is small enough of an increase
for me to say that you guys are right,
and I was wrong.
--
pete
Googmeister
2006-05-18 10:50:57 UTC
Permalink
Post by pete
Post by pete
Post by David Wagner
Post by pete
Post by Keith Thompson
The qsort() function does impose a significant performance overhead
compared to a hand-written sorting routine. It has to perform an
indirect function call for each comparison.
If you re-implement the
exact same algorithm used by your implementation, but using inline
comparisons, you'll probably get a constant factor speedup.
A constant factor speedup of the comparisons
won't give you a constant speedup factor of the algorithm
unless the algorithm spends 100% of it's time doing comparisons.
Huh? If the sorting algorithm spends a constant fraction of its time
doing comparisons (which it does),
It doesn't.
The tendency is for the ratio of comparisons to data movements
to increase as the number of elements increases.
Post by David Wagner
then speeding up the time to do
a comparison by a constant factor will speed up the algorithm by a
constant factor.
I just made some measurments
on a quicksort with Sedgewick style loops.
The average comparisons/swap ratio with 1999 elements was 5.23
The average comparisons/swap ratio with 19999 elements was 5.53
These seems consistent with a more rigorous analysis of
(randomized) quicksort.
Avg # comparisons ~ 2n ln n
Avg # swaps ~ 1/3 n ln n
The ratio converges to 6 as n gets large.
Robert Maas, see http://tinyurl.com/uh3t
2006-12-13 19:45:09 UTC
Permalink
Post by Keith Thompson
Post by Torben Ægidius Mogensen
Indeed. I would rather criticise someone who calls himself a
programmer and who isn't able to program a sub-quadratic sorting
algorithm without having to consult a textbook (or use a library
routine).
I would criticize any programmer who *bothers* to implement a
sub-quadratic sorting algorithm without consulting a textbook or
using a library routine.
There's a difference between proving you're competant at writing
algorithms, by programming a famous old task without looking in a
book, vs. proving you're a wise manager of software who knows when
to use libraries and when to write your own code. Both should be
taught to any prospective software programmer.
Post by Keith Thompson
I seem to recall that there was a gap of a decade or so between
the first implementation of a binary search algorithm, and the
first *correct* implementation of a binary search algorithm.
Assuming that's really true, not an "urban legend", I don't
understand why they had so much trouble getting the algorithm
correct. I did my first binary search so long ago I don't remember
which language I used, but I remember the algorithm was rather
obvious:
You have an array, as a global or passed as an argument.
Elements in that array are in ascending sequence already.
You have two indexes, for the first and last elements in the
array where you want to search. I called them LO and HI.
If LO>HI then your range is empty, which means you've already
bottomed out without finding the target, so you immediately
return a not-found indication, for example -1.
Otherwise you compute MID = (LO+HI)/2 (doesn't matter which way
you round, you can even be inconsistent from moment to moment,
the algorithm works in any case).
Test target against element at MID.
- If target smaller, tail-recurse with LO, MID-1, or if you're
doing it iteratively then do assignment HI := MID-1.
- If target larger, tail-recurse with MID+1, HI, or if you're
doing it iteratively then do assignment LO := MID+1.
- Else (target exactly matches) you've found it, return MID.
The nice thing about my algorithm is it's symmetric, MID-1 or
MID+1, so it's easy at a glance to check you got it right.
Dr A. N. Walker
2006-12-14 15:34:57 UTC
Permalink
Post by Robert Maas, see http://tinyurl.com/uh3t
Post by Keith Thompson
I seem to recall that there was a gap of a decade or so between
the first implementation of a binary search algorithm, and the
first *correct* implementation of a binary search algorithm.
Assuming that's really true, not an "urban legend",
It's certainly an urban legend. Scarcely any of the code
in those days was ever published, hundreds of people must have
written that algorithm during that decade, many of them were
quite bright .... Basically, there's *no way* of knowing when
the first "correct" implementation was written, only when the
first correct implementation was published.

In any case, correctness is somewhat in the eye of the
beholder. If in a particular application it is known that the
array is not empty, or that the sought-for element is present,
then you can write slightly simpler code that would fail some
of the stress testing that a more general code needs. People
in those days got jobs done, they weren't concerned with formal
correctness according to some abstract spec. [I don't claim
that as good, bad or indifferent, it was just the way things
were.]
Post by Robert Maas, see http://tinyurl.com/uh3t
I don't
understand why they had so much trouble getting the algorithm
correct.
You're talking about a period that was about a decade
before the first undergraduate CS courses, and long before
anyone but the odd fanatic worried about "correctness", as
opposed to "working". Even the notion of an algorithm was
little discussed. You learned programming by attending a
two-day course on the Autocode of a particular computer, and
then just doing it. There were no books about computing, no
published code, no standards; and professors got very uppity
if some spotty oik from the Computing Service tried to tell
them how to write programs.

Nowadays, that particular algorithm is one of the
common early tasks in an algorithms module. You tell the
class what you want their code to do, and give them a few
minutes to write it. Then you find out whether their code
works if the array is empty, if there is only one element,
if the target is larger/smaller than the last/first element,
and so on. It doesn't, so that gives you the chance to talk
about invariants, pre- and post-conditions, program structure
Post by Robert Maas, see http://tinyurl.com/uh3t
[...] I remember the algorithm was rather
obvious: [...]
Quite so! Lots of science in general, and maths/CS in
particular, is rather obvious. The job of education is to make
it so. *Before* you've been taught how to make things obvious,
even the simplest concepts are obscure.
Post by Robert Maas, see http://tinyurl.com/uh3t
If LO>HI then your range is empty, which means you've already
bottomed out without finding the target, so you immediately
return a not-found indication, for example -1.
You've already hit a design problem! What will you do if
-1 is a permitted index? Do you want the complexity of returning
a structure consisting of a Boolean and an integer [if your chosen
language permits that]? Or do you want the caller to have to test
whether the returned index is in range?
Post by Robert Maas, see http://tinyurl.com/uh3t
Otherwise you compute MID = (LO+HI)/2 (doesn't matter which way
you round, you can even be inconsistent from moment to moment,
the algorithm works in any case).
[The algorithm works, of course, as long as LO <= MID <= HI,
it's just more efficient if MID is somewhere around the middle. But
if we're picking nits, then you're in trouble if LO+HI > Maxint, or
in various other similar potential overflow cases.]
Post by Robert Maas, see http://tinyurl.com/uh3t
Test target against element at MID.
- If target smaller, tail-recurse with LO, MID-1, or if you're
doing it iteratively then do assignment HI := MID-1. [...]
In the old days, this wasn't necessarily as easy as you
make it seem. For integer elements, OK. For reals, there was the
permitted error to worry about. Few languages had proper strings
before the mid-'60s, so if you had an application like trying to
see if a word was in a list, there was a lot of encoding and
decoding to do here. Many languages didn't permit recursion;
and even "iteration" was discouraged -- "while (lo >= hi) {...}"
is a relatively late invention -- so you got spaghetti code using
"goto" to emulate the iteration.
--
Andy Walker, School of MathSci., Univ. of Nott'm, UK.
***@maths.nott.ac.uk
Robert Maas, see http://tinyurl.com/uh3t
2006-12-14 18:36:12 UTC
Permalink
correctness is somewhat in the eye of the beholder. If in a
particular application it is known that the array is not empty,
or that the sought-for element is present, then you can write
slightly simpler code that would fail some of the stress testing
that a more general code needs.
My code worked i all such cases. But there were two assumptions,
based on the technology I was using, that would make my code less
than theoretically universal, so you have a good point not with
those specifics above but with that general idea and the specifics
you cite later.
People in those days got jobs done, they weren't concerned with
formal correctness according to some abstract spec.
Well, if my subroutine was supposed to handle a particular class of
problems, I tried to make sure it really would handle them all. It
was easier for me to write a mathematially "pure" spec and then
satisfy it, instead of write an ugly special-cases spec and
constantly check if the exceptions in the spec match the failure
modes of the program. (In case you haven't guessed, I was a math
major. I liked science better in elementary school, but did better
in math, so I was directed toward math instead of science, although
I treat math research from a scientific viewpoint instead of a
find-a-formal-proof purist viewpoint. Find-a-proof is just to show
everyone I got the correct solution.)
You're talking about a period that was about a decade before the
first undergraduate CS courses, and long before anyone but the
odd fanatic worried about "correctness", as opposed to "working".
I was in that period. When I was undergraduate in math department
(at SCU), the only programming courses available were FORTRAN (only
for the graduate school EE program) and 1401 AutoCoder (only for
MBA program). I was allowed to browse the FORTRAN and machine
language manuals in the machine room, and use the computer while
the EE people were in there so a supervisor was present so long as
I always let the EE people have priority on the machine (IBM 1620).
Later they learned to trust me, so I was allowed to stay in the
machine room after everyone had left, and I often stayed all night
until people started showing up the next morning to claim their
priority on the machine.

I heard rumors that some other university had programming courses
for undergraduates, but I couldn't afford to go there, and I got by
just fine reading the manuals and figuring out things by
experience. The most "useful" program I wrote on my own was to
perform abstract differentiation on polynomials, which involved
computing coefficients and variable-powers of the individual terms
using the product rule then collecting similar terms. Later I got
my first paying software jobs writing payroll program (to replace
IBM 407 plugboard program) and pre-registration (brand new
automation never before done there).

As for formal CS (S for "science", not "programming") courses, I
didn't even hear of such until many years later.
You learned programming by attending a two-day course on the
Autocode of a particular computer, ...
Back then I never even heard of such. Maybe the EE "course" in
Fortran programming was actually like that, two days of lecture
then nothing but lab after that, I wouldn't know the details.
Nowadays, that particular algorithm is one of the common early
tasks in an algorithms module. You tell the class what you want
their code to do, and give them a few minutes to write it.
Do you (not you personally, the instructor of said class) simply
tell them the data is already sorted into correct sequence, in an
array, and you want an efficient way to find the matching element
if it's present? Or do you also mention "divide the array in half"
as a clue how to do it?

When you say a few minutes to write it, do they have an actual
machine to try it on, or do they have to do it all without machine?
Then you find out whether their code works if the array is empty,
if there is only one element, if the target is larger/smaller
than the last/first element, and so on. It doesn't, so that
gives you the chance to talk about invariants, pre- and
post-conditions, program structure in general, blah-de-blah,
That sounds like an interesting way to run such a class. I've never
seen that teaching method used in this way. The closest to it I can
think of is in college, a course that included group theory, we
were sent to the chalk board to try to invent groups of various
sizes up to 5. For 1,2,3,4 it was easy, pretty obvious. But for 5
it was hard, there seemed to be only one possible group structure.
Anything else violated associativity. The lesson was indeed the
cyclic group is the only group of order 5. So this chalkboard
lesson got our minds prepared to really appreciate the power of
subgroups and cosets in narrowing down the possibilities. In this
case, some power of an element must be equal to 1, so that element
generates a cyclic subgroup of size equal to that power number. But
by cosets the order of the whole group (5) must be divisible by the
order of that subgroup, but because 5 is prime you have only two
choices, whole group cyclic, or the trivial case that you are
looking at the identity. Thus any non-identity element must
generate cyclic subgroup of size 5, which by pidgenhole principle
must be whole group, QED.

Then we did groups of order 6, which was *much* easier knowing
already about cosets and what they imply about subgroups.
(And we got the lesson that not all groups are commutative!)
[...] I remember the algorithm was rather obvious: [...]
Quite so! Lots of science in general, and maths/CS in
particular, is rather obvious. The job of education is to make
it so. *Before* you've been taught how to make things obvious,
even the simplest concepts are obscure.
But I wasn't *taught* how to do binary search. Somehow I heard of
the general idea of splitting in the middle, and figured out myself
the actual algorithm, which at that point (with a little thought)
was obvious (to me).
If LO>HI then your range is empty, which means you've already
bottomed out without finding the target, so you immediately
return a not-found indication, for example -1.
You've already hit a design problem! What will you do if -1 is a
permitted index?
This is the first of the two good points you raise, where the
conditions of the system where I worked meant "no problem". In this
case, I was programming in assembly language, where all array
indexes start at 0, or in fortran where all array indexes start at
1, or in SAIL where I forget but it was one or the other. So -1 was
always smaller than the bottom index.
Do you want the complexity of returning a structure consisting of
a Boolean and an integer [if your chosen language permits that]?
None of the languages allowed that. But assembly language allowed
using more than one return-value register, so in that case it would
have been possible. But there's no point since the test of the
boolean register to see whether it's nonzero isn't any faster than
the test of the main register to see whether it's -1 or not (either
is two instructions, compare register against literal constant to
set status bits, then conditional branch), so multiple-value-return
was no advantage, given that a single out-of-bounds value was
always available to use as a not-found indication.
Or do you want the caller to have to test whether the returned
index is in range?
All it has to test is that one globally defined not-found value.
Depending on the language, that could be a named constant in
memory, a macro, or if neither available I could just remember to
always test for any negative number by testing for retval<0 instead
of retval=-1.

But since the caller *must* check the returned whatever (value,
values, structure) for found/notfound, it doesn't matter whether we
use structure or multiple register values or single encoded value,
it's all the same amount of code in any case, and using a single
encoded value is simplest and most general (same encoding scheme
works in all three languages, so I don't have to remember which I'm
using as I switch around between languages).

As for using non-local return, such as throw/catch or
error/errorset, I didn't get access to a decent Lisp until many
years later, and by then I was entrenched in the
encoded-single-return-value method, so I kept using it there too.
(Except in LISP I can use NIL instead of -1 as not-found value.)
Otherwise you compute MID = (LO+HI)/2 (doesn't matter which way
you round, you can even be inconsistent from moment to moment,
the algorithm works in any case).
[The algorithm works, of course, as long as LO <= MID <= HI, it's
just more efficient if MID is somewhere around the middle.
Well, that's the whole point of *binary* instead of *sequential*
search, isn't it? Divide and conquer works best if you divide in
half as closely as is practical. Any near-mid-point, even as far
away as 25/75 quadrile (is that the right word??) would still
guarantee log(n) time with only moderately worse constant factor.
But midpoint is easier/faster to compute than any other such
splitting point, so it'd be perverse to deliberately pick a
worse-than-middle splitting point.
But if we're picking nits, then you're in trouble if LO+HI >
Maxint, or in various other similar potential overflow cases.]
I thought of that as I was posting my algorithm, but I wanted to
stay honest as to my original algorithm, and have it appear nice
and symmetric instead of weird. In fact I was working on a PDP-10
computer which used 36-bit words for integers (and floats too, but
I never used them for such purposes), but only an 18-bit address
space, so even if all of memory was one array the index never
exceeded the right half of one machine word, so there was never any
problem with overflow when adding two or even a hundred array
indexes in a single word of memory.

Of course if you're right up at the limit where twice an array index
might overflow (wrap around to negative value), you have to change
mid := (lo+hi)/2
to:
mid := lo + (hi-lo)/2
which takes longer to compute so it's not used unless the machine
architecture and programming environment present this problem.
Of course there are three other ways to accomplish the same
avoid-overflow/wraparound trick:
mid := hi - (hi-lo)/2
mid := lo - (lo-hi)/2
mid := hi + (lo-hi)/2
but I discourage any of those because they unnecessarily complicate
the debugging with generation of negative differences and/or
backward offsets, which nobody really bright would ever get wrong,
but (wink wink). Just asking for a stupid oversight to break
everything, or a new programmer on the job to fail to understand it
and change it and break it.

Now if this algorithm were written in C++ templates (or C macros,
yuk!!), where the person writing the algorithm has no control over
what data types and array ranges will occur when it's used, then
it'd be really hard to get a single algorithm that is **correct**.
For example, if array indexes are of type unsigned integer, then
there's no such thing as -1 as return value. However we can
probably assume that array indexes are closed under subtraction of
smaller value from larger value in all cases, so at least that one
of the two possible problems isn't a problem, so long as we stick
to lo+(hi-lo)/2, avoiding the three alternatives I said I
discourage. For a template/macro description of the algorithm to be
universally correct, the not-found constant will probably have to
be supplied as an extra parameter (argument) supplied by the
calling application. Some applications that use signed integers but
have arrays always start at 0 might prefer -1 for not-found, while
other applications that use unsigned integers might use initialHI+1,
different value for each call, or maxPosInt, different value for
each index datatype, as the not-found value, but hey it works!

And of course in Java you could use the LISP trick, pass back a
polymorphic data type, and do a type-check to see whether the value
you got is of the index type or of the exceptional type. That
specific not-found value would of course be passed as a parameter
to the binary search routine. (Or maybe better, throw a real live
exception!! Java has a pretty nice exception-class and
exception-handling system built-in from the start.)
- If target smaller, tail-recurse with LO, MID-1, or if you're
doing it iteratively then do assignment HI := MID-1. [...]
In the old days, this wasn't necessarily as easy as you make it
seem. For integer elements, OK.
That's all I ever worked with in regard to binary search.
For reals, there was the permitted error to worry about.
If I had written floating-point binary search, I probably would
have always returned the *closest* match, a final fixup on the
index just before returning, never returning a not-found value, and
then let the caller decide whether the value was close enough for
his needs or not. If I wanted that for integers, that would have
been an interesting varition too, useful for some applications.
Few languages had proper strings before the mid-'60s,
Indeed I started using SAIL in 1969, which misses that time period
by a few years. I didn't know about Lisp until Larry Masinter
showed it to me circa 1972, but it had strings effectively as lists
of ASCII numeric codes from the beginning (1964, one of the "few"
you cite I presume), or as pnames of symbols as an alternative,
either of which was good enough for hacking an algorithm.
so if you had an application like trying to see if a word was in
a list, there was a lot of encoding and decoding to do here.
I cheated, using a purturbed linear-congruential algorithm to
compute 35-bit hash of the string, then comparing the hashs. There
was "never" two strings with the same hash, until I implemented
Schroeppel's linear-relation-finding algorithm in MacSyma,
whereupon it was easy to put in the linear constraints for a
hashing conflict and find smallest-norm five-character
string-differences that generated zero hash difference, and then
use one of those to directly construct pairs of strings with the
same hash, sigh.
Many languages didn't permit recursion;
Yeah, like Fortran, or anything whatsoever using IBM 360 calling
conventions where each routine had its own private static block for
storing the saved registers. But iteration was always allowed, and
as I pointed out either could work the same way, either recurse
with LO,MID-1, or assign HI:=MID-1, so that's not a problem.
and even "iteration" was discouraged -- "while (lo >= hi) {...}"
is a relatively late invention
I agree syntactically it's moderately recent. It was in Lisp, but I
probably programmed binary search before I met Lisp. But if all you
had was FOR loops, with RETURN any time you wanted to break out of
the loop, you could set up a worthless FOR loop (ran virtually
forever, longer than log(n) for sure), and thereby emulate "while
true" for the duration of the binary search.
so you got spaghetti code using "goto" to emulate the iteration.
That's not spaghetti code. This is nice clean programming template:
FUNCTION functionname (parameters) BEGIN
declare local constants and variables.
initialize loop constants.
LP:
test data conditions, and conditionally:
perform changes to loop variables, or
return a value already now, or
go to EX.
GOTO LP;
EX:
Final fixup of return value (code common to more than one exit path).
Return that value now.
END;
Spaghetti code is when you have more than one non-final label in a
single block and you jump around between them in a non-structured
way. For example, the parser for Reduce (Tony Hearn at Utah) was
one huge spaghetti-code function about five or ten pages long.
Dr A. N. Walker
2006-12-15 17:06:24 UTC
Permalink
Post by Robert Maas, see http://tinyurl.com/uh3t
correctness is somewhat in the eye of the beholder. [...]
My code worked i all such cases.
Sure, but the question is rather whether we should count
as correct code that fails in cases [such as passing an empty array]
that could arise in general but not in a particular application.
If someone claims that no correct version was written until [X],
then such questions become relevant.

[snip]
Post by Robert Maas, see http://tinyurl.com/uh3t
Nowadays, that particular algorithm is one of the common early
tasks in an algorithms module. You tell the class what you want
their code to do, and give them a few minutes to write it.
Do you (not you personally, the instructor of said class) simply
tell them the data is already sorted into correct sequence, in an
array, and you want an efficient way to find the matching element
if it's present? Or do you also mention "divide the array in half"
as a clue how to do it?
I [personally!] mention "look at the middle element" in the
intro, with a bit of waffle about moving fingers up and down, and
comparison with how to look up names in the telephone directory.
Post by Robert Maas, see http://tinyurl.com/uh3t
When you say a few minutes to write it, do they have an actual
machine to try it on, or do they have to do it all without machine?
In my case, it was literally in the middle of a lecture,
so they were just asked to write down some code. My lecture
notes say:

" Please try it now. Don't worry about the language used or
" the coding details; concentrate on making sure that lo, hi and
" the other variables get set to the correct values, and that your
" code gives the correct value of i in all cases. "

I gave them about ten minutes, then asked them to swap with neighbours,
and check whether the code they were looking at worked in various
"stress" tests [not extreme cases, such as those involving "MaxInt",
which is not really the point of the example]. There was usually
some hilarity as students tried to work out what the code meant,
which also helped the general atmosphere of the lecture. Jon
"Programming Pearls" Bentley has an article about exactly this
same "experiment", and also notes that "no-one" gets this right
first time, but once you've talked about invariants, etc., it's
so easy that "everyone" does.
Post by Robert Maas, see http://tinyurl.com/uh3t
That sounds like an interesting way to run such a class. I've never
seen that teaching method used in this way. [...]
Most of mathematics isn't really amenable to it. I've
done similar things occasionally with NA and with game theory,
but the opportunities are rare.
Post by Robert Maas, see http://tinyurl.com/uh3t
But since the caller *must* check the returned whatever (value,
values, structure) for found/notfound, it doesn't matter whether we
use structure or multiple register values or single encoded value,
it's all the same amount of code in any case, and using a single
encoded value is simplest and most general (same encoding scheme
works in all three languages, so I don't have to remember which I'm
using as I switch around between languages).
For your particular circumstances, OK; but in a language
[such as Pascal] in which any integer may potentially arise as a
subscript, there is no reliable "out of bounds" marker [unless
we move up a level of abstraction and return "nil" for not found
and a pointer to the found element otherwise]. Again, the point
is not that your algorithm was wrong, but rather that it might
not pass the test of "first correct implementation" if that was
aimed at the more general problem. [Or if the commentator was
being particularly nit-picky.]
Post by Robert Maas, see http://tinyurl.com/uh3t
Now if this algorithm were written in C++ templates (or C macros,
yuk!!), where the person writing the algorithm has no control over
what data types and array ranges will occur when it's used, then
it'd be really hard to get a single algorithm that is **correct**.
Quite. That's why the whole original question of "why
did it take so long to get a correct implementation" is really
rather bogus. Firstly, I don't believe it did, though it is
certainly very likely that some early published versions were
buggy; but more importantly there is no clear-cut meaning of
"correct" in this case, as the problem was not nailed down
tightly enough for us to be able to judge the context of those
writing programs 50-odd years ago.
Post by Robert Maas, see http://tinyurl.com/uh3t
and even "iteration" was discouraged -- "while (lo >= hi) {...}"
is a relatively late invention
I agree syntactically it's moderately recent. It was in Lisp, but I
probably programmed binary search before I met Lisp. But if all you
had was FOR loops, with RETURN any time you wanted to break out of
the loop, you could set up a worthless FOR loop (ran virtually
forever, longer than log(n) for sure), and thereby emulate "while
true" for the duration of the binary search.
Yes, you could; but there was a different mindset in the
early days. A FOR-loop with a break seems different from a WHILE.
--
Andy Walker, School of MathSci., Univ. of Nott'm, UK.
***@maths.nott.ac.uk
s***@gmail.com
2006-12-18 15:20:09 UTC
Permalink
Post by Keith Thompson
[...]
Post by Torben Ægidius Mogensen
Indeed. I would rather criticise someone who calls himself a
programmer and who isn't able to program a sub-quadratic sorting
algorithm without having to consult a textbook (or use a library
routine).
I would criticize any programmer who *bothers* to implement a
sub-quadratic sorting algorithm without consulting a textbook or using
a library routine.
In fairness to Torben, he was talking about the *ability* to do this,
not whether it was a good idea from a software development sense.

Sorting is a nice, clean, well-defined problem, and efficient
algorithms for it (either mergesort or quicksort) are very
straightforward uses of the basic concept of divide-and-conquer.

It just so happens that this *specific* problem is such a useful thing
that there are many good implementations that can be used, so a good
programmer should take advantage of that. However, if they *can't*
roll their own on such a clean problem, what are the odds that they
can come up with good solutions to other, not-so-clean, and
not-so-well-studied problems that they might encounter for which they
*can't* rely on pre-written libraries?
Post by Keith Thompson
I don't remember where I read this, but I seem to recall that there
was a gap of a decade or so between the first implementation of a
binary search algorithm, and the first *correct* implementation of a
binary search algorithm.
I seem to remember reading that too. If I had to bet on a source, I'd
suggest Bentley's "Programming Pearls" - he has quite the obsession
with binary search... :-) Unfortunately, I'm at home, and my copy is
at work, so I can't verify this now.
--
Steve Stringer
***@gmail.com
Chris Smith
2006-12-18 20:24:38 UTC
Permalink
Post by s***@gmail.com
Sorting is a nice, clean, well-defined problem, and efficient
algorithms for it (either mergesort or quicksort) are very
straightforward uses of the basic concept of divide-and-conquer.
I'd expect someone with a fair practical knowledge of programming to
come up with merge sort or even heap sort on their own; but quicksort is
completely non-obvious to me. In particular, it's a little non-obvious
both that partitioning can be done in linear time, and it's completely
non-obvious that choosing an appropriate pivot can be done well without
prior knowledge about the distribution of values and without negatively
impacting the asymptotic complexity of the routine.
Post by s***@gmail.com
Post by Keith Thompson
I don't remember where I read this, but I seem to recall that there
was a gap of a decade or so between the first implementation of a
binary search algorithm, and the first *correct* implementation of a
binary search algorithm.
I seem to remember reading that too. If I had to bet on a source, I'd
suggest Bentley's "Programming Pearls" - he has quite the obsession
with binary search... :-)
I do. On page 34, Bentley quotes Knuth as saying that the first binary
search was published in 1946, but the first correct binary search was
published in 1962. If you're as pedantic as me, note the word
"published" rather than "devised" or "implemented".
--
Chris Smith
Jon Harrop
2006-12-18 23:44:16 UTC
Permalink
Post by Chris Smith
Post by s***@gmail.com
I seem to remember reading that too. If I had to bet on a source, I'd
suggest Bentley's "Programming Pearls" - he has quite the obsession
with binary search... :-)
I do. On page 34, Bentley quotes Knuth as saying that the first binary
search was published in 1946, but the first correct binary search was
published in 1962. If you're as pedantic as me, note the word
"published" rather than "devised" or "implemented".
Binary search has probably been used for thousands of years. I expect it was
used before calculus-based optimisation methods like Newton-Raphson. I'd be
amazed if it wasn't first published hundreds of years ago as well. It seems
like an odd thing to claim to be so modern, given how old much more
sophisticated concepts like calculus are...
--
Dr Jon D Harrop, Flying Frog Consultancy
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists/index.html?usenet
pete
2006-12-19 01:12:27 UTC
Permalink
Post by Jon Harrop
Binary search has probably been used for thousands of years.
I expect it was used before calculus-based optimisation methods
like Newton-Raphson. I'd be amazed if it wasn't first published
hundreds of years ago as well. It seems
like an odd thing to claim to be so modern, given how old much more
sophisticated concepts like calculus are...
If I understand this web page corrrectly
http://www-history.mcs.st-andrews.ac.uk/Biographies/Heron.html
there's a translation there of a description of the same
binary algorithm for square roots, which was 2000 years old
at the time that it was recorded by Heron about 2000 year ago.
--
pete
Ben Pfaff
2006-05-11 14:01:49 UTC
Permalink
Post by b***@myrealbox.com
Do PhD programs in CS even claim to be producing good programmers?
That's not a claim here at Stanford, as far as I know.
--
Ben Pfaff
email: ***@cs.stanford.edu
web: http://benpfaff.org
Charles Richmond
2006-05-11 18:07:47 UTC
Permalink
Post by b***@myrealbox.com
Post by Richard Heathfield
Post by James Dow Allen
Post by Richard Heathfield
Exercise for the post-graduate student: make the non-iterative
non-recursive version less efficient than the least efficient of the
versions so far discussed, ...
Not overly impressed with Comp Sci doctorates, eh?
When you've had to teach 'em to program, you don't tend to be too impressed
by the bits of paper that said they already could.
Point taken, but ....
Do PhD programs in CS even claim to be producing good programmers?
I mean, I can easily imagine legitimate dissertation research that
involves no programming at all, and while you could argue that the
degree program should include a breadth requirement that includes
programming skills, hm .... No, I don't think I would (argue that,
beyond a minimal level that I suspect would still leave the person
in a state in which you would have to "teach 'em to program").
This reminds me of this math professor that a friend and I took
numerical analysis from in college. This sadistic prof did *not*
provide the students with computer accounts. Instead, you had to
"play" the computer and do all the iterative calculations by hand.
This required a *lot* of writing and created quite a pile of notebook
paper.

ISTM that using the computer is part of the point of such a course.

Fortunately, I had the good sense to drop the class...

--
+----------------------------------------------------------------+
| Charles and Francis Richmond richmond at plano dot net |
+----------------------------------------------------------------+
birarai
2006-05-12 09:42:08 UTC
Permalink
Take a look at www.monsterSDLC.com
Richard Heathfield
2006-05-12 09:47:10 UTC
Permalink
Post by birarai
Take a look at www.monsterSDLC.com
...and you'll see a cartoon of an owl with a beach-ball stuck on his nose.
How is this relevant to our discussion of iteration vs recursion?
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Torben Ægidius Mogensen
2006-05-09 11:12:05 UTC
Permalink
Post by r***@gmail.com
Post by Sathyaish
a. While iteration is linear in time and constant in space, recursion
is exponential in space.
b. Iteration preserves state, recursion does not.
Missing Basic Stuff,
Question why it would require more time (then linear)?
why required more space ? (coz to preserve the state on stake )
Simple ex. fibonacci
fib(1) = fib(2) = 1
fib(n) = fib(n-1)+fib(n-2), if n>2
for fib(6)=fib(5)+fib(4)=[fib(4)+fib(3)] + [fib(3)+fib(2)] =-........
the basic thing is that fib(3) is calculated two times above.
Normally (not always) recursive one is slow(compare to linear) and/or
would require (more space) because
1. repeated computation done. (as in ex. fib(3) called twice,
2. and same result is stored more than once.
Before using recursive fun. Estimate how much space/time it would take
extra, ?
that is the best way to decide recursive is usable in particular case
or not ?
As Richard Heathfield said, this is not a question of recursion versus
iteration, but a question of using different algorithms. You are not
the only one making this mistake, though. I remember a special issue
of BYTE magazine from 1988 on benchmarks, where the author of an
article on Pascal benchmarks used the naive fibonacci function above
as a benchmark for function calls. The author then thought it would
be neat to compare the running time to a non-recursive implementation
and was flabbergasted by the large difference, concluding that
function calls must be very expensive indeed.

If your iterative fibonacci is

a := 0;
b := 1;
for i:=0 to n do begin
t := a;
a := b;
b := t+b
end;
writeln(b)

then the recursive version you should compare with is:

fib n = fib1 (n,0,1)

fib1 (0,a,b) = b
fib1 (n,a,b) = fib1 (n-1,b,a+b)

which is simpler than the above (it doesn't need the temporary
variable t) and equally fast (assuming a sensible compiler).

Both of the above use O(n) steps to calculate fibonacci of n. The
recursive function below uses O(log(n)) steps. Try writing this
without recursion.

fibo n = fst (h n)

h 0 = (1,0)
h n | even n = (a^2+b^2,b*(2*a-b)) where (a,b) = h (n`div`2)
h n | odd n = (a*(2*b+a),a^2+b^2) where (a,b) = h (n`div`2)

Note: It will be slower than the simple fib for small n.

Richard also hinted at an O(1) fibonacci function. He probably meant
(phi^n - (1-phi)^n)/sqrt(5), where phi = (sqrt(5)+1)/2. This is,
however, a bit misleading, as this is only O(1) if you can do
arbitrary precision arithmetic in constant time, which is a bit
doubtful. This is also to a lesser extent true for the simpler
versions, as the linear time is assuming that arithmetic operations on
arbitrary-size integers can be done in constant time.

Torben
Jonathan Bartlett
2006-05-09 17:22:37 UTC
Permalink
You might be interested in an article I wrote for IBM DeveloperWorks on
recursive programming:

http://www-128.ibm.com/developerworks/linux/library/l-recurs.html

Jon
----
Learn to program using Linux assembly language
http://www.cafeshops.com/bartlettpublish.8640017
Julian V. Noble
2006-05-09 22:45:07 UTC
Permalink
Post by Jonathan Bartlett
You might be interested in an article I wrote for IBM DeveloperWorks on
http://www-128.ibm.com/developerworks/linux/library/l-recurs.html
Jon
----
Learn to program using Linux assembly language
http://www.cafeshops.com/bartlettpublish.8640017
Nice article. I sent feedback. I don't agree that you should
keep variables constant throughout a program. That's what a
CONSTANT is for.
--
Julian V. Noble
Professor Emeritus of Physics
University of Virginia
Jonathan Bartlett
2006-05-11 18:27:02 UTC
Permalink
Post by Julian V. Noble
Nice article. I sent feedback. I don't agree that you should
keep variables constant throughout a program. That's what a
CONSTANT is for.
Constants don't work for such a thing. Constants must be (1) global and
(2) known at compile-time.

The point is not "constancy" as much as "single assignment only". There
is a subtle difference. A variable can get a new value, but only if it
is a new instance of that variable (i.e. from a new activation record).
Single assignment allows you to keep better control over your loops.
That way, at all times the derivation of any variable is easily
determinable.

Jon
----
Learn to program using Linux assembly language
http://www.cafeshops.com/bartlettpublish.8640017
Robert Maas, see http://tinyurl.com/uh3t
2006-12-13 18:49:25 UTC
Permalink
Post by Jonathan Bartlett
You might be interested in an article I wrote for IBM
http://www-128.ibm.com/developerworks/linux/library/l-recurs.html
I dislike that article, because it starts right off with the
wrongheaded way of computing factorial(N) by building up N stack
frames, with no actual computation done all the way down, then
actually doing the computation on the way back up. At least if
you're going to compute factorial, implement it in a true
"recursive spirit" divide-and-conquor way. Don't mention factorial
at all at the beginning. Instead ask how you would compute the
product of all the integers from M to N. Answer: Divide the problem
in half, from M to the midpoint, and then from after the midpoint
to N. Then after you've demonstrated this really fine algorithm
which takes only log(n) stack depth to compute a product of n
integers (n = N-M), finally mention in passing that prod(1,N) =
factorial(N).

And use Common Lisp or Java instead of C, so you have big integers
built-in instead of being limited by word size where you hit
arithmetic overflow before you hit stack overflow thereby masking
the really important issue.

Or compute modular factorial where fixed precision numbers isn't a
problem.
Impress somebody by recursively computing factorial(one billion)
modulo some prime slightly larger than one billion.
Then show how you get stack overflow if you try it the wrongheaded
way described in the cited article.
Loading...