derangement: code review request

M

Merrill & Michele

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

/*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);
putchar('\n');

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

Dan Pop

In said:
Dan, all fifteen bits count. If rand() stinks, then don't make it worse.


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
 
M

Merrill & Michele

2004-compliant. I have two macros. Mr. Pop's RND was not even close
to
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
 
R

Richard Bos

Tim Rentsch said:
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.
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;


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
 
D

Dan Pop

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

Merrill & Michele

Either explain WHY your problem requires a high quality sequence of
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
 
M

Merrill & Michele

/*derangement.c contributors: Eric Sosman, Dan Pop et ali*/
#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;

/*main control*/

/*permute randomly*/
for(m = 0; m < FAMSIZ; m++){
while(1){
t = rand();
if (t > top_num) continue;
n = t % FAMSIZ;
SWAP(m,n);
break;
}
}

/*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;
}
}

/*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');

return 0;
}
 
M

Michael Mair

Merrill said:
/*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().
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;

/*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.
}

/*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);
}
}

/*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...


Cheers,
Michael
 
D

Dan Pop

In said:
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."

How is this verbiage supposed to justify the need for a high quality
random number generator *for your specific problem*? Are you unable to
undestand my extremely simple question?

Dan
 
T

Tim Rentsch

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.

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;

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

Alan Balmer

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

Dan Pop

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

Merrill & Michele

Michael Mair" wrote:
Merrill said:
/*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;

/*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);
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
 
C

CBFalconer

Merrill said:
.... 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.
 
M

Merrill & Michele

MPJ
... 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
 
C

CBFalconer

Merrill said:
.... 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.
 
M

Merrill & Michele

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
 
P

pete

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

Merrill & Michele

"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
 

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

Staff online

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top