473,508 Members | 2,412 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

derangement: code review request

A derangement is a mapping of a set onto itself leaving no element fixed. I
realized that that was what I was programming when I was asked to randomly
determine who buys presents for whom this year in my wife's family.
Obviously, one does not buy for himself. The code is followed by some
questions.

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

#define fam_size 20
//must be between 2 and randmax minus one

int main(void)
{
int i,t,a[fam_size],b[fam_size],notdone1,notdone2;
int m,j;
time_t timer;
long counter, top_num;

//determine good random numbers
srand(time(&timer));
top_num=RAND_MAX-(RAND_MAX%fam_size)-1;

//initialize arrays

for (i=0;i<fam_size;i++){
a[i]=b[i]=0;
}
//main control structures
counter=0;
notdone1=1;

while(notdone1)
{
//ignore this first while loop
//this will ultimately play with
//any given derangement to see if it's
//suitable
for(j=0;j<fam_size;j++)

{
notdone2=1;
while(notdone2){

++counter;
t=rand();
m=t%fam_size;
if ((b[m]==0)&&(m!=j)&&(t<=top_num)){
a[j]=m;
b[m]=1;
notdone2=0;
}
else {
notdone2=1;
}
/* bad luck checker
starts us over except for counter*/
if ((j==fam_size-1)&&(b[j]==0)){
for (i=0;i<fam_size;i++){
a[i]=b[i]=0;
}
notdone2=0;
j=-1;
}
//end notdone2 while
}
//end j loop
}

for(i=0;i<fam_size;i++)
printf("%d %d\n",i,a[i]);
printf("counter= %d\n",counter);
notdone1=0;
//end outer while
}
return 0;
}

Q1) Is this code ANSI-compliant and C99-compliant?

Q2) The obvious style shortcomings are mostly a product of my IDE looking
different than what is copy/pasted (no Mr. Mair, I am not ready to be weened
off the tit). What style shortcomings do you see that don't involve
spacing?

Q3) There's at least one major design flaw. It follows the remark "bad luck
checker" and covers the event that the final element can only be mapped to
itself, which happens 1 out of every fam_size times that the program is run.
Any ideas how to make that less hideous?

++thanks. MPJ
----------------------------------
*OT* I had been teaching my nine-month-old during feedings:

"My big eater
hates Derek Jeter"

I guess I'll have to find new material :-) *end OT*
Nov 14 '05
136 5338
Da*****@cern.ch (Dan Pop) writes:
In <ln************@nuthaus.mib.org> Keith Thompson <ks***@mib.org> writes:

[...]
The best solution for anyone still programming on VMS^H^H^H OpenVMS is
probably to use the newer DECC rather than VAXC.


I was not even aware that VAX C still exists as a supported HP product.


I have no idea whether it is; I suspect it isn't.

The last time I actually worked on OpenVMS, we used both VAXC (on
VAXen) and DECC (on VAXen and Alphas) (I advocated abandoning VAXC at
the time). This was about 5-6 years ago. Now I have a stray account
on an old VAX/OpenVMS system (6.3, I think) that happens to have VAXC
and DECC installed; it's likely nothing on that system is supported.
I have no interest in support for it anyway, so I haven't looked into
it.

The more general issue is this: Always pay attention to compiler
diagnostics. Fixing your code so it compiles without warnings is
usually, but not always, a good idea. The exceptions are those
(hopefully rare, assuming a good compiler) cases where you know better
than the compiler.

Fixing your code doesn't mean tweaking it until the warning goes away,
it means understanding the problem and correcting it. Adding a cast
can eliminate a type conflict warning, but it's usually better to make
the types match in the first place. Declaring "void main" can
eliminate a warning about a missing return statement, but it's better
to add the return statement (and complain to the vendor if the warning
actually advises you to use "void main", as we saw here recently in
another thread).

To summarize the summary of the summary, programming is hard work.

--
Keith Thompson (The_Other_Keith) ks***@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.
Nov 14 '05 #51
falscher Ansatz MPJ
#define '.h>' @
#define > ' '
#define @ '.h>'
> > /* Every C program that I will consider begins with a hash
> > and ends with a close brace */
> > > > #include <stdio.h>
> > > > #include <stdlib.h>
> > > > #include <time.h>

> > > >
> > > > #define FAMSIZ 15 /*between 2 and RAND_MAX*/
> > > > #define SWAP \
> > > (tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
> /*would I be surprised if this worked*/
> > > >
> > > > int main(){
> > >
> > > int i;
> > > int m,n,tmp,t,top_num;
> > > int buys_for[FAMSIZ];
> > > >
> > /*i is always available for dummy*/
> > top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
> > srand(time(NULL));
> >
> > /*initialize*/
> > for (i=0;i<FAMSIZ;i++) buys_for[i]=i;
> >
> > /*main control*/
> >
> > > > printf("%d number=", t);
> > > > return 0;
> > > > }
> > > >
> > > >
> > >
> > >
> >
> >
>
>

Eight strikes, I'm out. Please don't tell me you read all this way

because I was OT. That would just make you dumb. MPJ

Nov 14 '05 #52
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
Acronyms that are pronounced/used as regular words eventually become just
regular words and we tend to forget their acroynm-ness. "Laser" is an
example of that, or "spool" (and in fact I used the word spool for
quite a while before finding out that it is an acronym).


Spool is probably a backronym. Even if it isn't, it was almost certainly
"designed"[1] from the start to remind one of those round, flanged
objects which are used to hold a length of thread, or a print job
created on one dinosaur, written to magtape or even punched tape which
was, well, spooled onto a spool, transferred to another dinosaur which
controls the printer, and there rolled off the spool, read and printed.

Richard

[1] scare quotes intentional
Nov 14 '05 #53
In <io********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
2004-compliant. I have two macros. Mr. Pop's RND was not even close to
right.


I have asked you to explain why. If you are unable to do it, there is no
point in repeating it. I have given you a *complete* program. Please
point out the flaws in its results.

My RND is flawed *only* when the size of the family is very close to
RAND_MAX, or when the size of the family is a small power of two and the
actual implementation of rnd() is extremely poor (only the last bits of
the "random" value are used in this case).

If you have other objections to it, please state them loud and clear.

You may also want to elaborate on why your problem *requires* a high
quality sequence of random numbers.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #54
> >2004-compliant. I have two macros. Mr. Pop's RND was not even close to
right.
I have asked you to explain why. If you are unable to do it, there is no
point in repeating it. I have given you a *complete* program. Please
point out the flaws in its results.

My RND is flawed *only* when the size of the family is very close to
RAND_MAX, or when the size of the family is a small power of two and the
actual implementation of rnd() is extremely poor (only the last bits of
the "random" value are used in this case).

If you have other objections to it, please state them loud and clear.


Dan, all fifteen bits count. If rand() stinks, then don't make it worse.
You may also want to elaborate on why your problem *requires* a high
quality sequence of random numbers.


Because, if it's two lines of code to get it right, then you get it right.

If interest remains after I get this darn thing put together from top to
bottom, then we can talk about this stuff. It would really help to be able
to read and write files, but I'm not there yet. I think I have to use win32
tools for files right now. Correction, right now, I have a ton of work to
do:-( MPJ
Nov 14 '05 #55
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /*between 2 and RAND_MAX*/
#define SWAP \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
int main(){
int i;
int m,n,tmp,t,top_num,penry;
int buys_for[FAMSIZ];

/*rand() prelims*/
top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
srand(time(NULL));

/*initialize*/
for (i = 0; i < FAMSIZ; i++) buys_for[i] = i;

/*main control*/
for(m = 0; m < FAMSIZ; m++){
while(1){
t = rand();
if (t > top_num) continue;
penry = t % FAMSIZ;
if (penry == m) continue;
if (buys_for[m] == buys_for[penry] || buys_for[penry] == buys_for[m])
continue;
break;
}
SWAP(m,n);
}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

return 0;
}

Nov 14 '05 #56
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /*between 2 and RAND_MAX*/
#define SWAP \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
int main(){
int i;
int m,n,tmp,t,top_num;
int buys_for[FAMSIZ];

/*rand() prelims*/
top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
srand(time(NULL));

/*initialize*/
for (i = 0; i < FAMSIZ; i++) buys_for[i] = i;

/*main control*/
for(m = 0; m < FAMSIZ; m++){
while(1){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
if (n == m) continue;
if (buys_for[m] == buys_for[n] || buys_for[n] == buys_for[m])
continue;
break;
}
SWAP(m,n);
}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

return 0;
}
/*one bug down*/
Nov 14 '05 #57
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /*between 2 and RAND_MAX*/
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
int main(){
int i;
int m,n,tmp,t,top_num,penry;
int buys_for[FAMSIZ];

/*rand() prelims*/
top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
srand(time(NULL));

/*initialize*/
for (i = 0; i < FAMSIZ; i++) buys_for[i] = i;

/*main control*/
for(m = 0; m < FAMSIZ; m++){
while(1){
t = rand();
if (t > top_num) continue;
penry = t % FAMSIZ;
if (penry == m) continue;
if (buys_for[m] == buys_for[penry] || buys_for[penry] == buys_for[m])
continue;
break;
}
SWAP(m,n);
}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

return 0;
}


Nov 14 '05 #58
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
A couple of the names use abbreviations as part of the name (eg,
'fam_size'). I recommend using the whole word, and always avoiding
abbreviations.
I disagree. Even for normal abbreviations, not just for acronyms,
industry-standard abbrevs are probably more legible than the whole word.

I mean, my main program deals with entering data for advertisement. Can
you imagine how much larger and less legible my code would've been if
I'd used advertisement_width_in_columns everywhere I know have adv_cols?


How about 'ad_columns'? My unabridged dictionary includes 'ad' as a
word. If 'ad_columns' is still too long for you, 'ad_width' has the
same number of letters as 'adv_cols'.

void


Ew, ganoo style.


It's hard to know how to respond to a statement that is clearly
nothing more than name calling. If you have a comment about the usage
rather than just an objection to some people who happen to use it, how
about letting us know what that is?

By the way, I've been writing return-type-on-a-separate-line style
function definitions in C since before the GNU project was formed.

generate_random_derangement( unsigned a[], unsigned n ){
unsigned i, j, t, r, r_limit;

r_limit = RAND_MAX - RAND_MAX % n;

for( i = 0; i < n; i++ ) a[i] = i;


Ew ew ew! You just proved that whitespace isn't _always_ good (and
whitespace on the _inside_ or parens rarely is).


If indeed something has been proved here, a better candidate is that
the spacing style used above is something Richard Bos is unaccustomed
to seeing.

The spacing style exemplified in the 'for' statement above arises
out of several considerations (among others):

1. The multiple spaces make it easier for my eyes to separate
the several control clauses of a 'for', and easier for my
brain to chunkify them.

2. Following a precept of Hoare's: Things that are different
should look different; hence, I don't put spaces inside
parentheses surrounding sub-expressions (at least not
usually), but I do put spaces inside parentheses used in
function calls/definitions, and also inside parentheses
used with control expressions.

3. Control expressions (in 'for', 'if', 'while', etc) are
different in character from other expression uses, and
often more central to understanding how an algorithm
works; using two spaces around control expressions helps
them stand out from the other code around them, which in
my experience aids comprehension.

Aside from your gut reaction, do you have any statement to offer about
why one might prefer an alternative spacing style over a style like
the one shown above? It seems like all you've said is, "In my
opinion, it's bad." Anything more objective to propose?

How about this more
moderate version:

for (i = 0; i < n; i++) a[i] = i;

In fact, I'd prefer

for (i=0; i<n; i++) a[i]=i;

But double spaces? Yuck.


I've tried both of the moderate versions. I prefer a style that is a
little more heterogeneous, for the reasons explained above; just as
in writing prose, too much homogeneity can itself make the text less
readable.

I admit the wider spacing looks strange at first and takes some
getting used to. That doesn't have to mean it's the wrong path;
the first time I ate sushi I didn't like it either.
Nov 14 '05 #59
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
Acronyms that are pronounced/used as regular words eventually become just
regular words and we tend to forget their acroynm-ness. "Laser" is an
example of that, or "spool" (and in fact I used the word spool for
quite a while before finding out that it is an acronym).


Spool is probably a backronym. Even if it isn't, it was almost certainly
"designed"[1] from the start to remind one of those round, flanged
objects which are used to hold a length of thread, or a print job
created on one dinosaur, written to magtape or even punched tape which
was, well, spooled onto a spool, transferred to another dinosaur which
controls the printer, and there rolled off the spool, read and printed.


Yes, spool was a bad example. Even if it wasn't "designed", certainly
the word spool was a word before the acronym came into existence.

On the other hand that doesn't invalidate the point. We still have
radar, sonar, and scuba, for example.
Nov 14 '05 #60
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /*between 2 and RAND_MAX*/
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
int main(){
int i;
int m,n,tmp,t,top_num;
int buys_for[FAMSIZ];

/*rand() prelims*/
top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
srand(time(NULL));

/*initialize*/
for (i = 0; i < FAMSIZ; i++) buys_for[i] = i;

/*main control*/
for(m = 0; m < FAMSIZ; m++){
while(1){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
if (n == m) continue;
if (buys_for[m] == buys_for[n] || buys_for[n] == buys_for[m])
continue;
break;
}
SWAP(m,n);
}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

return 0;
}
/*This compiles, links and crashes*/


Nov 14 '05 #61
In <0J********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
>2004-compliant. I have two macros. Mr. Pop's RND was not even close to
>right.


I have asked you to explain why. If you are unable to do it, there is no
point in repeating it. I have given you a *complete* program. Please
point out the flaws in its results.

My RND is flawed *only* when the size of the family is very close to
RAND_MAX, or when the size of the family is a small power of two and the
actual implementation of rnd() is extremely poor (only the last bits of
the "random" value are used in this case).

If you have other objections to it, please state them loud and clear.


Dan, all fifteen bits count. If rand() stinks, then don't make it worse.
You may also want to elaborate on why your problem *requires* a high
quality sequence of random numbers.


Because, if it's two lines of code to get it right, then you get it right.


This is NOT an answer. If a crappy random sequence is good enough for the
problem at hand, there is no point in using anything better.

Either explain WHY your problem requires a high quality sequence of
random numbers (and point out any flaws in the output of my program) or
stop wasting my time.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #62
> >> >2004-compliant. I have two macros. Mr. Pop's RND was not even close
to
>right.

I have asked you to explain why. If you are unable to do it, there is no point in repeating it. I have given you a *complete* program. Please
point out the flaws in its results.

My RND is flawed *only* when the size of the family is very close to
RAND_MAX, or when the size of the family is a small power of two and the actual implementation of rnd() is extremely poor (only the last bits of
the "random" value are used in this case).

If you have other objections to it, please state them loud and clear.
Dan, all fifteen bits count. If rand() stinks, then don't make it worse.
You may also want to elaborate on why your problem *requires* a high
quality sequence of random numbers.


Because, if it's two lines of code to get it right, then you get it

right.
This is NOT an answer. If a crappy random sequence is good enough for the
problem at hand, there is no point in using anything better.

Either explain WHY your problem requires a high quality sequence of
random numbers (and point out any flaws in the output of my program) or
stop wasting my time.


1. If you think that I control how you use your time, you overestimate my
influence.

2. Implementations come and go. My guess is that somebody who is not a
complete knucklehead is going to write a decent rand() implementation, at
which point, code written AS IF rand were good now, will port and BECOME
good.

3. The reason that I require this program to be right on the nuts is that
I'm going to take it to a very good combinatorialist who just happens to be
married to a statistician. A couple of traded favors later, I've got a much
better grasp on what I used to know in Hogg & Craig days. (I can actually
say I bought Hogg and Tanis too.) I was famously bad at stats. That I have
not been able to test my progs to see whether the pseudorandoms pass tests
undermines my ability to do a crucial part of development.

4. In case I haven't said it, I appreciate the personal attention you have
given to my endeavor to become a better programmer. MPJ
Nov 14 '05 #63
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
A couple of the names use abbreviations as part of the name (eg,
'fam_size'). I recommend using the whole word, and always avoiding
abbreviations.


I disagree. Even for normal abbreviations, not just for acronyms,
industry-standard abbrevs are probably more legible than the whole word.

I mean, my main program deals with entering data for advertisement. Can
you imagine how much larger and less legible my code would've been if
I'd used advertisement_width_in_columns everywhere I know have adv_cols?


How about 'ad_columns'? My unabridged dictionary includes 'ad' as a
word. If 'ad_columns' is still too long for you, 'ad_width' has the
same number of letters as 'adv_cols'.


Whatever. It's still an abbreviation, and avoiding abbreviations would
have been counterproductive, in this case.
void


Ew, ganoo style.


It's hard to know how to respond to a statement that is clearly
nothing more than name calling. If you have a comment about the usage
rather than just an objection to some people who happen to use it, how
about letting us know what that is?


It's ugly. It splits the type of the function over two lines for no good
reason (antediluvian editors are no excuse), and separates the return
type from the identifier in a way that nobody would even consider using
for objects. You don't write

int
i, j, counter;

do you? Well, then, why do so for functions?
generate_random_derangement( unsigned a[], unsigned n ){
unsigned i, j, t, r, r_limit;

r_limit = RAND_MAX - RAND_MAX % n;

for( i = 0; i < n; i++ ) a[i] = i;


Ew ew ew! You just proved that whitespace isn't _always_ good (and
whitespace on the _inside_ or parens rarely is).


If indeed something has been proved here, a better candidate is that
the spacing style used above is something Richard Bos is unaccustomed
to seeing.


Thankfully, yes. It's been quite well proven (for centuries; spacing is
not something that is unique to source code) that both too few, but also
too much whitespace renders text less legible.
Y o u d o n o t w r i t e like t h i s ,d o y o u ?

Richard
Nov 14 '05 #64
In <Hf********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
Either explain WHY your problem requires a high quality sequence of
random numbers (and point out any flaws in the output of my program) or
stop wasting my time.


1. If you think that I control how you use your time, you overestimate my
influence.

2. Implementations come and go. My guess is that somebody who is not a
complete knucklehead is going to write a decent rand() implementation, at
which point, code written AS IF rand were good now, will port and BECOME
good.

3. The reason that I require this program to be right on the nuts is that
I'm going to take it to a very good combinatorialist who just happens to be
married to a statistician. A couple of traded favors later, I've got a much
better grasp on what I used to know in Hogg & Craig days. (I can actually
say I bought Hogg and Tanis too.) I was famously bad at stats. That I have
not been able to test my progs to see whether the pseudorandoms pass tests
undermines my ability to do a crucial part of development.

4. In case I haven't said it, I appreciate the personal attention you have
given to my endeavor to become a better programmer. MPJ


I failed to find the answer to my very precise question in any of your
4 points, or even combining them together. "Because I'm going to show it
to an expert" is NOT an answer. As any engineer knows, only a fool
would use a better component than the actual design requires (unless
constrained by external factors: the better component is actually
cheaper or the "good enough" component is not available).

As bad as it is, the vanilla rand() implementation coming with most C
libraries is good enough for most programs using random numbers. The
others wouldn't use a random number generator with unknown properties,
anyway. As always, there is a tradeoff: poor quality random sequences
are usually cheaper (in terms of CPU cycles) than high quality ones.

Good implementors of the standard C library go for algorithms that
maximise the quality/cost ratio. The others are foolishly insisting on
either (high) quality or (low) cost.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #65
> >> Either explain WHY your problem requires a high quality sequence of
random numbers (and point out any flaws in the output of my program) or
stop wasting my time.


1. If you think that I control how you use your time, you overestimate myinfluence.

2. Implementations come and go. My guess is that somebody who is not a
complete knucklehead is going to write a decent rand() implementation, at
which point, code written AS IF rand were good now, will port and BECOME
good.

3. The reason that I require this program to be right on the nuts is thatI'm going to take it to a very good combinatorialist who just happens to bemarried to a statistician. A couple of traded favors later, I've got a muchbetter grasp on what I used to know in Hogg & Craig days. (I can actuallysay I bought Hogg and Tanis too.) I was famously bad at stats. That I havenot been able to test my progs to see whether the pseudorandoms pass testsundermines my ability to do a crucial part of development.

4. In case I haven't said it, I appreciate the personal attention you havegiven to my endeavor to become a better programmer. MPJ


I failed to find the answer to my very precise question in any of your
4 points, or even combining them together. "Because I'm going to show it
to an expert" is NOT an answer. As any engineer knows, only a fool
would use a better component than the actual design requires (unless
constrained by external factors: the better component is actually
cheaper or the "good enough" component is not available).

As bad as it is, the vanilla rand() implementation coming with most C
libraries is good enough for most programs using random numbers. The
others wouldn't use a random number generator with unknown properties,
anyway. As always, there is a tradeoff: poor quality random sequences
are usually cheaper (in terms of CPU cycles) than high quality ones.

Good implementors of the standard C library go for algorithms that
maximise the quality/cost ratio. The others are foolishly insisting on
either (high) quality or (low) cost.

Let's take the example of a roullette wheel with a single ought. The way
you designed the RND macro would have been just fine: the lack of
equiprobability is completely trumped by the fact that some dipstick is
giving his money to the house 1/41 times. That same dipstick would have no
chance of getting ahead by the fact that the UNNAMED IMPLEMENTATION's rand()
is less than it could be.

On another hand, let's say some M.I.T. brat actually has the sack to walk
around knowing not just that it's been 1.1 billion seconds from the time the
champaign hit the bow on the '98 OS, but he has discerned, with the help of
a few buddies, that a good time to bet on 37 is 1,098,589,231 seconds. I
think that with the cadence of the game, you could get within 3 seconds
either way. This yields a forty to seven payoff.

The poor punks become millionaires and engulfed in a lifestyle that ends
only one way. But when it hits the fan, your boss comes to you and says,
"we need to change the way we come up with random numbers." Because my
rand() is written AS IF the numbers were good, I could make changes without
altering a keystroke within main().

It has dawned on me, that this program is not going to become the
infrastructure of Vegas. Probability is, however, hard enough without
lackadaisical coding habits. Furthermore, it's still evolving. Gian-Carlo
said, "Kolmogorov had the truth, but not the whole truth."

I'm pretty close on this prog now. MPJ
Nov 14 '05 #66
rl*@hoekstra-uitgeverij.nl (Richard Bos) wrote:
Keith Thompson <ks***@mib.org> writes:
HTH, HAND, YMMV.


Hail To Hastur - His Arrival Nears Daily.


Hastur La Vista ? He has already arrived (if you live in california).
Nov 14 '05 #67
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
rl*@hoekstra-uitgeverij.nl (Richard Bos) writes:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:

> A couple of the names use abbreviations as part of the name (eg,
> 'fam_size'). I recommend using the whole word, and always avoiding
> abbreviations.

I disagree. Even for normal abbreviations, not just for acronyms,
industry-standard abbrevs are probably more legible than the whole word.

I mean, my main program deals with entering data for advertisement. Can
you imagine how much larger and less legible my code would've been if
I'd used advertisement_width_in_columns everywhere I know have adv_cols?
How about 'ad_columns'? My unabridged dictionary includes 'ad' as a
word. If 'ad_columns' is still too long for you, 'ad_width' has the
same number of letters as 'adv_cols'.


Whatever. It's still an abbreviation, and avoiding abbreviations would
have been counterproductive, in this case.


Sorry, I thought the meaning was obvious - to use words, and avoid
abbreviations that aren't words. Nothing wrong with using 'gas' (in
the sense of "gasoline"), 'motel' (short for "motor hotel"), or
'transistor' (short for "transfer resistor"), since they are all used
as words. Perhaps the phrasing should have been to avoid non-words,
in particular abbreviations that aren't words.

> void

Ew, ganoo style.


It's hard to know how to respond to a statement that is clearly
nothing more than name calling. If you have a comment about the usage
rather than just an objection to some people who happen to use it, how
about letting us know what that is?


It's ugly.


I might say the same thing about the all-on-one-line style. :)

Seriously though, how about a statement that is somewhat more
objectively verifiable?

It splits the type of the function over two lines for no good
reason [...],
Just curious - how can you say that when you haven't heard what the
reasons are? Or are you saying you've considered all possible reasons
and determined that none of them are good?

Also - what is the metric for whether a reason is "good"?

and separates the return
type from the identifier in a way that nobody would even consider using
for objects. You don't write

int
i, j, counter;

do you? Well, then, why do so for functions?


Clearly the two cases are different, and so different reasoning
applies:

1. Functions are different from objects; this difference is
made evident in many places in the text of the standard.

2. Variable declarations (and definitions) usually can be
written one per line, with variable names aligned on several
lines; function definitions always have function bodies
after them, so there isn't the same benefit of aligning
function names in several successive functions.

3. Function definitions tend to use a lot of space after the
function name (for parameter names and types), whereas
variable declarations usually don't. So line breaking
considerations are different for the two cases.

> generate_random_derangement( unsigned a[], unsigned n ){
> unsigned i, j, t, r, r_limit;
>
> r_limit = RAND_MAX - RAND_MAX % n;
>
> for( i = 0; i < n; i++ ) a[i] = i;

Ew ew ew! You just proved that whitespace isn't _always_ good (and
whitespace on the _inside_ or parens rarely is).


If indeed something has been proved here, a better candidate is that
the spacing style used above is something Richard Bos is unaccustomed
to seeing.


Thankfully, yes. It's been quite well proven (for centuries; spacing is
not something that is unique to source code) that both too few, but also
too much whitespace renders text less legible.
Y o u d o n o t w r i t e like t h i s ,d o y o u ?


I might, if I thought it would communicate more effectively.

But more to the point, the analogy text makes a weak and silly
argument. Weak because the spacing in the prose text example is
clearly more homogeneous and more random than the code text example;
silly because it presumes that the same kind of reasoning that applies
to prose text should apply to code text, whereas obviously that's not
so. We don't write code text all left-justified; nor is code text
filled the way prose text paragraphs are. The reading mechanisms for
the two kinds of text are quite different; we would expect that what
style choices communicate effectively would in many cases be different
also.

Nov 14 '05 #68
On 29 Oct 2004 10:17:19 -0700, Tim Rentsch <tx*@alumnus.caltech.edu>
wrote:

Also - what is the metric for whether a reason is "good"?


Finally, in this thread, a question that's easy to answer. It's "good"
if I like it. I don't like your excess spacing(1), therefore it's not
good ;-)

(1) It makes my eyes stutter.

--
Al Balmer
Balmer Consulting
re************************@att.net
Nov 14 '05 #69
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:

#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)tmp must be provided from the outside -- this is a possible
source of error.


Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.
either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))
No point in complicating the interface of SWAP.
or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}
Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.
or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)
If you make it a function, please spell its name in lower case.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().


Source code overheads, execution time overheads for no redeeming merits.
The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.

As a general purpose solution, a macro is better than a function, because
it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:

#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)

Eliminating the tmp parameter requires a very handy GNU C extension,
typeof. It didn't make its way into C99 because the committee members
couldn't figure out how to write its specification.
int main(){

Nit: Make this
int main (void) {
for clarity; then everyone knows that you want the empty
parameter list.


Who could possibly believe otherwise? One doesn't need to be an expert in
standard C in order to realise that the original version specifies an
empty list.

The only valid objection to the original form is that C99 deprecates it.
Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #70

Michael Mair" wrote:
Merrill & Michele wrote:
/*derangement.c contributors: Eric Sosman, Dan Pop et ali*/

s/ali/alii/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /*between 2 and RAND_MAX*/

Note: I would rather make this
#define FAMSIZ 15 /* between 2 and RAND_MAX */
The extra ' ' between * and comment text are not only for clarity
but if you start using tools like splint or doctext, then you can
make sure that an ordinary comment is not mistaken for something
else ( splint: /*@ splint-option @*/, doctext:
/*D
general description
D*/ and other)
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)

tmp must be provided from the outside -- this is a possible
source of error. either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))
or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}
or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().


This follows K&R and might have advantages of which I am not aware. A
disadvantage is that it uses pointers, which are tough if you want the prog
to be read by people who got their PhDs before the advent of the computer.

int main(){

Nit: Make this
int main (void) {
for clarity; then everyone knows that you want the empty
parameter list.
int i;
int m,n,tmp,t,top_num;
> int buys_for[FAMSIZ];

I'd rather put the variables used as loop counters or
indices in one line and the important ones with a "name"
in the other instead of making this i vs the rest.
This also makes you realize that either i or m is not
necessary. I would call t differently, say: random_num
to liken it to top_num.

/*rand() prelims*/
top_num=RAND_MAX - ( RAND_MAX % FAMSIZ) - 1;
srand(time(NULL));

/*initialize*/
for (i = 0; i < FAMSIZ; i++) buys_for[i] = i;

/*main control*/

/*permute randomly*/
for(m = 0; m < FAMSIZ; m++){

Nit: Go for a consistent spacing style. This for and the
above are different. I would rather use
for (m = 0; m < FAMSIZ; m++) {
and deliberately put no space between function name and (
for function calls.
while(1){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
SWAP(m,n);
break;
}

This effectively obfuscates the fact that you do not
have a loop encompassing all instructions.
do {
t = rand();
} while (t > top_num);

n = t % FAMSIZ;
SWAP(m,n);
is IMO clearer.


I agree.
}

/*remove collisions*/

for(m = 0; m < FAMSIZ; m++){
if (buys_for[m] == m){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
if (n == m) continue;
if (buys_for[m] == n ) continue;
SWAP(m,n);
break;
}

If you replace (t > top_num) by (t > FAMSIZ - 1), then you
will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
your final output -- your continues as well as the break refer to
the outer for-loop.
Replace if by while:
while (buys_for[m] == m) {
to heal it. However, I would structure the code as above:
if (buys_for[m] == m) { /* collision */
/* Obtain random number which does not reproduce this
** or ensue another collision. */
do {
t = rand();
if (t > top_num) /* right range */
continue;
n = t % FAMSIZ;
} while ( (n == m) || (buys_for[m] == n) );

SWAP(m,n);
}


Are you contending that the code doesn't work for some defined FAMSIZ <
RAND_MAX?
}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

Nits:
- "rotate" the table; otherwise it is not handy for large FAMSIZE
- insert spacing or separators of some sort, otherwise, at
FAMSIZE > 100, you get unreadable numbers.
For example:
/*out to console*/
putchar('\n');
for (i = 0; i < FAMSIZ; i++)
printf ("%3d\t%3d\n", i, buys_for[i]);

return 0;
}


As an aside: You stressed the importance of optimally treating the
random numbers in your discussion with Dan Pop.
Then, I would go one step further in your place:
Put initialization of the PRNG and calls to it into functions of their
own, for example:

static int my_RANDMAX = RANDMAX, my_modulus = 0;

void init_myrand (int modulus)
{
srand( (unsigned) time(NULL) );
my_modulus = modulus;
my_RANDMAX = RANDMAX - (RANDMAX % modulus) - 1;
}

int myrand (void)
{
int tmp;
do {
tmp = rand();
} while (tmp > my_RANDMAX);

return t%my_modulus;
}

....

init_myrand(FAMSIZE);
....
n = myrand();

or some more flexible solution. This allows you to play around with
different PRNGs and different ways to "fetch" the return value.
Example for the latter: In old implementations of rand(), the higher
bits are more random than the lower bits, so you could just get the
highest n bits and adjust my_RANDMAX correspondingly...


Now I'm truly confused. But I have to post and run. MPJ

Nov 14 '05 #71
Merrill & Michele wrote:
.... snip ...
This follows K&R and might have advantages of which I am not aware.
A disadvantage is that it uses pointers, which are tough if you want
the prog to be read by people who got their PhDs before the advent
of the computer.

.... snip ...

Bloody nonsense, and gross age discrimination.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!

Nov 14 '05 #72
> > MPJ
This follows K&R and might have advantages of which I am not aware.
A disadvantage is that it uses pointers, which are tough if you want
the prog to be read by people who got their PhDs before the advent
of the computer. ... snip ...

CBFalconer"
Bloody nonsense, and gross age discrimination.


I was to bring this program yesterday to a man who is proud of the fact that
the only progs he's ever written have been hand-coded instructions to a
Turing machine. Unfortunately, the return value was negative. But it's
gotten me to think about the generational issues with comp sci.

My mathematical mentor is my uncle, director of mathematical and computer
sciences at a midwestern university. I sat in on one of his C classes once.
I found the material pedestrian compared to his logic design class. I don't
think that programmers realize how much trouble they can get in when they
start pointing (see illustration, 1948 Lithograph).

http://home.comcast.net/~beckjensen/pointer.htm

I wear a lot of different hats and talk to all kinds of folks. Pointers to
them might be like the non-locality of space for you. MPJ
Nov 14 '05 #73
Merrill & Michele wrote:
MPJ
This follows K&R and might have advantages of which I am not
aware. A disadvantage is that it uses pointers, which are tough
if you want the prog to be read by people who got their PhDs
before the advent of the computer. ... snip ...

CBFalconer"
Bloody nonsense, and gross age discrimination.

.... snip ...
http://home.comcast.net/~beckjensen/pointer.htm

I wear a lot of different hats and talk to all kinds of folks.
Pointers to them might be like the non-locality of space for you.

I wasn't referring to pointers. I was talking about your attitude
to older people. Everybody with a brain and mild familiarity with
C knows that pointer misuse is responsible for many errors. Just
like in assembly. The fact that you ignored my point shows that
you have a serious problem there.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #74

MPJ
This follows K&R and might have advantages of which I am not
aware. A disadvantage is that it uses pointers, which are tough
if you want the prog to be read by people who got their PhDs
before the advent of the computer.
... snip ...

CBFalconer"
Bloody nonsense, and gross age discrimination.

... snip ...

http://home.comcast.net/~beckjensen/pointer.htm

I wear a lot of different hats and talk to all kinds of folks.
Pointers to them might be like the non-locality of space for you.

I wasn't referring to pointers. I was talking about your attitude
to older people. Everybody with a brain and mild familiarity with
C knows that pointer misuse is responsible for many errors. Just
like in assembly. The fact that you ignored my point shows that
you have a serious problem there.


The fact that you ignored the thread makes your point meaningless. My
serious problems are so far from catholic consumption that you would be
shocked; I can assure you that any type of pointer isn't one of them.
Furthermore, now that the Sox have plunged their knife through the daddies,
we no longer share baseball sympathies.

_obfuscate
swap(*int&, &int**)
* *

& &
* * *

/*wow, this code runs fast*/

I'm not convinced you're older than I. Furthermore, I'll just take a wild
stab in the dark and guess that you don't have the actuarial background I
do. So, Chuck, if you want to talk about older Americans, then what is the
number where the big part of mu x dx starts? MPJ

Nov 14 '05 #75
Merrill & Michele wrote:
>> MPJ
>> This follows K&R and might have advantages of which I am not
>> aware. A disadvantage is that it uses pointers, which are tough
>> if you want the prog to be read by people who got their PhDs
>> before the advent of the computer.
> ... snip ...

> CBFalconer"
> Bloody nonsense, and gross age discrimination.

... snip ...

http://home.comcast.net/~beckjensen/pointer.htm

I wear a lot of different hats and talk to all kinds of folks.
Pointers to them might be like the non-locality of space for you.

I wasn't referring to pointers.


But on the topic of pointers,
pointers are not an advanced topic in C.

If you take a look at the interface
to most of the standard library functions,
particularly the string and stdlib functions,
you'll see that pointers are the coin of the realm.

--
pete
Nov 14 '05 #76
>>> MPJ
>>> This follows K&R and might have advantages of which I am not
>>> aware. A disadvantage is that it uses pointers, which are tough
>>> if you want the prog to be read by people who got their PhDs
>>> before the advent of the computer.
>> ... snip ...
>
>> CBFalconer"
>> Bloody nonsense, and gross age discrimination.
>
... snip ...
>
> http://home.comcast.net/~beckjensen/pointer.htm
>
> I wear a lot of different hats and talk to all kinds of folks.
> Pointers to them might be like the non-locality of space for you.
I wasn't referring to pointers.
"pete"
But on the topic of pointers,
pointers are not an advanced topic in C.

But that they're allowed and sometimes necessary doesn't make code written
with them necessarily better. Again, compare Mr Pop's SWAP macro against
K&R's pointers. The former is very readable.
If you take a look at the interface
to most of the standard library functions,
particularly the string and stdlib functions,
you'll see that pointers are the coin of the realm.


I'm unaware of how to do file access without pointers. Chapter five K&R is
where I am now. Looks like I'm going to have to break my bills for the
appropriate coin. MPJ
Nov 14 '05 #77
In <41***********@mindspring.com> pete <pf*****@mindspring.com> writes:
But on the topic of pointers,
pointers are not an advanced topic in C.


It depends on your current standing. The OP has recently asked for help
with exercises 1-6 and 1-7 in K&R2.

And the guy who designed Java decided that pointers are too difficult for
most programmers, so he decided to hide them in the closet.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #78
Hi Dan,

Dan Pop wrote:
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
tmp must be provided from the outside -- this is a possible
source of error.


Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.


Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".

either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))


No point in complicating the interface of SWAP.


This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);

or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}


Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.


Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?

Be that as it may: Thanks for pointing out what is critical or
suboptimal so far!

or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)


If you make it a function, please spell its name in lower case.


Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().

Source code overheads, execution time overheads for no redeeming merits.
The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.


Er, right. I think you had a similar discussion with the OP about the
random numbers.
I rather like having the right types and being sure that everything
works as intended. So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.
You can of course be of different opinion.

As a general purpose solution, a macro is better than a function, because
it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:

#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)
Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.

Eliminating the tmp parameter requires a very handy GNU C extension,
typeof. It didn't make its way into C99 because the committee members
couldn't figure out how to write its specification.


Pity. They could have used the time it took to make a mess out of
lvalues to think about it... ;-)

int main(){


Nit: Make this
int main (void) {
for clarity; then everyone knows that you want the empty
parameter list.

Who could possibly believe otherwise? One doesn't need to be an expert in
standard C in order to realise that the original version specifies an
empty list.

The only valid objection to the original form is that C99 deprecates it.
Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.


Well, I would have liked to see some of the deprecated stuff outlawed.
At least we are rid of implicit int.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #79
[snip]
void SWAP (int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().
This follows K&R and might have advantages of which I am not aware. A
disadvantage is that it uses pointers, which are tough if you want the prog
to be read by people who got their PhDs before the advent of the computer.


Well, I won't get too much into this attitude or the fact that computers
have been around since before the 1950s.
The obvious issue with my solution is that pointers are not exactly
the solution for the early exercises. Apart from that, you can claim
overhead; see also Dan Pop's response and my answer to it.
I rather like to be sure that the right types are used.
[snip]
}

/*remove collisions*/

for(m = 0; m < FAMSIZ; m++){
if (buys_for[m] == m){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
if (n == m) continue;
if (buys_for[m] == n ) continue;
SWAP(m,n);
break;
}


If you replace (t > top_num) by (t > FAMSIZ - 1), then you
will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
your final output -- your continues as well as the break refer to
the outer for-loop.
Replace if by while:
while (buys_for[m] == m) {
to heal it. However, I would structure the code as above:
if (buys_for[m] == m) { /* collision */
/* Obtain random number which does not reproduce this
** or ensue another collision. */
do {
t = rand();
if (t > top_num) /* right range */
continue;
n = t % FAMSIZ;
} while ( (n == m) || (buys_for[m] == n) );

SWAP(m,n);
}

Are you contending that the code doesn't work for some defined FAMSIZ <
RAND_MAX?


Yes. Assume, for simplicity, RAND_MAX==31, FAMSIZ==20, a collision at
m==0 and the next value of rand() to be in the range [20,31], say 27:
m=0: buys_for[0]==0 (as per assumption)
t=27
t>19 (which also is top_num)
=>continue=>m++
m=1: ---we no longer consider the problem for m==0---

The same holds in the general setting for all rand() values between
top_num and RAND_MAX.

}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');


Nits:
- "rotate" the table; otherwise it is not handy for large FAMSIZE
- insert spacing or separators of some sort, otherwise, at
FAMSIZE > 100, you get unreadable numbers.
For example:
/*out to console*/
putchar('\n');
for (i = 0; i < FAMSIZ; i++)
printf ("%3d\t%3d\n", i, buys_for[i]);

return 0;
}


As an aside: You stressed the importance of optimally treating the
random numbers in your discussion with Dan Pop.
Then, I would go one step further in your place:
Put initialization of the PRNG and calls to it into functions of their
own, for example:

static int my_RANDMAX = RANDMAX, my_modulus = 0;

void init_myrand (int modulus)
{
srand( (unsigned) time(NULL) );
my_modulus = modulus;
my_RANDMAX = RANDMAX - (RANDMAX % modulus) - 1;
}

int myrand (void)
{
int tmp;
do {
tmp = rand();
} while (tmp > my_RANDMAX);

return t%my_modulus;
}

....

init_myrand(FAMSIZE);
....
n = myrand();

or some more flexible solution. This allows you to play around with
different PRNGs and different ways to "fetch" the return value.
Example for the latter: In old implementations of rand(), the higher
bits are more random than the lower bits, so you could just get the
highest n bits and adjust my_RANDMAX correspondingly...

Now I'm truly confused. But I have to post and run. MPJ


Reconsider it, ask "good" questions.
Cheers,
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #80

"Michael Mair" >
Dan Pop wrote:
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)

tmp must be provided from the outside -- this is a possible
source of error.

I can't really keep Dan and Michael apart when the screen is full of symbols
I don't understand. I would like to reiterate my question to Mr Mair: do
you think this code provides a random derangement given FAMSIZ between 2 and
RAND_MAX less one?
Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.


Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".

either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))


No point in complicating the interface of SWAP.


This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);

or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}


Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.


Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?

Be that as it may: Thanks for pointing out what is critical or
suboptimal so far!

or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)


If you make it a function, please spell its name in lower case.


Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().

A fella sent me a way to write to files, so I'm going to try to do this prog
with pointers. MPJ


Source code overheads, execution time overheads for no redeeming merits.
The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.


Er, right. I think you had a similar discussion with the OP about the
random numbers.
I rather like having the right types and being sure that everything
works as intended. So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.
You can of course be of different opinion.

As a general purpose solution, a macro is better than a function, because it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:
#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)


Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.

Eliminating the tmp parameter requires a very handy GNU C extension,
typeof. It didn't make its way into C99 because the committee members
couldn't figure out how to write its specification.


Pity. They could have used the time it took to make a mess out of
lvalues to think about it... ;-)

int main(){

Nit: Make this
int main (void) {
for clarity; then everyone knows that you want the empty
parameter list.

Who could possibly believe otherwise? One doesn't need to be an expert in standard C in order to realise that the original version specifies an
empty list.

The only valid objection to the original form is that C99 deprecates it.
Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.


Well, I would have liked to see some of the deprecated stuff outlawed.
At least we are rid of implicit int.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".

------------------------------
4 dead in Ohio --MPJ
Nov 14 '05 #81
That is RAND_MAX less FAMSIZ and maybe even less one. The cautious logician
adds that FAMSIZ be 32000 or less. MPJ
"Merrill & Michele" >
"Michael Mair" >
Dan Pop wrote:
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:
>>#define SWAP(m,n) \
>>(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
>
>tmp must be provided from the outside -- this is a possible
>source of error.
I can't really keep Dan and Michael apart when the screen is full of symbols I don't understand. I would like to reiterate my question to Mr Mair: do
you think this code provides a random derangement given FAMSIZ between 2 and RAND_MAX less one?
Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.
Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".

>either pass tmp, too:
> #define SWAP(m,n,tmp) \
> ((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))

No point in complicating the interface of SWAP.


This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);

>or provide it here:
> #define SWAP(m,n) \
> {int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}

Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.


Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?

Be that as it may: Thanks for pointing out what is critical or
suboptimal so far!

>or use a function. The latter excludes also potential problems
>with the type:
> void SWAP (int *a, int *b)

If you make it a function, please spell its name in lower case.


Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.
> {
> int tmp = *a;
> *a = *b;
> *b = tmp;
> }
>and pass &buys_for[m], &buys_for[n] to SWAP().
A fella sent me a way to write to files, so I'm going to try to do this

prog with pointers. MPJ
Source code overheads, execution time overheads for no redeeming merits. The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.
Er, right. I think you had a similar discussion with the OP about the
random numbers.
I rather like having the right types and being sure that everything
works as intended. So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.
You can of course be of different opinion.

As a general purpose solution, a macro is better than a function, because it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:
#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)


Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.

Eliminating the tmp parameter requires a very handy GNU C extension,
typeof. It didn't make its way into C99 because the committee members
couldn't figure out how to write its specification.


Pity. They could have used the time it took to make a mess out of
lvalues to think about it... ;-)

>>int main(){
>
>Nit: Make this
> int main (void) {
>for clarity; then everyone knows that you want the empty
>parameter list.
Who could possibly believe otherwise? One doesn't need to be an expert in
standard C in order to realise that the original version specifies an
empty list.

The only valid objection to the original form is that C99 deprecates

it. Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.


Well, I would have liked to see some of the deprecated stuff outlawed.
At least we are rid of implicit int.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".

------------------------------
4 dead in Ohio --MPJ

Nov 14 '05 #82
[snip]
void SWAP (int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().
This follows K&R and might have advantages of which I am not aware. A
disadvantage is that it uses pointers, which are tough if you want the prog
to be read by people who got their PhDs before the advent of the

computer.
"Michael Mair" :
Well, I won't get too much into this attitude or the fact that computers
have been around since before the 1950s.
The obvious issue with my solution is that pointers are not exactly
the solution for the early exercises. Apart from that, you can claim
overhead; see also Dan Pop's response and my answer to it.
I rather like to be sure that the right types are used.
[snip]
}

/*remove collisions*/

for(m = 0; m < FAMSIZ; m++){
if (buys_for[m] == m){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
if (n == m) continue;
if (buys_for[m] == n ) continue;
SWAP(m,n);
break;
}

If you replace (t > top_num) by (t > FAMSIZ - 1), then you
will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
your final output -- your continues as well as the break refer to
the outer for-loop.
Replace if by while:
while (buys_for[m] == m) {
to heal it. However, I would structure the code as above:
if (buys_for[m] == m) { /* collision */
/* Obtain random number which does not reproduce this
** or ensue another collision. */
do {
t = rand();
if (t > top_num) /* right range */
continue;
n = t % FAMSIZ;
} while ( (n == m) || (buys_for[m] == n) );

SWAP(m,n);
}

Are you contending that the code doesn't work for some defined FAMSIZ <
RAND_MAX?


Yes. Assume, for simplicity, RAND_MAX==31, FAMSIZ==20, a collision at
m==0 and the next value of rand() to be in the range [20,31], say 27:
m=0: buys_for[0]==0 (as per assumption)
t=27
t>19 (which also is top_num)
=>continue=>m++
m=1: ---we no longer consider the problem for m==0---

The same holds in the general setting for all rand() values between
top_num and RAND_MAX.

}

/*out to console*/
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", i);
putchar('\n');
for(i = 0; i < FAMSIZ; i++) printf ("%3d", buys_for[i]);
putchar('\n');

Nits:
- "rotate" the table; otherwise it is not handy for large FAMSIZE
- insert spacing or separators of some sort, otherwise, at
FAMSIZE > 100, you get unreadable numbers.
For example:
/*out to console*/
putchar('\n');
for (i = 0; i < FAMSIZ; i++)
printf ("%3d\t%3d\n", i, buys_for[i]);
return 0;
}

As an aside: You stressed the importance of optimally treating the
random numbers in your discussion with Dan Pop.
Then, I would go one step further in your place:
Put initialization of the PRNG and calls to it into functions of their
own, for example:

static int my_RANDMAX = RANDMAX, my_modulus = 0;

void init_myrand (int modulus)
{
srand( (unsigned) time(NULL) );
my_modulus = modulus;
my_RANDMAX = RANDMAX - (RANDMAX % modulus) - 1;
}

int myrand (void)
{
int tmp;
do {
tmp = rand();
} while (tmp > my_RANDMAX);

return t%my_modulus;
}

....

init_myrand(FAMSIZE);
....
n = myrand();

or some more flexible solution. This allows you to play around with
different PRNGs and different ways to "fetch" the return value.
Example for the latter: In old implementations of rand(), the higher
bits are more random than the lower bits, so you could just get the
highest n bits and adjust my_RANDMAX correspondingly...

Now I'm truly confused. But I have to post and run.

Reconsider it, ask "good" questions.


Dude, you snipped my code that you said wasn't working. I can, with my
extraordinary dexterity, come up with said code again. More important is
that I get food in my belly. It's a long day for a certain type of
mathematician. MPJ
Nov 14 '05 #83
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:
Hi Dan,

Dan Pop wrote:
In <2u*************@uni-berlin.de> Michael Mair <Mi**********@invalid.invalid> writes:
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)

tmp must be provided from the outside -- this is a possible
source of error.
Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.


Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".


Using a macro without understanding its needs and limitations is just
one of the many stupid things fools do. No point in trying to write code
that even a fool could maintain: the fool will always defeat your
attempts at being foolproof.
either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))


No point in complicating the interface of SWAP.


This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))


What do you need the "protecting" parentheses for?
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);
Which is defeating the purpose of SWAP: to simplify the code using it,
making it easier to read and understand. For no redeeming advantages.
It should have been obvious to anyone that it was not meant to be a
general purpose swapping macro, but one tailored to the needs of the
application.
or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}


Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.


Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?


The former can be considered a bug, while the latter is merely a design
flaw. You could argue that your original version was good enough for this
particular application, but you seemed to have a more ambitious goal in
mind, hence my objections.
or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)


If you make it a function, please spell its name in lower case.


Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.


Wrong! You're merely obfuscating the things. Macro names are spelled in
upper case to warn the reader that something that looks like a function
call doesn't have the semantics of a function call. If you start writing
genuine function names in upper case, this very important message is lost.

Inline or not, a function call is not a macro invocation.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().

Source code overheads, execution time overheads for no redeeming merits.
The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.


Er, right. I think you had a similar discussion with the OP about the
random numbers.


Exactly. The *simplest* solution that is entirely appropriate to the
problem should be always preferred. I wrote the program to illustrate
the description of an algorithm, not to teach anyone about how to write
Monte Carlo simulations or the "best" swapping macro.
I rather like having the right types and being sure that everything
works as intended.
It would be nice if C provided such certainties...
So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.
Inline functions are not an option if you have to write portable C code
today.
You can of course be of different opinion.
The above is not a matter of opinion, it is a matter of fact.
As a general purpose solution, a macro is better than a function, because
it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:

#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)


Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.


If it's non-general, there is no point in keeping it any more complicated
than *strictly* needed. In my example above, it is the generality that
justifies the complication in the interface. I wouldn't use such a macro
in any program where I need to swap only variables of one type.
The only valid objection to the original form is that C99 deprecates it.
Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.


Well, I would have liked to see some of the deprecated stuff outlawed.


Me too, but they decided that 10 years was not time enough for people to
clean up the codes they maintain.
At least we are rid of implicit int.
Which was NOT deprecated by C89, BTW.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".


True, but recursively calling a main defined with no parameters is not
something I consider sane. The other case may be open to discussion, but
the C++ people decided that it is sa[nf]er to outlaw it.

Because there is no visible call to main in the whole program, I don't
bother writing a prototype definition when there are no parameters. All
other parameterless functions do get their prototype definitions, because
they will be called from inside the program, with a prototype declaration
in scope. I wonder if the standard forcing me to change this habit will
be drafted during my lifetime :-)

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #84
>MPJ
Dan Pop
Michael Mair#define SWAP(m,n) \
>(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)

tmp must be provided from the outside -- this is a possible
source of error.

Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.


Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".


Using a macro without understanding its needs and limitations is just
one of the many stupid things fools do. No point in trying to write code
that even a fool could maintain: the fool will always defeat your
attempts at being foolproof.
either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))

No point in complicating the interface of SWAP.


This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))


What do you need the "protecting" parentheses for?
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);


Which is defeating the purpose of SWAP: to simplify the code using it,
making it easier to read and understand. For no redeeming advantages.
It should have been obvious to anyone that it was not meant to be a
general purpose swapping macro, but one tailored to the needs of the
application.
or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}

Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.


Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?


The former can be considered a bug, while the latter is merely a design
flaw. You could argue that your original version was good enough for this
particular application, but you seemed to have a more ambitious goal in
mind, hence my objections.
or use a function. The latter excludes also potential problems
with the type:
void SWAP (int *a, int *b)

If you make it a function, please spell its name in lower case.


Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.


Wrong! You're merely obfuscating the things. Macro names are spelled in
upper case to warn the reader that something that looks like a function
call doesn't have the semantics of a function call. If you start writing
genuine function names in upper case, this very important message is lost.

Inline or not, a function call is not a macro invocation.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().
Source code overheads, execution time overheads for no redeeming merits. The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.


Er, right. I think you had a similar discussion with the OP about the
random numbers.


Exactly. The *simplest* solution that is entirely appropriate to the
problem should be always preferred. I wrote the program to illustrate
the description of an algorithm, not to teach anyone about how to write
Monte Carlo simulations or the "best" swapping macro.
I rather like having the right types and being sure that everything
works as intended.


It would be nice if C provided such certainties...
So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.


Inline functions are not an option if you have to write portable C code
today.
You can of course be of different opinion.


The above is not a matter of opinion, it is a matter of fact.
As a general purpose solution, a macro is better than a function, because it can be written in a polymorphic way (to work for any C type) at the
expense of requiring the caller to pass the temp variable as an argument:
#define SWAP(a, b, tmp) (tmp = a, a = b, b = tmp)


Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.


If it's non-general, there is no point in keeping it any more complicated
than *strictly* needed. In my example above, it is the generality that
justifies the complication in the interface. I wouldn't use such a macro
in any program where I need to swap only variables of one type.
The only valid objection to the original form is that C99 deprecates it. Still a long way (at least 10 years) until a C standard might actually
disallow it (no feature deprecated by C89 was removed by C99, BTW),
an even longer way until that future standard will actually get
implemented, if we're to judge by the number of conforming C99
implementations in use today.


Well, I would have liked to see some of the deprecated stuff outlawed.


Me too, but they decided that 10 years was not time enough for people to
clean up the codes they maintain.
At least we are rid of implicit int.


Which was NOT deprecated by C89, BTW.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".


True, but recursively calling a main defined with no parameters is not
something I consider sane. The other case may be open to discussion, but
the C++ people decided that it is sa[nf]er to outlaw it.

Because there is no visible call to main in the whole program, I don't
bother writing a prototype definition when there are no parameters. All
other parameterless functions do get their prototype definitions, because
they will be called from inside the program, with a prototype declaration
in scope. I wonder if the standard forcing me to change this habit will
be drafted during my lifetime :-)


Mr Pop:

while (1)
if x and not y; continiue;
while(1)
if y and not x; conitnue;
break:
break;

Might I trouble you to describe the behavior of this code in terms of y,x
and every way you can think to associate them logically? MPJ
Nov 14 '05 #85
Hiho,

as you seem to have trouble to read the posts, I heavily snipped
for you:

Merrill & Michele wrote:
[snip]
Your flawed code:
>/*remove collisions*/
>
>for(m = 0; m < FAMSIZ; m++){
> if (buys_for[m] == m){
> t = rand();
> if (t > top_num) continue;
> n = t % FAMSIZ;
> if (n == m) continue;
> if (buys_for[m] == n ) continue;
> SWAP(m,n);
> break;
> }

If you replace (t > top_num) by (t > FAMSIZ - 1), then you
will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
your final output -- your continues as well as the break refer to
the outer for-loop.
Replace if by while:
while (buys_for[m] == m) {
to heal it. However, I would structure the code as above:
if (buys_for[m] == m) { /* collision */
/* Obtain random number which does not reproduce this
** or ensue another collision. */
do {
t = rand();
if (t > top_num) /* right range */
continue;
n = t % FAMSIZ;
} while ( (n == m) || (buys_for[m] == n) );

SWAP(m,n);
}
Are you contending that the code doesn't work for some defined FAMSIZ <
RAND_MAX?
Yes. Assume, for simplicity, RAND_MAX==31, FAMSIZ==20, a collision at
m==0 and the next value of rand() to be in the range [20,31], say 27:
m=0: buys_for[0]==0 (as per assumption)
t=27
t>19 (which also is top_num)
=>continue=>m++
m=1: ---we no longer consider the problem for m==0---

The same holds in the general setting for all rand() values between
top_num and RAND_MAX.

[snip2: Explanation of possible improvements etc.] Dude, you snipped my code that you said wasn't working. I can, with my
extraordinary dexterity, come up with said code again. More important is
that I get food in my belly. It's a long day for a certain type of
mathematician. MPJ


I am not your dude.
And I did not snip it. The "reconsider" (which I snipped for you)
referred to the snip2.
If you do not understand why your code does not work always as intended,
replace top_num as suggested and do not use FAMSIZ values which are
divisors of RAND_MAX+1.
Cheers
Michael
--
E-Mail: Mine is a gmx dot de address.

Nov 14 '05 #86
In <a5********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
Mr Pop:

while (1)
if x and not y; continiue;
while(1)
if y and not x; conitnue;
break:
break;

Might I trouble you to describe the behavior of this code in terms of y,x
and every way you can think to associate them logically? MPJ


Are you sure you had to include a 160-lines post in order to append this
*completely unrelated* question?

I'm not sure I can interpret your pseudocode the same way as you did.
Since I'm a lousy mind reader, please implement it in C and repost it.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #87
Keith Thompson wrote:

[Snip]

To summarize the summary of the summary, programming is hard work.


That makes a nice quote. Should be nominated for the Quote of the Month
award .. :)

Abhinav
Nov 14 '05 #88

"> >Mr Pop:

while (1)
if x and not y; continiue;
while(1)
if y and not x; conitnue;
break:
break;

Might I trouble you to describe the behavior of this code in terms of y,x
and every way you can think to associate them logically? MPJ


Are you sure you had to include a 160-lines post in order to append this
*completely unrelated* question?

I'm not sure I can interpret your pseudocode the same way as you did.
Since I'm a lousy mind reader, please implement it in C and repost it.

Dan


I can't pinpoint where it is that Mr. Mair says my prog goes overboard. My
question boils down to this: in nested loops, do the 'continue's know to go
back to the program control at the level where it is nested, or do I need to
use variables to get the scope I want? Election's over, so my
posting-sloppily-30-seconds days are to an end for a while. MPJ
Nov 14 '05 #89
> Hiho,

as you seem to have trouble to read the posts, I heavily snipped
for you:

Merrill & Michele wrote:
[snip]
Your flawed code:
>>/*remove collisions*/
>>
>>for(m = 0; m < FAMSIZ; m++){
>> if (buys_for[m] == m){
>> t = rand();
>> if (t > top_num) continue;
>> n = t % FAMSIZ;
>> if (n == m) continue;
>> if (buys_for[m] == n ) continue;
>> SWAP(m,n);
>> break;
>> }
>
>If you replace (t > top_num) by (t > FAMSIZ - 1), then you
>will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
>your final output -- your continues as well as the break refer to
>the outer for-loop.
>Replace if by while:
> while (buys_for[m] == m) {
>to heal it. However, I would structure the code as above:
> if (buys_for[m] == m) { /* collision */
> /* Obtain random number which does not reproduce this
> ** or ensue another collision. */
> do {
> t = rand();
> if (t > top_num) /* right range */
> continue;
> n = t % FAMSIZ;
> } while ( (n == m) || (buys_for[m] == n) );
>
> SWAP(m,n);
> }
Are you contending that the code doesn't work for some defined FAMSIZ <
RAND_MAX?

Yes. Assume, for simplicity, RAND_MAX==31, FAMSIZ==20, a collision at
m==0 and the next value of rand() to be in the range [20,31], say 27:
m=0: buys_for[0]==0 (as per assumption)
t=27
t>19 (which also is top_num)
=>continue=>m++
m=1: ---we no longer consider the problem for m==0---

The same holds in the general setting for all rand() values between
top_num and RAND_MAX. [snip2: Explanation of possible improvements etc.]
Dude, you snipped my code that you said wasn't working. I can, with my
extraordinary dexterity, come up with said code again. More important

is that I get food in my belly. It's a long day for a certain type of
mathematician. MPJ


I am not your dude.
And I did not snip it. The "reconsider" (which I snipped for you)
referred to the snip2.
If you do not understand why your code does not work always as intended,
replace top_num as suggested and do not use FAMSIZ values which are
divisors of RAND_MAX+1.

Relax, Herr Gott! I'll work on that today, along with a version using the
pointers. Thanks for your help. MPJ
Nov 14 '05 #90
Flawed code:
>>>>for(m = 0; m < FAMSIZ; m++){
>>>> if (buys_for[m] == m){
>>>> t = rand();
>>>> if (t > top_num) continue;
>>>> n = t % FAMSIZ;
>>>> if (n == m) continue;
>>>> if (buys_for[m] == n ) continue;
>>>> SWAP(m,n);
>>>> break;
So RAND_MAX is 31. FAMSIZ is 20. m=0 and has a collision. This implies
buysfor[0]==0. t is 27 and greater than topnum. for is iterated. gotcha.
> }
>>>Michael Mair:
>>>If you replace (t > top_num) by (t > FAMSIZ - 1), then you
>>>will for FAMSIZ at about sqrt(RANDMAX) probably find collisions in
>>>your final output -- your continues as well as the break refer to
>>>the outer for-loop.
>>>Replace if by while:
>>> while (buys_for[m] == m) {
>>>to heal it. However, I would structure the code as above:
>>> if (buys_for[m] == m) { /* collision */
>>> /* Obtain random number which does not reproduce this
>>> ** or ensue another collision. */
>>> do {
>>> t = rand();
>>> if (t > top_num) /* right range */
>>> continue;
>>> n = t % FAMSIZ;
>>> } while ( (n == m) || (buys_for[m] == n) );
>>>
>>> SWAP(m,n);
>>> }
>>
>>
>>Are you contending that the code doesn't work for some defined FAMSIZ <>>RAND_MAX?
>
>Yes. Assume, for simplicity, RAND_MAX==31, FAMSIZ==20, a collision at
>m==0 and the next value of rand() to be in the range [20,31], say 27:
>m=0: buys_for[0]==0 (as per assumption)
>t=27
>t>19 (which also is top_num)
>=>continue=>m++
>m=1: ---we no longer consider the problem for m==0---
>
>The same holds in the general setting for all rand() values between
>top_num and RAND_MAX.

snip

Indeed, I could not locate the program that ultimately I thought was right,
so I'm starting from scratch again. If you comment to keep FAMSIZ between 2
and 2000 inclusive, I believe this eliminates one of the problems you
mentioned.

The other thing I am not getting is as I attempt to do the swap as pointers.
Is this really a good idea when that which is to be swapped are entries of
the same array? Doesn't it, for precisely this problem, basically double
the demand on main memory? What would *(buysfor + i ) reference? MPJ
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define FAMSIZ 15 /* between 2 and 2,000 */
/* don't think I don't pay attention */

int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int mango, int coconut){

int noscope;
/* all pointers as ints */
noscope=mango;
MPJ

Nov 14 '05 #91
In <P6********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
The other thing I am not getting is as I attempt to do the swap as pointers.


Wait until you read the relevant part of K&R2.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #92

"Dan Pop" <Da*****@cern.ch> wrote in message
news:cm**********@sunnews.cern.ch...
In <P6********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
The other thing I am not getting is as I attempt to do the swap as
pointers.
Wait until you read the relevant part of K&R2.

Dan


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

#define FAMSIZ 15 /* between 2 and 2,000 */
/* don't think I don't pay attention */

int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int *px, int *py){

int noscope;
/* all pointers as ints */
noscope = *px;
*px = *py;
*py = noscope;
}

}


/* initialize and permute */
for (i = 0; i < FAMSIZ; i++) buysfor[i] = i;

while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);


/* http://home.comcast.net/~beckjensen/range1.htm */

doesn't compile
This is a Moses Malone post: I'll get my own rebound. MPJ


Nov 14 '05 #93
In <35********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int *px, int *py){

int noscope;

doesn't compile


Are you surprised?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #94
Dan Pop wrote:
In <35********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:

int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int *px, int *py){

int noscope;

doesn't compile


Are you surprised?


I hope not. The only question is whether these inane code snippets
are offending or just a sort of white noise...

@OP: Even if you are not posting a question: Give us meaningful,
compilable code or code snippets which can be used in an actual
program and don't use c.l.c as repository for underdone meta-ideas,
please.
Thanks.

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #95

"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:2v*************@uni-berlin.de...
Dan Pop wrote:
In <35********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int *px, int *py){

int noscope;

doesn't compile


Are you surprised?


I hope not. The only question is whether these inane code snippets
are offending or just a sort of white noise...

@OP: Even if you are not posting a question: Give us meaningful,
compilable code or code snippets which can be used in an actual
program and don't use c.l.c as repository for underdone meta-ideas,
please.
Thanks.

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

Nov 14 '05 #96

"Michael Mair" <Mi**********@invalid.invalid> wrote in message
news:2v*************@uni-berlin.de...
Dan Pop wrote:
In <35********************@comcast.com> "Merrill & Michele" <be********@comcast.net> writes:
int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];

void swap(int *px, int *py){

int noscope;

doesn't compile


Are you surprised?


I hope not. The only question is whether these inane code snippets
are offending or just a sort of white noise...

@OP: Even if you are not posting a question: Give us meaningful,
compilable code or code snippets which can be used in an actual
program and don't use c.l.c as repository for underdone meta-ideas,
please.
Thanks.

-Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.


Doing my best Michael. I don't know how long it took you to get through
K&R, but I'm struggling with it.

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

#define FAMSIZ 15 /* between 2 and 2,000 */
/* don't think I don't pay attention */

int main(void){

int i;
int m,n,t,topnum;
int buysfor[FAMSIZ];
void swap(int *px, int *py);


/* initialize and permute */
for (i = 0; i < FAMSIZ; i++) buysfor[i] = i;

m = 0;
while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);
++ m;
}
/*out to console*/
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",i);
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor[i]);
putchar('\n');
return 0;
}

void swap(int *px, int *py){

int noscope;
/* all pointers as ints */
noscope = *px;
*px = *py;
*py = noscope;
}

/*http://home.comcast.net/~beckjensen/range1.htm*/

Gotta run. MPJ


Nov 14 '05 #97
MPJ:
"Dan Pop" writes:
"Merrill & Michele
[undeclared function]void swap(int *px, int *py){
doesn't compile
Are you surprised?


No, I just couldn't figure out what the errors that the compiler was spewing
out meant. I forgot to declare the function. That I posted what I had was
a filibuster of sorts with regards to my newsreader. I'm going to get this
code right and stylistically acceptable. I really do not appreciate
disparagement when I'm working my ass off (elsethread directed). Last
night, I asked my uncle why he didn't use K&R to teach. I thought his
answer was interesting, but I wouldn't want to trouble this forum with my 2
decades of meta-ideas. MPJ
Nov 14 '05 #98

/*derangement2 contributors: Eric Sosman, Dan Pop, Michael Mair*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FAMSIZ 20 /* between 2 and 2,000 */

int main(void){

int i, m, n, t, topnum, buysfor[FAMSIZ];
void swap(int *px, int *py);

/* get vanilla rand started well */
srand(time(NULL));
topnum = RAND_MAX - (RAND_MAX % FAMSIZ) - 1;
for (i = 0; i < 9; ++ i) t = rand();

/* initialize and permute */
for (i = 0; i < FAMSIZ; ++ i) buysfor[i] = i;
m = 0;
while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);
++ m;
}

/*out to console*/
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",i);
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor[i]);
putchar('\n');

/* remove collisions */
for (m = 0; m < FAMSIZ; ++ m){
while (buysfor[m] == m){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
if ((n == m) || (buysfor[m] == n)) continue;
swap (&buysfor[m] , &buysfor[n]);
}
}

/* to console*/

for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor[i]);
putchar('\n');

return 0;
}

void swap(int *px, int *py){
int noscope;
noscope = *px;
*px = *py;
*py = noscope;
}

I think I finally got it. I couldn't get my head around the do-while
control loops. MPJ
Nov 14 '05 #99

"Merrill & Michele" <be********@comcast.net> дÈëÏûÏ¢ÐÂÎÅ
:Tr********************@comcast.com...

/*derangement2 contributors: Eric Sosman, Dan Pop, Michael Mair*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FAMSIZ 20 /* between 2 and 2,000 */

int main(void){

int i, m, n, t, topnum, buysfor[FAMSIZ];
void swap(int *px, int *py);

/* get vanilla rand started well */
srand(time(NULL));
topnum = RAND_MAX - (RAND_MAX % FAMSIZ) - 1;
for (i = 0; i < 9; ++ i) t = rand();

/* initialize and permute */
for (i = 0; i < FAMSIZ; ++ i) buysfor[i] = i;
m = 0;
while (m < FAMSIZ){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
swap (&buysfor[m] , &buysfor[n]);
++ m;
}

/*out to console*/
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",i);
putchar('\n');
for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor[i]);
putchar('\n');

/* remove collisions */
for (m = 0; m < FAMSIZ; ++ m){
while (buysfor[m] == m){
t = rand();
if (t > topnum) continue;
n = t % FAMSIZ;
if ((n == m) || (buysfor[m] == n)) continue;
swap (&buysfor[m] , &buysfor[n]);
}
}

/* to console*/

for (i = 0;i < FAMSIZ; i ++) printf("%3d",buysfor[i]);
putchar('\n');

return 0;
}

void swap(int *px, int *py){
int noscope;
noscope = *px;
*px = *py;
*py = noscope;
}

I think I finally got it. I couldn't get my head around the do-while
control loops. MPJ

Nov 14 '05 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.