Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

a gift for the mortensens

1 view
Skip to first unread message

frank

unread,
Jan 10, 2010, 2:35:19 AM1/10/10
to
Christmas persists for me. If you ever get an opportunity to attend a
"white elephant party," do so, because it's hilarious.

My friend Alan Mortensen forbade me from spending money on gifts as I
visited his and my family in Salt lake over the actual holidays, so I'm
working out a way where I can give his girls something of value.

I intend to write a couple C utilities for them, as software is not
dough. Where I'm stuck right now is that I can't seem to find source
for invoking pseudo-random behaviour. So here's my first attempt:

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

int main (void)
{

void srand(unsigned seed);
int rand(void);
time_t time(something);

srand(time(&timer));

return("pretty pathetic");
}

I've written hundreds of programs in C that invoke pseudo-random
behavior but nothing recently, or as "frank."

So, I'm looking for a link or some tips on how to invoke pseudo-random
behavior in C. Thanks for your comment.
--
frank

Nick Keighley

unread,
Jan 10, 2010, 11:12:18 AM1/10/10
to
On 10 Jan, 07:35, frank <fr...@example.invalid> wrote:

> I intend to write a couple C utilities [...].  


> Where I'm stuck right now is that I can't seem to find source
> for invoking pseudo-random behaviour.  So here's my first attempt:
>
> #include <stdio.h>
> #include <stdlib.h>
>
> int main (void)
> {
>
> void srand(unsigned seed);
> int rand(void);

don't do this. It isn't necessary if you have the approriate #includes


> time_t time(something);
>
> srand(time(&timer));
>
> return("pretty pathetic");
>
> }
>
> I've written hundreds of programs in C that invoke pseudo-random
> behavior but nothing recently, or as "frank."
>
> So, I'm looking for a link or some tips on how to invoke pseudo-random
> behavior in C.  Thanks for your comment.

try the FAQ http://c-faq.com/lib/index.html
particularly questions 13.15 and 13.16

frank

unread,
Jan 10, 2010, 6:05:14 PM1/10/10
to
Nick Keighley wrote:
> On 10 Jan, 07:35, frank <fr...@example.invalid> wrote:
>
>> I intend to write a couple C utilities [...].
>> Where I'm stuck right now is that I can't seem to find source
>> for invoking pseudo-random behaviour. So here's my first attempt:
>>
>> #include <stdio.h>
>> #include <stdlib.h>
>>
>> int main (void)
>> {
>>
>> void srand(unsigned seed);
>> int rand(void);
>
> don't do this. It isn't necessary if you have the approriate #includes

right. They're already declared in the headers.

> try the FAQ http://c-faq.com/lib/index.html
> particularly questions 13.15 and 13.16
>

The FAQ wouldn't load but I have a hard copy here that gave me what
seems to be an appropriate seed:

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
i is 1337295409
i is 2147483647
c is 1
dan@dan-desktop:~/source$ ./out
i is 1660238507
i is 2147483647
c is �
dan@dan-desktop:~/source$ cat mort1.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{


int i;
char c;
srand((unsigned int)time((time_t *)NULL));

i=rand();
printf("i is %d\n", i);
printf("i is %d\n", RAND_MAX);
c=(char)i;
printf("c is %c\n", c);

return 0;
}
// gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
dan@dan-desktop:~/source$

What I want to do now is produce equiprobable chars. If I wanted all
the chars, then I think that the above would suffice, but I want only
lower case letters.

I could use j = rand()%26 or some such and add that character to a, but
I want to be mindful of 13.16, which warns against this. Can someone
say a few words about this?

TIA.
--
frank

Barry Schwarz

unread,
Jan 10, 2010, 6:47:17 PM1/10/10
to
On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
wrote:

snip

>dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>i is 1337295409
>i is 2147483647

One of these statements must be false.

>c is 1

While that is the character representation of low order byte on an
ASCII machine, my EBCDIC system will produce significantly different
output.

>dan@dan-desktop:~/source$ ./out
>i is 1660238507
>i is 2147483647

>c is ?


>dan@dan-desktop:~/source$ cat mort1.c
>#include <stdio.h>
>#include <stdlib.h>
>#include <time.h>
>
>int main(void)
>{
>
>
>int i;
>char c;
>srand((unsigned int)time((time_t *)NULL));
>
>i=rand();
>printf("i is %d\n", i);
>printf("i is %d\n", RAND_MAX);

This statement is rarely true. For some seeds, it need not ever be
true.

>c=(char)i;

Does your system complain without the cast? If this code is executed
on a system where char is signed, the cast may not produce the desired
value and may not produce any value.

>printf("c is %c\n", c);
>
>return 0;
>}
>// gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>dan@dan-desktop:~/source$
>
>What I want to do now is produce equiprobable chars. If I wanted all
>the chars, then I think that the above would suffice, but I want only
>lower case letters.
>
>I could use j = rand()%26 or some such and add that character to a, but
>I want to be mindful of 13.16, which warns against this. Can someone
>say a few words about this?

There is no requirement for rand to produce random numbers with a
uniform distribution. How will your code handle a normal or Poisson
distribution?

--
Remove del for email

Ben Bacarisse

unread,
Jan 10, 2010, 6:49:58 PM1/10/10
to
frank <fr...@example.invalid> writes:
<snip>

> What I want to do now is produce equiprobable chars. If I wanted all
> the chars, then I think that the above would suffice, but I want only
> lower case letters.
>
> I could use j = rand()%26 or some such and add that character to a,
> but I want to be mindful of 13.16, which warns against this. Can
> someone say a few words about this?

When RAND_MAX is 2147483647 (as in your example) rand() results from 0
up to 2147483623 give you remainders 0 to 25 repeatedly. In fact
there are 82595524 sets of remainders. The 24 "left over" numbers,
2147483624 to 2147483647, give remainders 0 to 23 so, on average, 24
and 25 occur very slightly less often (1 in 82595525 times). The bias
is tiny -- will it matter?

If it does matter, instead of calling rand() once you must loop until
the result is between 0 and 2147483623. To be portable you'd write:

int r;
while ((r = rand()) >= RAND_MAX/26);

--
Ben.

Keith Thompson

unread,
Jan 10, 2010, 7:13:43 PM1/10/10
to
Barry Schwarz <schw...@dqel.com> writes:
[...]

> There is no requirement for rand to produce random numbers with a
> uniform distribution. How will your code handle a normal or Poisson
> distribution?

The standard's requirement is (C99 7.20.2.1p2):

The rand function computes a sequence of pseudo-random integers in
the range 0 to RAND_MAX.

I've always assumed that this is meant to imply a uniform
distribution. The authors probably thought that was so obvious it
didn't need to be stated.

Of course, any finite sequence from a uniform distribution has a
finite probability of looking like a normal or Poisson distribution,
or even a sequence of 0s.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

unread,
Jan 10, 2010, 7:20:19 PM1/10/10
to
frank <fr...@example.invalid> writes:
[..]

> #include <stdio.h>
> #include <stdlib.h>
> #include <time.h>
>
> int main(void)
> {
>
>
> int i;
> char c;
> srand((unsigned int)time((time_t *)NULL));
>
> i=rand();
> printf("i is %d\n", i);
> printf("i is %d\n", RAND_MAX);
> c=(char)i;
> printf("c is %c\n", c);
>
> return 0;
> }

Indentation?

None of the three casts in your program are necessary, and IMHO your
code would be improved by dropping them.

srand(time(NULL);;
...
c = i;

The second "i is %d\n" presumably is a typo for "RAND_MAX is %d\n".

If plain char is signed, the conversion of i from int to char (which
occurs with or without the cast) can produce an implementation-defined
result or raise an implementation-defined signal. If you want to
produce numbers within a specified range, you should do the necessary
arithmetic yourself.

If you want random lowercase letters, you can declare

const char letters[] = "abcdefghijklmnopqrstuvwxyz"

and index into the array with a random number in the range 0..25.

Section 13 of the comp.lang.c FAQ, <http://www.c-faq.com/>, has
several questions about random numbers.

Nick Keighley

unread,
Jan 11, 2010, 3:35:36 AM1/11/10
to
On 10 Jan, 23:05, frank <fr...@example.invalid> wrote:
> Nick Keighley wrote:
> > On 10 Jan, 07:35, frank <fr...@example.invalid> wrote:

> >> I intend to write a couple C utilities [...].  
> >> Where I'm stuck right now is that I can't seem to find source
> >> for invoking pseudo-random behaviour.  So here's my first attempt:

<snip>

> > try the FAQhttp://c-faq.com/lib/index.html


> > particularly questions 13.15 and 13.16
>
> The FAQ wouldn't load but I have a hard copy here that gave me what
> seems to be an appropriate seed:

<snip>

> #include <stdio.h>
> #include <stdlib.h>
> #include <time.h>
>
> int main(void)
> {
>
> int i;
> char c;
> srand((unsigned int)time((time_t *)NULL));
>
> i=rand();
> printf("i is %d\n", i);
> printf("i is %d\n", RAND_MAX);
> c=(char)i;

what do you think this does?

> printf("c is %c\n", c);
>
> return 0;}

<snip>

> What I want to do now is produce equiprobable chars.

see FAQ 13.6

> If I wanted all
> the chars, then I think that the above would suffice,

and likely a lot of other stuff

> but I want only lower case letters.
>
> I could use j = rand()%26

that produces badly distributed numbers in the rnage 0..25. The lower
case letters are not in the range 0..25 in most character sets. Use
FAQ 13.6 to get yourself a uniform distribution of numbers in the
range in the range 0..25. The use Keiths idea or add 'a' (which will
work for ASCII).

> or some such and add that character to a, but
> I want to be mindful of 13.16, which warns against this.  Can someone
> say a few words about this?

do what 13.6 says?

Frank

unread,
Jan 11, 2010, 2:24:50 PM1/11/10
to

Wouldn't this be a demotion? Mapping onto a smaller set like modular
athimetic. It *should* be able to produce any char in the set, and
somewhat equiprobably.


>
>> printf("c is %c\n", c);
>>
>> return 0;}
>
> <snip>
>
>> What I want to do now is produce equiprobable chars.
>
> see FAQ 13.6

I think they've switched numbers on the on-line ones:

Q: How can I split up a string into whitespace-separated fields?
How can I duplicate the process by which main() is handed argc and argv?

>
>> If I wanted all
>> the chars, then I think that the above would suffice,
>
> and likely a lot of other stuff
>
>> but I want only lower case letters.
>>
>> I could use j = rand()%26
>
> that produces badly distributed numbers in the rnage 0..25. The lower
> case letters are not in the range 0..25 in most character sets. Use
> FAQ 13.6 to get yourself a uniform distribution of numbers in the
> range in the range 0..25. The use Keiths idea or add 'a' (which will
> work for ASCII).
>
>> or some such and add that character to a, but
>> I want to be mindful of 13.16, which warns against this. Can someone
>> say a few words about this?
>
> do what 13.6 says?

Thanks all for responses. I have to run right now but had source tyo
discuss.
--
frank

Keith Thompson

unread,
Jan 11, 2010, 3:42:35 PM1/11/10
to
Frank <fr...@example.invalid> writes:
> On 1/11/2010 2:35 AM, Nick Keighley wrote:
>> On 10 Jan, 23:05, frank<fr...@example.invalid> wrote:
[...]
>>> int i;
>>> char c;
[...]

>>> c=(char)i;
>>
>> what do you think this does?
>
> Wouldn't this be a demotion? Mapping onto a smaller set like modular
> athimetic. It *should* be able to produce any char in the set, and
> somewhat equiprobably.
[...]

It's a conversion; since it converts from a wider type to a narrower
type, I suppose you could call it a demotion.

But what makes you think modular arithmetic is involved?

Plain char may be either signed or unsigned. If it's unsigned, then
yes, the result of the conversion is reduced modulo UCHAR_MAX+1
(that's modulo 256 on systems with 8-bit bytes). But if it's signed,
and the int value is outside the range CHAR_MIN..CHAR_MAX, then the
result of the conversion is implementation-defined -- *or* an
implementation-defined signal is raised.

I already mentioned this elsethread, though not in quite so much
detail.

frank

unread,
Jan 11, 2010, 5:56:04 PM1/11/10
to
Keith Thompson wrote:
> frank <fr...@example.invalid> writes:

[snipped and reordered for thematic reasons]

> None of the three casts in your program are necessary, and IMHO your
> code would be improved by dropping them.
>
> srand(time(NULL);;
> ...
> c = i;

This seems to work (with a right paren added and semi-colon removed):

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort2.c -o out; ./out
mort2.c: In function �main�:
mort2.c:11: warning: unused variable �c�
RAND_MAX is 2147483647
i is 13
dan@dan-desktop:~/source$ cat mort2.c


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

#define N 26

int
main (void)
{
int i;
char c;

srand(time(NULL));
printf ("RAND_MAX is %d\n", RAND_MAX);
i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
printf ("i is %d\n", i);

return 0;
}

// gcc -std=c99 -Wall -Wextra mort2.c -o out; ./out
dan@dan-desktop:~/source$

So none of those casts were doing anything for me? If so, I say we
replace this part of the FAQ.


>
> The second "i is %d\n" presumably is a typo for "RAND_MAX is %d\n".
>

more or less


> If plain char is signed, the conversion of i from int to char (which
> occurs with or without the cast) can produce an implementation-defined
> result or raise an implementation-defined signal. If you want to
> produce numbers within a specified range, you should do the necessary
> arithmetic yourself.

ok


>
> If you want random lowercase letters, you can declare
>
> const char letters[] = "abcdefghijklmnopqrstuvwxyz"
>
> and index into the array with a random number in the range 0..25.
>
> Section 13 of the comp.lang.c FAQ, <http://www.c-faq.com/>, has
> several questions about random numbers.
>

ok

> Indentation?
>

[implementation-specific]
I love these utilities that I get from ubuntu:
dan@dan-desktop:~/source$ indent -i3 mort2.c
The program 'indent' is currently not installed. You can install it by
typing:
sudo apt-get install indent
bash: indent: command not found
dan@dan-desktop:~/source$ sudo apt-get install indent
[sudo] password for dan:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer
required:
linux-headers-2.6.28-11 linux-headers-2.6.28-11-generic
Use 'apt-get autoremove' to remove them.
The following NEW packages will be installed:
indent
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 81.4kB of archives.
After this operation, 508kB of additional disk space will be used.
Get:1 http://us.archive.ubuntu.com jaunty/main indent 2.2.10-1 [81.4kB]
Fetched 81.4kB in 1s (41.4kB/s)
Selecting previously deselected package indent.
(Reading database ... 122566 files and directories currently installed.)
Unpacking indent (from .../indent_2.2.10-1_i386.deb) ...
Processing triggers for man-db ...
Setting up indent (2.2.10-1) ...

dan@dan-desktop:~/source$ indent -i3 mort2.c
dan@dan-desktop:~/source$ cat mort2.c


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

#define N 26

int
main (void)
{
int i;
char c;

srand ((unsigned int) time ((time_t *) NULL));
printf ("RAND_MAX is %d\n", RAND_MAX);
i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
printf ("i is %d\n", i);

return 0;
}

// gcc -std=c99 -Wall -Wextra mort2.c -o out; ./out

It took less than a minute.
--
frank


frank

unread,
Jan 11, 2010, 6:16:26 PM1/11/10
to

I don't quite see what you mean here, Ben. As I evaluate this, I start
at the right and get a number that is about a hundred million, and I
don't see how your source equates to its description.

What I think we need to do with this method is toss out all the results
higher than ...23 . If your source does this, can you tell me how?
--
frank

Keith Thompson

unread,
Jan 11, 2010, 6:14:23 PM1/11/10
to
frank <fr...@example.invalid> writes:
> Keith Thompson wrote:
>> frank <fr...@example.invalid> writes:
>
> [snipped and reordered for thematic reasons]
>
>> None of the three casts in your program are necessary, and IMHO your
>> code would be improved by dropping them.
>>
>> srand(time(NULL);;
>> ...
>> c = i;
>
> This seems to work (with a right paren added and semi-colon removed):

Oops, typo on my part.

[...]


> #include <stdio.h>
> #include <stdlib.h>
> #include <time.h>
>
> #define N 26
>
> int
> main (void)
> {
> int i;
> char c;
>
> srand(time(NULL));
> printf ("RAND_MAX is %d\n", RAND_MAX);
> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
> printf ("i is %d\n", i);
>
> return 0;
> }
>
> // gcc -std=c99 -Wall -Wextra mort2.c -o out; ./out
> dan@dan-desktop:~/source$
>
> So none of those casts were doing anything for me? If so, I say we
> replace this part of the FAQ.

No, that's not what I said. None of the casts in your previous code
were necessary. I obviously wasn't commenting on code you hadn't
posted yet.

In your new code:

i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);

the cast to int is unnecessary, since the result is being assigned to
an int object. The other two casts are necessary and appropriate,
since in their absence the int values wouldn't be converted to double.

[...]

>> Indentation?
>>
>
[52 lines deleted]


>
> It took less than a minute.

Great. Though I'm not quite sure why you felt the need to tell us, in
great detail, how you did it. Just posting properly indented code is
more than enough.

frank

unread,
Jan 11, 2010, 6:26:52 PM1/11/10
to
Barry Schwarz wrote:
> On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
> wrote:

>> dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>> i is 1337295409
>> i is 2147483647
>
> One of these statements must be false.

They are not simultaneously, but sequentially true.


>
>> c is 1
>
> While that is the character representation of low order byte on an
> ASCII machine, my EBCDIC system will produce significantly different
> output.

I thought they were the same for the first 128 elements, and that ascii
filled out 129-256, while ebcdic was size 128.

snip


>> c=(char)i;
>
> Does your system complain without the cast? If this code is executed
> on a system where char is signed, the cast may not produce the desired
> value and may not produce any value.

Why would a person want to have a signed char? I've never used one,
except errantly.

snip
--
frank

Ben Bacarisse

unread,
Jan 11, 2010, 6:39:39 PM1/11/10
to
frank <fr...@example.invalid> writes:
<snip>

> dan@dan-desktop:~/source$ cat mort2.c
> #include <stdio.h>
> #include <stdlib.h>
> #include <time.h>
>
> #define N 26
>
> int
> main (void)
> {
> int i;
> char c;
>
> srand(time(NULL));
> printf ("RAND_MAX is %d\n", RAND_MAX);
> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);

Here be dragons. As 64 bit integers get more and more common we are
edging towards a time when this will routinely fail because
(double)RAND_MAX + 1 can be equal to RAND_MAX if RAND_MAX is big
enough. This does not happen with a 32 RNG and normal IEEE
double-precision numbers, but if RAND_MAX is big enough (and a signed
64-bit int is big enough) the +1 has no effect on (double)RAND_MAX.

To get a floating-point number in [0, 1) I have taken to writing:

nextafter((double)rand() / RAND_MAX, 0)

nextafter is a C99 function that gives the next representable number,
near the first argument in the direction of the second. There are
probably better ways to do this, but the best of all would be a
floating-point random function in C. Such a function could rely on
the internal representation of a floating point number to give a
properly uniform distribution. Many C libraries include such a
function as an extension.

> printf ("i is %d\n", i);
>
> return 0;
> }

<snip>
--
Ben.

Ben Bacarisse

unread,
Jan 11, 2010, 6:52:15 PM1/11/10
to
frank <fr...@example.invalid> writes:

> Ben Bacarisse wrote:
>> frank <fr...@example.invalid> writes:
>> <snip>
>>> What I want to do now is produce equiprobable chars. If I wanted all
>>> the chars, then I think that the above would suffice, but I want only
>>> lower case letters.
>>>
>>> I could use j = rand()%26 or some such and add that character to a,
>>> but I want to be mindful of 13.16, which warns against this. Can
>>> someone say a few words about this?
>>
>> When RAND_MAX is 2147483647 (as in your example) rand() results from 0
>> up to 2147483623 give you remainders 0 to 25 repeatedly. In fact
>> there are 82595524 sets of remainders. The 24 "left over" numbers,
>> 2147483624 to 2147483647, give remainders 0 to 23 so, on average, 24
>> and 25 occur very slightly less often (1 in 82595525 times). The bias
>> is tiny -- will it matter?
>>
>> If it does matter, instead of calling rand() once you must loop until
>> the result is between 0 and 2147483623. To be portable you'd write:
>>
>> int r;
>> while ((r = rand()) >= RAND_MAX/26);
>>
>
> I don't quite see what you mean here, Ben. As I evaluate this, I
> start at the right and get a number that is about a hundred million,
> and I don't see how your source equates to its description.

Yes, I made a mistake. I meant to write:

while ((r = rand()) >= (RAND_MAX/26)*26);

(I hope I've got that right now.) This should discard the 24 extra
results that lead to the bias.

This may be moot now since from your recent post I think you have
decided that the bias does not matter.

--
Ben.

Keith Thompson

unread,
Jan 11, 2010, 6:57:00 PM1/11/10
to
frank <fr...@example.invalid> writes:
> Barry Schwarz wrote:
>> On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
>> wrote:
>
>>> dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>>> i is 1337295409
>>> i is 2147483647
>>
>> One of these statements must be false.
>
> They are not simultaneously, but sequentially true.

As I already pointed out and you acknowledged, the second "i is" was a
typo for "RAND_MAX is". i never takes on the value 2147483647, except
perhaps by coincidence. As printed, the first statement is true, the
second is false.

>>> c is 1
>>
>> While that is the character representation of low order byte on an
>> ASCII machine, my EBCDIC system will produce significantly different
>> output.
>
> I thought they were the same for the first 128 elements, and that
> ascii filled out 129-256, while ebcdic was size 128.

Nope. ASCII is a 7-bit code with codes 0-127 (typically stored in an
8-bit byte). EBCDIC is an 8-bit code, mostly inconsistent with ASCII.

Google is your friend.

> snip
>>> c=(char)i;
>>
>> Does your system complain without the cast? If this code is executed
>> on a system where char is signed, the cast may not produce the desired
>> value and may not produce any value.
>
> Why would a person want to have a signed char? I've never used one,
> except errantly.

Historical reasons, mostly. The point is that, on many modern
implementations, very likely including the one you're using, plain
char is a signed type.

Try printing the values of CHAR_MIN, CHAR_MAX, SCHAR_MIN, SCHAR_MAX,
and UCHAR_MAX (defined in <limits.h>).

frank

unread,
Jan 11, 2010, 8:01:45 PM1/11/10
to
Ben Bacarisse wrote:

> Yes, I made a mistake. I meant to write:
>
> while ((r = rand()) >= (RAND_MAX/26)*26);
>
> (I hope I've got that right now.) This should discard the 24 extra
> results that lead to the bias.

That makes sense now.


>
> This may be moot now since from your recent post I think you have
> decided that the bias does not matter.
>

Does the following admit of the same bias:
i = ((double) rand () / ((double) RAND_MAX + 1) * N);

What's happening bitwise in the above?
--
frank

Ersek, Laszlo

unread,
Jan 11, 2010, 8:34:54 PM1/11/10
to
In article <0.e39a1a19d064e8d97c6e.2010...@bsb.me.uk>, Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> To get a floating-point number in [0, 1)

"The drand48() and erand48() functions shall return non-negative,
double-precision, floating-point values, uniformly distributed over the
interval [0.0,1.0)."

Not standard C, but present in SUS since v1. [0] [1] [2]

erand48() should be suitable for multi-threaded usage. [3] [4] [5]

The XSI legend in SUSv4 [0] and SUSv3 [1] only shows that the interface
is not required from the implementation for POSIX conformance, but
required for XSI (X/Open System Interfaces or Single UNIX Specification)
conformance [6] [7].

Cheers,
lacos

[0] http://www.opengroup.org/onlinepubs/9699919799/functions/drand48.html
[1] http://www.opengroup.org/onlinepubs/000095399/functions/drand48.html
[2] http://www.opengroup.org/onlinepubs/007908775/xsh/drand48.html

[3] http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01
[4] http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_09.html#tag_02_09_01
[5] http://www.opengroup.org/onlinepubs/007908775/xsh/threads.html#tag_000_010_002

[6] http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_442
[7] http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap03.html#tag_03_439

Ben Bacarisse

unread,
Jan 11, 2010, 10:01:34 PM1/11/10
to
frank <fr...@example.invalid> writes:
<snip>

> Does the following admit of the same bias:
> i = ((double) rand () / ((double) RAND_MAX + 1) * N);

Yes.

> What's happening bitwise in the above?

That's complex and not very helpful, I think. The simplest way to see
what is happening is to pretend RAND_MAX is, say, 15 and to run through
all the outcomes when N does not divide 16. You'll see that some values
(2, 4 and 7) occur less frequently than the rest.

--
Ben.

frank

unread,
Jan 11, 2010, 11:12:22 PM1/11/10
to
Ben Bacarisse wrote:

>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>
> Here be dragons. As 64 bit integers get more and more common we are
> edging towards a time when this will routinely fail because
> (double)RAND_MAX + 1 can be equal to RAND_MAX if RAND_MAX is big
> enough. This does not happen with a 32 RNG and normal IEEE
> double-precision numbers, but if RAND_MAX is big enough (and a signed
> 64-bit int is big enough) the +1 has no effect on (double)RAND_MAX.
>
> To get a floating-point number in [0, 1) I have taken to writing:
>
> nextafter((double)rand() / RAND_MAX, 0)
>
> nextafter is a C99 function that gives the next representable number,
> near the first argument in the direction of the second. There are
> probably better ways to do this, but the best of all would be a
> floating-point random function in C. Such a function could rely on
> the internal representation of a floating point number to give a
> properly uniform distribution. Many C libraries include such a
> function as an extension.

Is gcc one of them?

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort3.c -o out; ./out
mort3.c: In function �main�:
mort3.c:12: warning: unused variable �c�
/tmp/ccAPcgbE.o: In function `main':
mort3.c:(.text+0x58): undefined reference to `nextafter'
collect2: ld returned 1 exit status
bash: ./out: No such file or directory
dan@dan-desktop:~/source$ cat mort3.c


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

#include <math.h>

#define N 26

int
main (void)
{
int i;
char c;

srand(time(NULL));
printf ("RAND_MAX is %d\n", RAND_MAX);

i = nextafter((double)rand() / RAND_MAX, 0);


printf ("i is %d\n", i);

return 0;
}

// gcc -std=c99 -Wall -Wextra mort3.c -o out; ./out
--
frank

frank

unread,
Jan 11, 2010, 11:29:54 PM1/11/10
to
Keith Thompson wrote:
> frank <fr...@example.invalid> writes:
>> Barry Schwarz wrote:
>>> On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
>>> wrote:
>>>> dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>>>> i is 1337295409
>>>> i is 2147483647
>>> One of these statements must be false.
>> They are not simultaneously, but sequentially true.
>
> As I already pointed out and you acknowledged, the second "i is" was a
> typo for "RAND_MAX is". i never takes on the value 2147483647, except
> perhaps by coincidence. As printed, the first statement is true, the
> second is false.

Now that I think about it, you are absolutely correct. i assumes one
value in the program and hence cannot be two. I think I was injecting
less belief in the "i is " part than a literal one. A longer version of
it may have been better to read "The integer I'm looking for is ".


>
>>>> c is 1
>>> While that is the character representation of low order byte on an
>>> ASCII machine, my EBCDIC system will produce significantly different
>>> output.
>> I thought they were the same for the first 128 elements, and that
>> ascii filled out 129-256, while ebcdic was size 128.
>
> Nope. ASCII is a 7-bit code with codes 0-127 (typically stored in an
> 8-bit byte). EBCDIC is an 8-bit code, mostly inconsistent with ASCII.
>
> Google is your friend.

I swear I've seen it differently, but I doubt you'd write that if it
weren't demonstrable.


>
>> snip
>>>> c=(char)i;
>>> Does your system complain without the cast? If this code is executed
>>> on a system where char is signed, the cast may not produce the desired
>>> value and may not produce any value.
>> Why would a person want to have a signed char? I've never used one,
>> except errantly.
>
> Historical reasons, mostly. The point is that, on many modern
> implementations, very likely including the one you're using, plain
> char is a signed type.
>
> Try printing the values of CHAR_MIN, CHAR_MAX, SCHAR_MIN, SCHAR_MAX,
> and UCHAR_MAX (defined in <limits.h>).

For something like this, I don't want to write a program; I want to look
at limits.h for my implementation. I've probably asked you three times
for this over the past couple years, but I keep getting sent back to go
in a lot of ways, as I work up my linux install for the 4th time. What
is the name of the newsgroup specific to gcc?
--
frank

frank

unread,
Jan 12, 2010, 12:15:37 AM1/12/10
to
Keith Thompson wrote:
> frank <fr...@example.invalid> writes:
>> Keith Thompson wrote:
>>> frank <fr...@example.invalid> writes:
>> [snipped and reordered for thematic reasons]
>>
>>> None of the three casts in your program are necessary, and IMHO your
>>> code would be improved by dropping them.
>>>
>>> srand(time(NULL);;
>>> ...
>>> c = i;
>> This seems to work (with a right paren added and semi-colon removed):
>
> Oops, typo on my part.

I think "we" should update the FAQ to replace your expression with the
one that Steve Summit had. People like me, who read his collection
while sitting in a parking lot, are always grateful for his
contribution, but useless casts make code unreadable.


>
> [...]
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <time.h>
>>
>> #define N 26
>>
>> int
>> main (void)
>> {
>> int i;
>> char c;
>>
>> srand(time(NULL));
>> printf ("RAND_MAX is %d\n", RAND_MAX);
>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>> printf ("i is %d\n", i);
>>
>> return 0;
>> }
>>
>> // gcc -std=c99 -Wall -Wextra mort2.c -o out; ./out
>> dan@dan-desktop:~/source$
>>
>> So none of those casts were doing anything for me? If so, I say we
>> replace this part of the FAQ.
>
> No, that's not what I said. None of the casts in your previous code
> were necessary. I obviously wasn't commenting on code you hadn't
> posted yet.

Yeah, I didn't do the best editing here.


>
> In your new code:
>
> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>
> the cast to int is unnecessary, since the result is being assigned to
> an int object. The other two casts are necessary and appropriate,
> since in their absence the int values wouldn't be converted to double.

Still curious about this.


> Indentation?
>>>
> [52 lines deleted]
>> It took less than a minute.
>
> Great. Though I'm not quite sure why you felt the need to tell us, in
> great detail, how you did it. Just posting properly indented code is
> more than enough.
>

http://clc-wiki.net/wiki/clc-wiki:Policies#codeformat

This is topical, according to the wiki. I didn't explain the details
but will now take the opportunity to do so. MY OS (ubuntu) registered
that I wanted indent and gave me the the line that I needed to make it
happen off the command line. Then I hit the up arrow twice to find the
command that had failed, and voila.
--
frank

Barry Schwarz

unread,
Jan 12, 2010, 12:59:52 AM1/12/10
to
On Mon, 11 Jan 2010 15:14:23 -0800, Keith Thompson <ks...@mib.org>
wrote:

>frank <fr...@example.invalid> writes:

snip

>> #include <stdio.h>

Only the second cast to double is necessary. Once RAND_MAX is
converted to double, all the remaining values in the expression must
also be converted. While the first cast to double might achieve the
same effect, the denominator would be evaluated as an int first and
could overflow before being converted to double.

Barry Schwarz

unread,
Jan 12, 2010, 12:59:52 AM1/12/10
to
On Mon, 11 Jan 2010 16:26:52 -0700, frank <fr...@example.invalid>
wrote:

>Barry Schwarz wrote:
>> On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
>> wrote:
>
>>> dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort1.c -o out; ./out
>>> i is 1337295409
>>> i is 2147483647
>>
>> One of these statements must be false.
>
>They are not simultaneously, but sequentially true.
>>
>>> c is 1
>>
>> While that is the character representation of low order byte on an
>> ASCII machine, my EBCDIC system will produce significantly different
>> output.
>
>I thought they were the same for the first 128 elements, and that ascii
>filled out 129-256, while ebcdic was size 128.

The character '1' on an ASCII system is 0x31. On an EBCDIC system it
is 0xF1. ASCII 'A' is 0x41, EBCDIC is 0xC1. Worse, on an ASCII
system, 'J'-'I' is 1; in EBCDIC it is 8.

About the only character in common is '\0' which is 0x00 on both.

Richard Heathfield

unread,
Jan 12, 2010, 1:02:57 AM1/12/10
to
Barry Schwarz wrote:
> On Mon, 11 Jan 2010 15:14:23 -0800, Keith Thompson <ks...@mib.org>
> wrote:

<snip>

>> In your new code:
>>
>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>>
>> the cast to int is unnecessary, since the result is being assigned to
>> an int object. The other two casts are necessary and appropriate,
>> since in their absence the int values wouldn't be converted to double.
>
> Only the second cast to double is necessary.

Not even the second cast is necessary.

i = (rand() / (RAND_MAX + 1.0)) * N;

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within

Keith Thompson

unread,
Jan 12, 2010, 1:41:46 AM1/12/10
to
frank <fr...@example.invalid> writes:
> Ben Bacarisse wrote:
[...]

>> To get a floating-point number in [0, 1) I have taken to writing:
>>
>> nextafter((double)rand() / RAND_MAX, 0)
>>
>> nextafter is a C99 function that gives the next representable number,
>> near the first argument in the direction of the second. There are
>> probably better ways to do this, but the best of all would be a
>> floating-point random function in C. Such a function could rely on
>> the internal representation of a floating point number to give a
>> properly uniform distribution. Many C libraries include such a
>> function as an extension.
>
> Is gcc one of them?

No, since gcc is a compiler not a library. (glibc is the library
most commonly associated with gcc, but in fact gcc is generally
used with whatever library exists on the system.)

[...]

Keith Thompson

unread,
Jan 12, 2010, 1:51:27 AM1/12/10
to
frank <fr...@example.invalid> writes:
> Keith Thompson wrote:
>> frank <fr...@example.invalid> writes:
>>> Barry Schwarz wrote:
>>>> On Sun, 10 Jan 2010 16:05:14 -0700, frank <fr...@example.invalid>
>>>> wrote:
[...]

>>>>> i is 1337295409
>>>>> i is 2147483647
>>>> One of these statements must be false.
>>> They are not simultaneously, but sequentially true.
>>
>> As I already pointed out and you acknowledged, the second "i is" was a
>> typo for "RAND_MAX is". i never takes on the value 2147483647, except
>> perhaps by coincidence. As printed, the first statement is true, the
>> second is false.
>
> Now that I think about it, you are absolutely correct. i assumes one
> value in the program and hence cannot be two. I think I was injecting
> less belief in the "i is " part than a literal one. A longer version
> of it may have been better to read "The integer I'm looking for is ".

So you were using "i" to refer generically to whatever integer you're
looking at the moment, while your program declares an integer object
named "i". That's, um, a very interesting way of looking at things.

Really, given that you wanted to display the values of i and RAND_MAX,
the only sensible thing to write would be:

printf("i is %d\n", i);

printf("RAND_MAX is %d\n", RAND_MAX);

or some variation.

[...]

>>> Why would a person want to have a signed char? I've never used one,
>>> except errantly.
>>
>> Historical reasons, mostly. The point is that, on many modern
>> implementations, very likely including the one you're using, plain
>> char is a signed type.
>>
>> Try printing the values of CHAR_MIN, CHAR_MAX, SCHAR_MIN, SCHAR_MAX,
>> and UCHAR_MAX (defined in <limits.h>).
>
> For something like this, I don't want to write a program; I want to
> look at limits.h for my implementation.

Ok, nobody's stopping you. But why? The standard headers aren't
generally written to be particularly human-readable. On my system,
for example, I see the following in /usr/include/limits.h:

/* Minimum and maximum values a `char' can hold. */
# ifdef __CHAR_UNSIGNED__
# define CHAR_MIN 0
# define CHAR_MAX UCHAR_MAX
# else
# define CHAR_MIN SCHAR_MIN
# define CHAR_MAX SCHAR_MAX
# endif

I can guess where __CHAR_UNSIGNED__ would be defined, but I'm not sure
(plain char is signed on my system).

For that matter, the standard headers aren't necessarily even
implemented as source files.

Writing and executing a program is the only reliable way to display
the values to which these macros expand.

> I've probably asked you three
> times for this over the past couple years, but I keep getting sent
> back to go in a lot of ways, as I work up my linux install for the 4th
> time. What is the name of the newsgroup specific to gcc?

You're probably looking for gnu.gcc.help.

Keith Thompson

unread,
Jan 12, 2010, 1:57:58 AM1/12/10
to
frank <fr...@example.invalid> writes:
> Keith Thompson wrote:
>> frank <fr...@example.invalid> writes:
>>> Keith Thompson wrote:
>>>> frank <fr...@example.invalid> writes:
>>> [snipped and reordered for thematic reasons]
>>>
>>>> None of the three casts in your program are necessary, and IMHO your
>>>> code would be improved by dropping them.
>>>>
>>>> srand(time(NULL);;
>>>> ...
>>>> c = i;
>>> This seems to work (with a right paren added and semi-colon removed):
>>
>> Oops, typo on my part.
>
> I think "we" should update the FAQ to replace your expression with the
> one that Steve Summit had.

I think you meant that the other way around.

> People like me, who read his collection
> while sitting in a parking lot, are always grateful for his
> contribution, but useless casts make code unreadable.

What useless casts? There were several in the earlier code you
posted; there aren't very many in the FAQ. In question 13.16, we see:

(int)((double)rand() / ((double)RAND_MAX + 1) * N)

and

(int)(drand48() * N)

The double casts *are* necessary. The int casts may or may not be,
depending on what's done with the result.

[...]

>> In your new code:
>>
>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>>
>> the cast to int is unnecessary, since the result is being assigned to
>> an int object. The other two casts are necessary and appropriate,
>> since in their absence the int values wouldn't be converted to double.
>
> Still curious about this.

About what? I don't know what you're asking.

>> Indentation?
>>>>
>> [52 lines deleted]
>>> It took less than a minute.
>>
>> Great. Though I'm not quite sure why you felt the need to tell us, in
>> great detail, how you did it. Just posting properly indented code is
>> more than enough.
>
> http://clc-wiki.net/wiki/clc-wiki:Policies#codeformat
>
> This is topical, according to the wiki.

[l..]

My remark was more about verbosity than about topicality, but arguing
the point any further would just be ironic.

Keith Thompson

unread,
Jan 12, 2010, 2:02:16 AM1/12/10
to
Richard Heathfield <r...@see.sig.invalid> writes:
> Barry Schwarz wrote:
>> On Mon, 11 Jan 2010 15:14:23 -0800, Keith Thompson <ks...@mib.org>
>> wrote:
>
> <snip>
>
>>> In your new code:
>>>
>>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>>>
>>> the cast to int is unnecessary, since the result is being assigned to
>>> an int object. The other two casts are necessary and appropriate,
>>> since in their absence the int values wouldn't be converted to double.
>>
>> Only the second cast to double is necessary.
>
> Not even the second cast is necessary.
>
> i = (rand() / (RAND_MAX + 1.0)) * N;

Nicely done!

In cases like this, though, I think I'd argue that using casts or not
is largely a matter of taste. I find that I'm a little uncomfortable
with the way the constant 1.0 imposes its type on the rest of the
expression, bubbling up through multiple levels of the tree.

And I suppose that's inconsistent with most of what I've said about
using casts where implicit conversions would do the same job. Oh,
well.

Richard Heathfield

unread,
Jan 12, 2010, 4:04:40 AM1/12/10
to
Keith Thompson wrote:

<snip>

> I find that I'm a little uncomfortable
> with the way the constant 1.0 imposes its type on the rest of the
> expression, bubbling up through multiple levels of the tree.

But you get that "bubbling up" anyway, with (double)RAND_MAX, so I don't
see why 1.0 should worry you.

Ben Bacarisse

unread,
Jan 12, 2010, 6:46:34 AM1/12/10
to
frank <fr...@example.invalid> writes:

> Ben Bacarisse wrote:
<snip>
>> ... There are


>> probably better ways to do this, but the best of all would be a
>> floating-point random function in C. Such a function could rely on
>> the internal representation of a floating point number to give a
>> properly uniform distribution. Many C libraries include such a
>> function as an extension.
>
> Is gcc one of them?

glibc (rather than gcc) includes drand48. It is a POSIX function.
Someone else posted about this as well (sorry I forget who).

<snip>
--
Ben.

Ben Bacarisse

unread,
Jan 12, 2010, 6:52:07 AM1/12/10
to
Keith Thompson <ks...@mib.org> writes:

> frank <fr...@example.invalid> writes:
<snip>


>> People like me, who read his collection
>> while sitting in a parking lot, are always grateful for his
>> contribution, but useless casts make code unreadable.
>
> What useless casts? There were several in the earlier code you
> posted; there aren't very many in the FAQ. In question 13.16, we see:
>
> (int)((double)rand() / ((double)RAND_MAX + 1) * N)
>
> and
>
> (int)(drand48() * N)
>
> The double casts *are* necessary. The int casts may or may not be,
> depending on what's done with the result.

Surely only one of the casts to double is needed? I'm not sure it's
clearer to omit one, but I don't think they are both needed. I have
also seen the expression with neither cast and 1 replaced by 1.0.

<snip>
--
Ben.

Ben Bacarisse

unread,
Jan 12, 2010, 6:53:36 AM1/12/10
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
re: (int)((double)rand() / ((double)RAND_MAX + 1) * N)
<snip>

> Surely only one of the casts to double is needed? I'm not sure it's
> clearer to omit one, but I don't think they are both needed. I have
> also seen the expression with neither cast and 1 replaced by 1.0.

Sorry. I see that got covered in another sub-thread.

--
Ben.

Nick Keighley

unread,
Jan 12, 2010, 7:12:29 AM1/12/10
to
On 11 Jan, 19:24, Frank <fr...@example.invalid> wrote:
> On 1/11/2010 2:35 AM, Nick Keighley wrote:
> > On 10 Jan, 23:05, frank<fr...@example.invalid>  wrote:
> >> Nick Keighley wrote:
> >>> On 10 Jan, 07:35, frank<fr...@example.invalid>  wrote:

> >>>> I intend to write a couple C utilities [...].
> >>>> Where I'm stuck right now is that I can't seem to find source
> >>>> for invoking pseudo-random behaviour.  So here's my first attempt:
>
> >>> try the FAQ http://c-faq.com/lib/index.html
> >>> particularly questions 13.15 and 13.16

<snip>

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

> >> int main(void)
> >> {
>
> >> int i;
> >> char c;
> >> srand((unsigned int)time((time_t *)NULL));
>
> >> i=rand();


> >> printf("i is %d\n", i);

> >> printf("i is %d\n", RAND_MAX);


> >> c=(char)i;
>
> > what do you think this does?
>
> Wouldn't this be a demotion?  

well it stuffs an int into a char. The cast is unecessary.

> Mapping onto a smaller set like modular athimetic.
> It *should* be able to produce any char in the set, and
> somewhat equiprobably.

but it may produce some stuff that isn't a valid character. char might
be 8 bits and charcaters might be 7 bits (less likely these days).
Plus you might have problems with signed/unsigned chars.

> >> printf("c is %c\n", c);
>
> >> return 0;}>


> >> What I want to do now is produce equiprobable chars.
>

> > see FAQ 13.6
>
> I think they've switched numbers on the on-line ones:
>
> Q: How can I split up a string into whitespace-separated fields?
> How can I duplicate the process by which main() is handed argc and argv?

or I screwed up. <pause> ok, now look at FAQ 13.16 instead
:-(

> >>   If I wanted all
> >> the chars, then I think that the above would suffice,
>

> > and likely a lot of other stuff


>
> >> but I want only lower case letters.
>
> >> I could use j = rand()%26
>

> > that produces badly distributed numbers in the rnage 0..25. The lower
> > case letters are not in the range 0..25 in most character sets.

actually they *can't* be in the range 0..25 in C because 0 is reserved
for the nul character.

> > Use
> > FAQ [13.16] to get yourself a uniform distribution of numbers in the
> > range in the range 0..25. The use Keiths idea or add 'a' (which will
> > work for ASCII).

<snip>

Ersek, Laszlo

unread,
Jan 12, 2010, 10:05:58 AM1/12/10
to

It may have been me (too):

http://groups.google.com/group/comp.lang.c/msg/8a13f0c02a4769d2

As written there, drand48() is specifically not a POSIX function, it's
an XSI (X/Open System Interafes / Single UNIX Specification) function.
It's (theoretically) possible to conform to POSIX without conforming to
the SUS.

In my understanding, the POSIX documents and the SUS documents were
different sets of specifications before SUSv3. They were merged starting
with SUSv3, and from that point on, put crudely, SUS \ XSI = POSIX.
Since drand48() is marked XSI, it's possible for an implementation to
conform to POSIX without providing drand48().

Personally, I'd call it without a second thought: if I was programming
for SUSv2 / UNIX 98 (a distinct set of specs from the then-current POSIX
specs), the interface is required; if I was programming for SUSv3 / UNIX
03, or SUSv4, I'd just document the XSI-dependency of the code. I
believe this would be no limitation at all in practice; see the list of
UNIX 98 / UNIX 03 certified products:

http://www.opengroup.org/openbrand/register/

No GNU/Linux based product there, but that's the least worry: the
development of glibc seems to drive the SUS, so to say.

http://www.reddit.com/r/programming/comments/a4u27/dear_proggit_we_talk_a_lot_about_programming/c0fvdwn

Cheers,
lacos
http://lacos.hu/

Flash Gordon

unread,
Jan 12, 2010, 4:15:59 PM1/12/10
to
frank wrote:
> Keith Thompson wrote:
>> frank <fr...@example.invalid> writes:
>>> Keith Thompson wrote:
>>>> frank <fr...@example.invalid> writes:
>>> [snipped and reordered for thematic reasons]
>>>
>>>> None of the three casts in your program are necessary, and IMHO your
>>>> code would be improved by dropping them.
>>>>
>>>> srand(time(NULL);;
>>>> ...
>>>> c = i;
>>> This seems to work (with a right paren added and semi-colon removed):
>>
>> Oops, typo on my part.
>
> I think "we" should update the FAQ to replace your expression with the
> one that Steve Summit had.

The FAQ is maintained by Steve Summit, you will have to email him if you
think something should be changed.

> People like me, who read his collection
> while sitting in a parking lot, are always grateful for his
> contribution, but useless casts make code unreadable.

I would be inclined to look more carefully... it is entirely possible
that Steve what is in the FAQ is correct.

<snip>

>> Great. Though I'm not quite sure why you felt the need to tell us, in
>> great detail, how you did it. Just posting properly indented code is
>> more than enough.
>>
>
> http://clc-wiki.net/wiki/clc-wiki:Policies#codeformat
>
> This is topical, according to the wiki.

<snip>

Those are the policies for the Wiki (and are open to change if someone
wants them changed).

The link for discussions about topical views about comp.lang.c is this
http://clc-wiki.net/wiki/Intro_to_clc
--
Flash Gordon

frank

unread,
Jan 12, 2010, 9:00:18 PM1/12/10
to

Thx, Flash, I found this as I was just poking around there:

# Compiler-specific questions, such as installation issues and
locations of header files. Ask about these in compiler-specific
newsgroups, such as gnu.gcc.help, comp.os.msdos.djgpp (x86 version of
the free gcc C compiler), comp.compilers.lcc (the LCC family of C
compilers including LCC-Win32).


1.4 is a good resource for me as I seem to need to repopulate my
newsreader every 6 months.
--
frank

Phil Carmody

unread,
Jan 13, 2010, 4:54:40 AM1/13/10
to
Keith Thompson <ks...@mib.org> writes:
> Richard Heathfield <r...@see.sig.invalid> writes:
>> Barry Schwarz wrote:
>>> On Mon, 11 Jan 2010 15:14:23 -0800, Keith Thompson <ks...@mib.org>
>>> wrote:
>>
>> <snip>
>>
>>>> In your new code:
>>>>
>>>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>>>>
>>>> the cast to int is unnecessary, since the result is being assigned to
>>>> an int object. The other two casts are necessary and appropriate,
>>>> since in their absence the int values wouldn't be converted to double.
>>>
>>> Only the second cast to double is necessary.
>>
>> Not even the second cast is necessary.
>>
>> i = (rand() / (RAND_MAX + 1.0)) * N;
>
> Nicely done!
>
> In cases like this, though, I think I'd argue that using casts or not
> is largely a matter of taste. I find that I'm a little uncomfortable
> with the way the constant 1.0 imposes its type on the rest of the
> expression, bubbling up through multiple levels of the tree.
>
> And I suppose that's inconsistent with most of what I've said about
> using casts where implicit conversions would do the same job. Oh,
> well.

After years of dithering between different techniques, I now almost
always use Richard's. I think nothing says 'use floating point' more
concisely than actually sticking floating point numbers in the
expression. Try it - you might like it ;-)

Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1

Phil Carmody

unread,
Jan 13, 2010, 4:57:07 AM1/13/10
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
> frank <fr...@example.invalid> writes:
> <snip>
>> dan@dan-desktop:~/source$ cat mort2.c
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <time.h>
>>
>> #define N 26
>>
>> int
>> main (void)
>> {
>> int i;
>> char c;
>>
>> srand(time(NULL));
>> printf ("RAND_MAX is %d\n", RAND_MAX);
>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>
> Here be dragons. As 64 bit integers get more and more common we are
> edging towards a time when this will routinely fail because
> (double)RAND_MAX + 1 can be equal to RAND_MAX if RAND_MAX is big
> enough. This does not happen with a 32 RNG and normal IEEE
> double-precision numbers, but if RAND_MAX is big enough (and a signed
> 64-bit int is big enough) the +1 has no effect on (double)RAND_MAX.

I'd like to see which real-world value of RAND_MAX and which
rounding mode could make that happen. Typically, RAND_MAX will
be odd, and adding 1 will cause a cascade of carries and leave
a result which requires fewer bits of precision to represent
accurately.

Ben Bacarisse

unread,
Jan 13, 2010, 7:52:38 AM1/13/10
to
Phil Carmody <thefatphi...@yahoo.co.uk> writes:

> Ben Bacarisse <ben.u...@bsb.me.uk> writes:
>> frank <fr...@example.invalid> writes:
<snip>

>>> i = (int) ((double) rand () / ((double) RAND_MAX + 1) * N);
>>
>> Here be dragons. As 64 bit integers get more and more common we are
>> edging towards a time when this will routinely fail because
>> (double)RAND_MAX + 1 can be equal to RAND_MAX if RAND_MAX is big
>> enough. This does not happen with a 32 RNG and normal IEEE
>> double-precision numbers, but if RAND_MAX is big enough (and a signed
>> 64-bit int is big enough) the +1 has no effect on (double)RAND_MAX.
>
> I'd like to see which real-world value of RAND_MAX and which
> rounding mode could make that happen.

I don't know of real world systems with 64-bit RAND_MAX. My warning
was for the future of this common idiom. Of course, if you switch
rand() for a 64-bit RNG (like KISS recently posted by George
Marsaglia) you get the same problem if you use the idiom above.

> Typically, RAND_MAX will
> be odd, and adding 1 will cause a cascade of carries and leave
> a result which requires fewer bits of precision to represent
> accurately.

That doesn't help, I don't think. Using my gcc, it is true that a
large RAND_MAX get rounded up when converted to double, but so do a
few of the returned values from rand(). Adding 1 does not have the
effect of making the result of the division < 1.0 because the +1 has
no effect.

The probability of getting a large rand() from a 64-bit generator is
very low, but it will happen one day! Here is the worse case example
on my system. 512 returns from rand() can cause problems. You can
fix it with long double but since that may be no wider than double,
that option can just mask the problem until the code moves to another
machine.

#include <stdio.h>
#include <limits.h>

#define RAND_MAX LLONG_MAX
#define N 10

long long int rand(void) { return RAND_MAX-511; }

int main(void)
{
int n = (rand() / (RAND_MAX + 1.0)) * N;
if (n == N)
puts("Don't use n as an array index!");
return 0;
}

--
Ben.

frank

unread,
Jan 13, 2010, 4:23:57 PM1/13/10
to
Keith Thompson wrote:
> Richard Heathfield <r...@see.sig.invalid> writes:

>> Not even the second cast is necessary.
>>
>> i = (rand() / (RAND_MAX + 1.0)) * N;
>
> Nicely done!
>
> In cases like this, though, I think I'd argue that using casts or not
> is largely a matter of taste. I find that I'm a little uncomfortable
> with the way the constant 1.0 imposes its type on the rest of the
> expression, bubbling up through multiple levels of the tree.
>
> And I suppose that's inconsistent with most of what I've said about
> using casts where implicit conversions would do the same job. Oh,
> well.
>

I missed this. (A guy's gotta sleep some time.) Ben thinks that what's
happening here is a little too nuanced for me, but I think I can get my
head around it and bring the necessary machinery to bear:

dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort5.c -o out; ./out
1222567701 = 01001000110111101110011100010101
14 = 00000000000000000000000000001110
dan@dan-desktop:~/source$ cat mort5.c


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

#include <math.h>
#include <limits.h>

#define STRING "%13d = %s\n"
#define E_TYPE int
#define N 26

typedef E_TYPE e_type;

void bitstr (char *str, const void *obj, size_t n);

int
main (void)
{
int i, j;
e_type e;
char ebits[CHAR_BIT * sizeof e + 1];

srand (time (NULL));
j = rand ();
e = j;
bitstr (ebits, &e, sizeof e);
printf (STRING, e, ebits);
i = (j / (RAND_MAX + 1.0)) * N;
e = i;
bitstr (ebits, &e, sizeof e);
printf (STRING, e, ebits);

return 0;
}

void
bitstr (char *str, const void *obj, size_t n)
{
unsigned mask;
const unsigned char *const byte = obj;

while (n-- != 0)
{
mask = ((unsigned char) -1 >> 1) + 1;

do
{
*str++ = (char) (mask & byte[n] ? '1' : '0');
mask >>= 1;
}
while (mask != 0);
}
*str = '\0';
}


// gcc -std=c99 -Wall -Wextra mort5.c -o out; ./out
dan@dan-desktop:~/source$

I've seen now several versions of
i = (j / (RAND_MAX + 1.0)) * N;
What is happening to 1222567701 / (RAND_MAX + 1.0) * 26?
Of what type is (RAND_MAX + 1.0) ?

Thanks again for your thoughtful comments.
--
frank

Keith Thompson

unread,
Jan 13, 2010, 5:13:21 PM1/13/10
to
frank <fr...@example.invalid> writes:
[big snip]

> I've seen now several versions of
> i = (j / (RAND_MAX + 1.0)) * N;
> What is happening to 1222567701 / (RAND_MAX + 1.0) * 26?
> Of what type is (RAND_MAX + 1.0) ?

RAND_MAX is of type int. 1.0 is of type double. The "usual
arithmetic conversions" are applied to the operands (C99 6.5.6p4).
These are described in 6.3.1.8. RAND_MAX is converted from int to
double, and the addition yields a double result.

Grab a copy of <http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf>
if you haven't already. Or any decent C reference should explain it.

Something else I just thought of: An alternative to
(RAND_MAX + 1.0)
would be
(double)(RAND_MAX + 1)
The version with 1.0 has two advantages that I can think of:
it avoids the need for a cast, and it avoids integer overflow if
RAND_MAX == INT_MAX.

frank

unread,
Jan 13, 2010, 6:29:24 PM1/13/10
to
Keith Thompson wrote:
> frank <fr...@example.invalid> writes:
> [big snip]
>> I've seen now several versions of
>> i = (j / (RAND_MAX + 1.0)) * N;
>> What is happening to 1222567701 / (RAND_MAX + 1.0) * 26?
>> Of what type is (RAND_MAX + 1.0) ?
>
> RAND_MAX is of type int. 1.0 is of type double. The "usual
> arithmetic conversions" are applied to the operands (C99 6.5.6p4).
> These are described in 6.3.1.8. RAND_MAX is converted from int to
> double, and the addition yields a double result.
>
> Grab a copy of <http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf>
> if you haven't already. Or any decent C reference should explain it.
>
> Something else I just thought of: An alternative to
> (RAND_MAX + 1.0)
> would be
> (double)(RAND_MAX + 1)
> The version with 1.0 has two advantages that I can think of:
> it avoids the need for a cast, and it avoids integer overflow if
> RAND_MAX == INT_MAX.
>

I'm not sure that does what you think it does:


dan@dan-desktop:~/source$ gcc -std=c99 -Wall -Wextra mort7.c -o out; ./out
mort7.c: In function �main�:
mort7.c:35: warning: integer overflow in expression
mort7.c:22: warning: unused variable �g�
mort7.c:21: warning: unused variable �k�
mort7.c:21: warning: unused variable �i�
3908406666 = 00010111010010111100000101011010
-2147483648.0000006 =
1100000111100000000000000000000000000000000000000000000000000000
dan@dan-desktop:~/source$ cat mort7.c


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

#define STRING "%7d6 = %s\n"
#define E_TYPE int
#define F_TYPE double
#define STRING2 "%7f6 = %s\n"
#define N 26

typedef E_TYPE e_type;
typedef F_TYPE f_type;

void bitstr (char *str, const void *obj, size_t n);

int
main (void)
{
int i, j, k;
double g;
e_type e;
f_type f;


char ebits[CHAR_BIT * sizeof e + 1];

char fbits[CHAR_BIT * sizeof f + 1];

srand (time (NULL));
j = rand ();
e = j;
bitstr (ebits, &e, sizeof e);
printf (STRING, e, ebits);


f = (double)(RAND_MAX + 1);
bitstr (fbits, &f, sizeof f);
printf (STRING2, f, fbits);

return 0;
}

void
bitstr (char *str, const void *obj, size_t n)
{
unsigned mask;
const unsigned char *const byte = obj;

while (n-- != 0)
{
mask = ((unsigned char) -1 >> 1) + 1;

do
{
*str++ = (char) (mask & byte[n] ? '1' : '0');
mask >>= 1;
}
while (mask != 0);
}
*str = '\0';
}


// gcc -std=c99 -Wall -Wextra mort7.c -o out; ./out
dan@dan-desktop:~/source$

I think we all agree that none of these values are to be negative.
--
frank

frank

unread,
Jan 13, 2010, 6:38:43 PM1/13/10
to
frank wrote:
> Keith Thompson wrote:

>> Something else I just thought of: An alternative to
>> (RAND_MAX + 1.0)
>> would be
>> (double)(RAND_MAX + 1)
>> The version with 1.0 has two advantages that I can think of:
>> it avoids the need for a cast, and it avoids integer overflow if
>> RAND_MAX == INT_MAX.
>>
>
> I'm not sure that does what you think it does:

Yes you do. You state it above, but I didn't understand that when I posted.
--
frank

frank

unread,
Jan 13, 2010, 6:51:46 PM1/13/10
to

I think it's important that the 1.0 bubbles up. You know a machine can
always give you one represented as a double. Adding RAND_MAX is then
small potatoes.

I've looked at a few different ways to do it, and the less good ones
involve building the integer, which isn't a good idea with RAND_MAX, and
then casting/converting it to a floating point type.

I still haven't figured out why we're creating a double type with a
value near RAND_MAX, but overflow is not the way to get there. Can
someone say a few words about
integer / double * integer?
--
frank

frank

unread,
Jan 14, 2010, 4:12:22 AM1/14/10
to
Keith Thompson wrote:

> If you want random lowercase letters, you can declare
>
> const char letters[] = "abcdefghijklmnopqrstuvwxyz"
>
> and index into the array with a random number in the range 0..25.

I've got something now that looks alright, and it seems to test well for
the 200,000 times I put it through its paces:

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

#include <assert.h>

#define N 26

char random_char (void);

int
main (void)
{
char a;
int i, counter;

srand (time (NULL));

counter = 0;

for (i = 0; i < RAND_MAX / 1000; ++i)
{
a = random_char ();
// printf("a is %c\n", a);
++counter;
}
printf ("counter is %d\n", counter);

return 0;
}

char
random_char (void)
{
char c;
int i, j;
const char letters[] = "abcdefghijklmnopqrstuvwxyz";
j = rand ();
i = (j / (RAND_MAX + 1.0)) * N;
assert (0 <= i && i < N);
c = letters[i];
return c;
}


// gcc -std=c99 -Wall -Wextra f1.c -o out; ./out

What I can't tell here is whether I've written something hugely
expensive in terms of computation. Would this code perform well?
--
frank

Phil Carmody

unread,
Jan 14, 2010, 4:37:43 AM1/14/10
to
frank <fr...@example.invalid> writes:
> I still haven't figured out why we're creating a double type with a
> value near RAND_MAX, but overflow is not the way to get there. Can
> someone say a few words about
> integer / double * integer?

Treated as ((integer/double)*integer). (integer/double) is
performed as (double/double) to yield a double. And then
(double*integer) performed as (double*double) to yield a
double.

It's integer/integer you normally want to be very wary of,
if you're embedding it within a tree of expressions that
will eventually become a double.

Phil Carmody

unread,
Jan 14, 2010, 4:50:55 AM1/14/10
to

AH, I didn't realise you were looking at that end of the issue.
Indeed, that is a problem.

> The probability of getting a large rand() from a 64-bit generator is
> very low, but it will happen one day! Here is the worse case example
> on my system. 512 returns from rand() can cause problems. You can
> fix it with long double but since that may be no wider than double,
> that option can just mask the problem until the code moves to another
> machine.
>
> #include <stdio.h>
> #include <limits.h>
>
> #define RAND_MAX LLONG_MAX
> #define N 10
>
> long long int rand(void) { return RAND_MAX-511; }
>
> int main(void)
> {
> int n = (rand() / (RAND_MAX + 1.0)) * N;
> if (n == N)
> puts("Don't use n as an array index!");

Yeah, but if you're mucking around with FP anyway, you shouldn't
expect results to not be inconveniently rounded occasionally
unless you've done some very thorough numerical analysis. 754 may
help you but C on its own doesn't.

It does appear that implementers are very slow to migrate to
larger RAND_MAX, or in fact do anything to make rand() less of
the almost-useless toy that it currently is, so hopefully this
will never be a problem.

Already missing contributions by Dik,

frank

unread,
Jan 15, 2010, 10:32:54 PM1/15/10
to
On Jan 13, 3:13 pm, Keith Thompson <ks...@mib.org> wrote:
> frank <fr...@example.invalid> writes:
>
> [big snip]
>
> > I've seen now several versions  of
> > i = (j / (RAND_MAX + 1.0)) * N;
> > What is happening to 1222567701 / (RAND_MAX + 1.0) * 26?
> > Of what type is (RAND_MAX + 1.0) ?
>
> RAND_MAX is of type int.  1.0 is of type double.  The "usual
> arithmetic conversions" are applied to the operands (C99 6.5.6p4).
> These are described in 6.3.1.8.  RAND_MAX is converted from int to
> double, and the addition yields a double result.
>
> Grab a copy of <http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf>
> if you haven't already.  Or any decent C reference should explain it.
>
> Something else I just thought of: An alternative to
>     (RAND_MAX + 1.0)
> would be
>     (double)(RAND_MAX + 1)
> The version with 1.0 has two advantages that I can think of:
> it avoids the need for a cast, and it avoids integer overflow if
> RAND_MAX == INT_MAX.
>

Otherwise, if both operands have signed integer types or both have
unsigned
integer types, the operand with the type of lesser integer conversion
rank is
converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank
greater or
equal to the rank of the type of the other operand, then the operand
with
signed integer type is converted to the type of the operand with
unsigned
integer type.
Otherwise, if the type of the operand with signed integer type can
represent
all of the values of the type of the operand with unsigned integer
type, then
the operand with unsigned integer type is converted to the type of the
operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type.

Can someone show an example for these integer promotions?

0 new messages