coin toss problem

O

osmium

Ben said:
My initial problem was that I had read in a maths book that the average
no. of 6 heads in a row in a sequence of 200 tosses was at least one...
my program kept providing 0.77
I have since realised that they must have meant "at least 6"...

AFAICT they really meant exactly. I get about 1.5 "hits" under the problem
as I understand it.
I only started learning programming a few months ago- so I'm not sure
what the problem is with global variables? (And what's an alternative?)

Move the variables above main so they are included in main, or to whoever
they belong to. The idea is to pass information by passing paramters.
The #defines seem to do what I want - enums might be more appropriate,
but I haven't yet learnt what they are :)

That's a prefectly good reason.
The sentinel seemed easy enough to use - what potential problems are
there with using them? Why are they only a last resort?

Not many problems, they just make you look like a student. Instructors
often teach the use of sentinels to avoid teaching how to handle end of
file. The thought is that sentinels are easier to understand, and I agree.
But real programmers use end of file.

Pay attention to the definition of in_a_row. Does it mean *exactly* n in
a
row? The code says no. To determine that your code would have to look at
the next character - the one that breaks the sequence- , and it doesn't
do
that. To me, exactly is the most sensible thing to compute. For
example,
if in_a_row is 3 what does the following sequence of heads get counted
as:
001111111100 ?

It does compute 'exactly x in a row' ... which is what I intended...
(it looks at the character that breaks the sequence when 'i' is
incremented - which breaks the while loop)

while(A==H)
{
i++;
row_h++;
}

if(row_h==in_a_row)
count++;

row_h=0;


I goofed and missed that. It is really hard to study code with no
indentation. And no comments. And no paycheck for all the effort. That (the
general area) was my leading candidate for the trouble you were having. So
you are back at square zero WRT my help.
My uni textbook says "If you need your program to be portable, and
require the values to be uncorelated even when compiled with the
original rand and srand functions, you should extract the desired value
from high-order bits rather than low-order ones..."

But they are talking really small numbers, like six (sides on a die). Not
half the numbers.
I'm a newbie ... by habbit I tend to stick in as many extra parens as
possible ;)

Better too many than too few. Much better.

If you want to indent and repost, I will take a fresh look at what you have.
I was bothered mostly by not knowing what it was that it was supposed to
compute.

Here's another cut at it. It is wordier than most C programs, in the hopes
of retaining some clarity. The array, as I suspect you already knew, was
just a crutch. There might be some ideas you can use. Or then it could be
all wrong. Probability and statistics are real bears. I tried to derive
the answer you quote from your book and couldn't get it.
------
#include <stdio.h>
#include <stdlib.h> // abort
#include <time.h> // time

// count the number of times that there are exactly w heads in a row
int count(int w)
{
if(w<2)
{
printf("Function count is not intended to work\nfor sequences "
"of lengths less than 2.\n\n"
"Aborting\n");
getchar();
abort();
}
static int mid_pt = RAND_MAX / 2.0;
int on = 0; // state. on means "in count mode"
int ct = 0; // number of occurances of heads
int bit = 0; // the coin. 1 is a head
int last = 0; // results for preceding flip
int k = 0; // number of heads in *this* sequence
int i;
for(i=1; i<128; i++)
{
bit = rand();
bit = (bit<mid_pt) ? 0 : 1;
if(bit && !last) // transition to heads
{
k = 1;
on = 1;
}
else if(!bit && last) // transition to tails
{
k++; // count this flip
if(k == w)
ct++; // count the winners
k = 0;
on = 0; // back to passive mode
}
else if(on && bit) // another head
k++;
else
/* do nothing */;
last = bit;
}
return ct;
} // end function
//====================
int main()
{
srand(time(NULL));
int sum = 0;
int n = 6; /* count the number of times there are *exactly* n heads in a
row.*/
int i;
for(i=1; i<1000; i++)
sum += count(n);
printf("Mean number of times there were exactly %d heads: %g",
n, (sum/1000.0) );
getchar();
}
 
K

Keith Thompson

osmium said:
Not many problems, they just make you look like a student. Instructors
often teach the use of sentinels to avoid teaching how to handle end of
file. The thought is that sentinels are easier to understand, and I agree.
But real programmers use end of file.

Using a sentinel when reading a file, rather than checking for EOF, is
rarely a good idea. But sentinels can be useful in other contexts.

Consider a function that takes a variable number of pointer arguments.
Using a null pointer as a sentinel is a reasonable approach.
 
B

Ben C

const int a = 2;
*(int*)(&a) = 3;

would cause UB.

Why? Is this something to do with "type-punning"-- we're taking the
address of an object of one type (const int) and making a pointer to
another type (int) point to it, then dereferencing. This is always UB.
It allows for machines to use different sizes and shapes of pointers to
different types if they want to.

But

const int a = 2;
(int) a = 3;

is not UB, right?
Touché!

"const int a = 2;" is a compile time constant, where as "const int b =
f();" isn't.

I guess the clarity of the distinction depends on one's view of the world.

IIRC, in "The Design and Evolution of C++" Stroustrup justifies this as
part of a general crusade against the C preprocessor (which he aptly
describes as a "bulldozer").

In C# you get two different keywords-- "readonly" and "const" instead of
using "const" to mean both.
 
O

Old Wolf

Richard said:
Ian Collins said:

If you're using a C99 compiler, well, fair enough. If you're using a
compiler adhering to an older standard, like 99.90813774% of us,

GCC seems to be the most common compiler around. In
its default mode it accepts many C99 constructs. So I
think your figure should be revised downwards somewhat.
 
O

Old Wolf

Ben said:
But

const int a = 2;
(int) a = 3;

is not UB, right?

Well, it should fail to compile. (int)a is not an lvalue.

Whether or not constraint violations are UB is a bit of an
academic matter (half the NG seems to think they are and
half think they aren't).
 
O

osmium

osmium said:
Here's another cut at it.

I see the copy I posted is where I was fooling around trying to see how many
trials it took to get a result of 1.0 It is in the vicinity of 128 trials.
Change the 128 to 200 to customize this to your question. Also note this
was compiled on a compiler that accepts some C99 syntax, E.g., \\ comments.

Note that if you had six coins and flipped them all, you would get six heads
with probability .0156 . That's available from tables of the binomial
distribution. A good statistics book will have that in the appendix.
 
O

Old Wolf

Eric said:
For example,

int array[] = { 1, 2, 3 }, *p = array + 1;
printf ("%d\n", SENTINEL[p]);

... outputs "-3\n" if SENTINEL is -1, but "1\n" if it
is (-1).

(I *think* the only way to form an expression where
the presence or absence of parentheses around -1 makes
a difference is to use the bass-ackward array notation
as above. Can anyone come up with another?)

In pre-ANSI C we had:

int a = 1;
a =SENTINEL;

forming the =- operator.

Technically there is this:
#define PP(X) #X
#define PS(X) PP(X)

size_t value = sizeof PS(SENTINEL);


The only binary operators with higher precedence that unary
minus are () [] -> . and I don't see how to apply any of
them apart from [].

We could have:

void f(int i) { }

meaning that
f SENTINEL

is an expression (albeit, an expression that violates a constraint
in the no-brackets case).
 
E

Eric Sosman

Keith said:
Using a sentinel when reading a file, rather than checking for EOF, is
rarely a good idea. [...]

I'd say that using a sentinel (or equivalent, e.g. an
embedded count) is mandatory when reading a binary stream.
How else will you know when you've read all the data -- and
only the data?
 
C

CBFalconer

Old said:
GCC seems to be the most common compiler around. In
its default mode it accepts many C99 constructs. So I
think your figure should be revised downwards somewhat.

If you disapprove, I suggest you supply an equally precise revised
value. Otherwise why criticize the extensive research that has
gone into Richards figure? After all, 9 nines precision is not to
be sneezed at, and it does imply that Richard has polled at least
10E9 C users.
 
K

Keith Thompson

Eric Sosman said:
Keith said:
Using a sentinel when reading a file, rather than checking for EOF,
is
rarely a good idea. [...]

I'd say that using a sentinel (or equivalent, e.g. an
embedded count) is mandatory when reading a binary stream.
How else will you know when you've read all the data -- and
only the data?

I'm sure a lot of programs just read the entire file, but I realize
the standard allows binary files to be padded with zero bytes.

For a file that's just a linear sequence of fixed-size records,
reading up to EOF (at the cost of possibly not working on systems that
do padding) might be good enough. For anything more complex, the
structure of the file itself should tell indicate where the valid data
is (<PEDANTIC>are</PEDANTIC>). A sentinel is one of many possible
ways to do that.

Of course, C strings use '\0' as a sentinel value; the cost is that
you can't have '\0' in the string itself.
 
R

Richard Heathfield

Old Wolf said:
Whether or not constraint violations are UB is a bit of an
academic matter (half the NG seems to think they are and
half think they aren't).

I don't think it matters either way, provided they continue to be regarded
as show-stoppers.
 
R

Richard Heathfield

osmium said:
I see the copy I posted is where I was fooling around trying to see how
many
trials it took to get a result of 1.0 It is in the vicinity of 128
trials.
Change the 128 to 200 to customize this to your question. Also note this
was compiled on a compiler that accepts some C99 syntax, E.g., \\
comments.

\\ comments? :)

Incidentally, I am wary of a comment syntax that breaks when the text is
re-flowed, and which in any case constitutes a syntax error in a great many
extant implementations.
 
M

Mark McIntyre

osmium said:


\\ comments? :)

for writing C in Arabic, of course.

gd&r
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,184
Messages
2,570,973
Members
47,529
Latest member
JaclynShum

Latest Threads

Top