derangement: code review request

D

Dan Pop

In said:
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
 
M

Michael Mair

Hi Dan,

Dan said:
In said:
#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!

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... ;-)

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
 
M

Michael Mair

[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);
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);

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
 
M

Merrill & Michele

"Michael Mair" >
Dan said:
#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!

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
 
M

Merrill & Michele

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 said:
#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
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.



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.



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

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".
 
M

Merrill & Michele

[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);
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);


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
 
D

Dan Pop

In said:
Hi Dan,

Dan said:
In said:
#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.
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.
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.
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
 
M

Merrill & Michele

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.
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.
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.
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
 
M

Michael Mair

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
 
D

Dan Pop

In said:
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
 
A

Abhinav

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
 
M

Merrill & Michele

"> >Mr Pop:
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
 
M

Merrill & Michele

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
 
M

Merrill & Michele

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
 
M

Merrill & Michele

Dan Pop said:
In <[email protected]> "Merrill & Michele" 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;

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
 
M

Michael Mair

Dan said:
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
 
M

Merrill & Michele

Michael Mair said:
Dan said:
In <[email protected]> "Merrill & Michele"
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
 
M

Merrill & Michele

Michael Mair said:
Dan said:
In <[email protected]> "Merrill & Michele"
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

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;

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);
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
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top