How not to abuse a "for loop": examples?

C

Chris Torek

If that page is meant to be a troll then ignore this, but why didn't
you malloc the whole array in one go?

It will will not fit. (It seems to me that he uses a series of sparse
arrays, coded rather oddly; but I only glanced at the code.)
Quoting from your page:
char Posvalue[13][13][13][13][13][13][13][13][13][13][13][13];

When I try to compile the above statement with FSF's C compiler
I get:
bonzo.c:1: size of array `Posvalue' is too large

typedef char Nodes[13][13][13][13][13][13][13][13][13][13][13][13];
Nodes *Posvalue = calloc(1, sizeof *Posvalue);

This requires pow(13,12) (23 298 085 122 481) bytes -- requiring
about 45 bits' worth of address space (log2(above) is 44.405...).
Not a problem on some modern 64-bit architectures, perhaps, but
most machines have a bit of trouble handing out over 21 thousand
gigabytes (21.7 TB) of virtual memory. :)
 
T

Toby Newman

# Arthur J. O'Dwyer
You missed the point. Google up "comp.lang.c FAQ" and read
Section 14, which is all about floating-point numbers. (In a
nutshell: 'j' may never be equal to 10.0, due to rounding errors
in the addition operations.)

Thanks for the helpful post. I am aware of the existance of float
rounding errors, but no so aware that I'm able to spot them in the wild
yet :)

So, the code would be corrected by instead doing:

float j;
for (j = 0.0; j < 10.0; j += 0.1)
{
}
 
C

CBFalconer

Toby said:
# Arthur J. O'Dwyer


Thanks for the helpful post. I am aware of the existance of
float rounding errors, but no so aware that I'm able to spot
them in the wild yet :)

So, the code would be corrected by instead doing:

float j;
for (j = 0.0; j < 10.0; j += 0.1)
{
}

No, by writing:

int i;
float j;

for (i = 0; i < 100; i++) {
j = i / 10.0;
...
}
 
A

Arthur J. O'Dwyer


No. CBFalconer has it right, in his parallel reply. Toby's
loop has the exact same problem as the original: you don't know
how many times the loop will be executed! Consider two systems
on which this code might be run; on the first,

j <-- 0, 0.1, 0.2, 0.3, 0.4, 0.499, 0.599, 0.699, 0.799, 0.899, 0.999
(eleven iterations)

On the second,

j <-- 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9
(ten iterations)

Unless you're actually using this loop to distinguish different
systems according to such icky floating-point behavior, it's better
to stick to comparing integers for equality.

HTH,
-Arthur
 
T

Thomas Matthews

Toby said:
# Thomas Matthews




Gets the program stuck in a loop. I guess you could do the same with
while(1)
{}
No. The point is that the index variable is modified
within the block of statements. This was _not_ designed
as a forever loop.

Keeps the program occupied for a little while. I guess better to time
the pause some other way, more accurately and less dependant upon
processor speed.
Nope. The point here is that floating point arithmetic
and comparison are not exact enough for this loop. One
should not use floating point values for indices in a
loop.

I guess the problem with this one is that m being an unsigned integer
will cause problems when you perform
9 - 2 - 2 - 2 - 2 - 2...
and never get to be lessthan or equal to 0, so the loop goes on forever.
This is another issue on unspecified behavior.
The loop causes an underflow at m == 1. One cannot
subract the value of "2" from "1" when the domain
is restricted to all positive integers (including
zero). This is undefined in terms of mathematics.



--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
D

Dave Vandervies

This is another issue on unspecified behavior.
The loop causes an underflow at m == 1. One cannot
subract the value of "2" from "1" when the domain
is restricted to all positive integers (including
zero). This is undefined in terms of mathematics.

Except that we're talking in terms of C here, not mathematics, and in
C this one is well-defined. Unsigned arithmetic wraps -1 around to
UINT_MAX, which (if I'm not mistaken) is required to be odd, so you get
an infinite loop repeatedly counting down the odd integers in the range
of unsigned int.


dave
 
P

pete

Arthur said:
No. CBFalconer has it right, in his parallel reply. Toby's
loop has the exact same problem as the original: you don't know
how many times the loop will be executed!

No! Your code has the problem. You don't know whether
or not j will be less than 10.0 in the body of the loop.

link -> data = log(10.0 - j);
}
link -> next = NULL;
 
A

Arthur J. O'Dwyer

No! Your code has the problem. You don't know whether
or not j will be less than 10.0 in the body of the loop.

link -> data = log(10.0 - j);
}
link -> next = NULL;

I think we've gotten attributions garbled somewhere here.
Thomas's intentionally-wrong code was:

This is wrong, wrong, wrong.

Your "corrected" version was:

This is at least a finite loop, but its behavior is still
implementation-defined.

CBFalconer in a parallel subthread suggested
int jj;
for (jj = 0; jj < 100; jj += 1) {
double j = jj / 10.0;

This is absolutely correct and unimpeachable, and there is
absolutely nothing wrong with it. According to me, that is.
Notice that /I/ never wrote any code in this thread. I just
pointed out that /your/ code was wrong, and /Chuck's/ code
was correct. And I stand by that.

I think you may have assumed that Thomas's code was really
CBFalconer's. Now that you know it's not, are you still
argumentative? ;)

-Arthur
 
O

Old Wolf

Chris Torek said:
Old Wolf said:
If that page is meant to be a troll then ignore this, but why didn't
you malloc the whole array in one go?
typedef char Nodes[13][13][13][13][13][13][13][13][13][13][13][13];
Nodes *Posvalue = calloc(1, sizeof *Posvalue);

This requires pow(13,12) (23 298 085 122 481) bytes -- requiring
about 45 bits' worth of address space (log2(above) is 44.405...).
Not a problem on some modern 64-bit architectures, perhaps, but
most machines have a bit of trouble handing out over 21 thousand
gigabytes (21.7 TB) of virtual memory. :)

Good point. However I have seen Dan Pop recommend this technique
and the OS should optimise sparse arrays by not reserving the space
until it is actually used. Speaking of Mr Pop, I haven't seen any
posts from him for a while.. what's up?
 
R

RCollins

Old said:
Chris Torek said:
Old Wolf said:
If that page is meant to be a troll then ignore this, but why didn't
you malloc the whole array in one go?
typedef char Nodes[13][13][13][13][13][13][13][13][13][13][13][13];
Nodes *Posvalue = calloc(1, sizeof *Posvalue);

This requires pow(13,12) (23 298 085 122 481) bytes -- requiring
about 45 bits' worth of address space (log2(above) is 44.405...).
Not a problem on some modern 64-bit architectures, perhaps, but
most machines have a bit of trouble handing out over 21 thousand
gigabytes (21.7 TB) of virtual memory. :)


Good point. However I have seen Dan Pop recommend this technique
and the OS should optimise sparse arrays by not reserving the space
until it is actually used. Speaking of Mr Pop, I haven't seen any
posts from him for a while.. what's up?

Isn't this the big vacation season in Europe ... where everybody goes
to a health spa, to prepare themselves to face the coming Christmas
season?
 
J

James Dow Allen

Putting this piece of code in context, here's the very
first sentence of my lesson9.htm:
Programming loses much of its fun when one's
programs all look the same.

Chris Torek said:
... a series of sparse arrays, coded rather oddly ...

Given the above context, I'll take this as a compliment! :)

The 90-line source program in question is *much harder* to
read or understand than the average 90-line source program.
But that's not a fair comparison. The question should be,
how does the net readability of my code compare with another
program that *solves the same problem*?

I posted the link to this peculiar code almost as a
joke, but now it occurs to me that it might pose an
interesting challenge for programmers in general, or
c.l.c'ers in particular. It would be instructive for
me, and perhaps others, to compare with a properly
coded version, but we'll need that properly coded version.
(It should be a full program that solves Waldo's Nim;
otherwise I'm afraid fragments will be posted that simply
can't accomplish what the peculiar code does.)

Write the program the way it should be; let c.l.c'ers
vote on the best solution. I'll be happy to post the
winning submission at my website (unless the winner feels
this would be a booby prize. :) It shouldn't take long
to do it: as Mr. Torek pointed out, the peculiar part
just sets up a sparse array, and the rest is a very
simple algorithm which isn't the issue. (A heuristic
improvement may exist, but that would be a separate
topic for alt.brain.teasers.)

A thread based on such a ``contest,'' might be fun for
c.l.c, and you should be grateful to me for playing the
buffoon whose code needs improvement. But first, let me
summarize my feelings about my own code:
(1) it was written for play not pay; paid code would
have been improved in some ways (though I'm afraid
it still would have used a macro like NFOR).
(2) nesting 12 loops seems like the natural and best
way to write the program; since the loops are essentially
identical, using a macro seemed right; with
these decisions, packing the calloc() into the for-statement
substantially simplified the syntax. You may disapprove,
but the intent was to clarify the code, not obfuscate it!
(3) some aspects of the code others find ``bad'' are
indeed bad. My question is whether the cure would
be worse than the disease. We all agree global variables
are bad, but we use them when the alternative is
dozens of unwieldy function arguments. We all agree
long functions are bad, but some of us use them when
factorings aren't really helpful. And I'd like to see the
"proper" version of this program before agreeing it's better.
(4) coding involves trade-offs, and shouldn't be dictated
by dogma. (as an extreme example of dogma, one can find old
messages in c.l.c with the claim that *longjmp()* is
better than *goto* because it's a function, not an (evil)
keyword.)
(5) as most readers realized, the code indulged a whimsical
(or perverse) love of minimalism. I hope some of you also
find programming *Fun*!

* * * * * * * * * * * * * * *

Someone wrote, in effect:
Was this a troll?
Just do calloc(13*13*13*13*13*13, 13*13*13*13*13*13);
[I've rearranged the 13's so the numbers fit size_t.]

Errh, my contest offer is sincere, but submissions will
be expected to compile and execute on present-day computers.

Someone else wrote, in effect:
The flaw in this code is the 18 tab characters `indent'
needs to add, after `cc -E' ...

Was *this* a troll? I personally see nothing wrong with
nesting a dozen loops, especially here when the loops are
equivalent (just handling different axes of a multi-dimensional
structure), but if there *is* something wrong with it,
fitting tabs onto paper or screen can't be the problem, can
it? And why would anyone think adding 18 indentations to
the code is a good idea (unless your 4th grade programming
teacher used to hit you with a ruler when you didn't indent
every sub-block)? Finally, although we've all used
cc -E | indent
to decipher obfuscated code, the idea that code like

#define NFOR(N) something_very_complicated_but \
whose_complexity_doesn't_involve_N_or_submacros
NFOR(1) NFOR(2) NFOR(3) NFOR(4) NFOR(5) NFOR(6)
NFOR(7) NFOR(8) NFOR(9) NFOR(10) NFOR(11) NFOR(12)

calls for the `cc -E | indent' tool strikes me as inexplicable.

James
 
M

Mabden

Old Wolf said:
Good point. However I have seen Dan Pop recommend this technique
and the OS should optimise sparse arrays by not reserving the space
until it is actually used. Speaking of Mr Pop, I haven't seen any
posts from him for a while.. what's up?

Indeed. I invoked His name in another thread (and was cautioned
appropriately) and received nary a word. I did get a slight anal
discomforture later in the week, tho.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,372
Latest member
LucretiaFo

Latest Threads

Top