Bug 121885

Summary: random() system call returning the same number on amd64
Product: Base System Reporter: moggie
Component: amd64Assignee: freebsd-amd64 (Nobody) <amd64>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 6.2-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
random.c none

Description moggie 2008-03-19 22:30:00 UTC
I was experiencing some strange behavour using random() in a program so I thought
I'd better make a test program to see what was going on. The test program is simply
trying to use some random numbers to simulate packet loss.

Unfortunately when the test program executed it showed the random() number function
returning the number '8440544' each time. It first appeared that there was something
wrong with my program, but when it was executed on an i386 box it seemed to work as
expected - producing seemingly random numbers.

I ran the program on another amd64 machine which behaved in the same way as the
first test, resulting in random() returning the same number each time. The source code
for the test program is included below.

How-To-Repeat: The test program was just compiled as any other and executed:

	gcc -o random random.c
	./random
Comment 1 rsmith 2008-03-20 07:18:50 UTC
On Wed, Mar 19, 2008 at 10:02:31PM +0000, Lewis wrote:
> --- random.c begins here ---
> #include <stdio.h>
> #include <strings.h>
> #include <stdlib.h>
> #include <time.h>
> #include <sys/types.h>
> #include <unistd.h>
> 
> int main(int argc, char ** argv) {
> 
> 	srandom(time(0) * getpid());
> 	printf("time: %d\n", time(0));
> 	printf("pid: %d\n", getpid());
> 	
> 	double r_num;


This should be 'long random;', see random(3).

With this change it works. Or, see below.

> 	int i, percent = 50;
> 	/* Constant 0x7fffffff is equal to (2**31)-1, which is the
> 	*  maximum value returned by the random() number function.
> 	*  http://web.mit.edu/answers/c/c_random_numbers.html 2008/03/19 */
> 
> 	for (i = 0; i < 100; i++) {
> 		/*r_num = ((float) random() / (float) 0x7fffffff);*/
> 		r_num = random();
> 
> 		if (r_num < (percent / 100)) {
> 			printf("random: %u - Dropped packet.\n",r_num);
> 		} else {
> 			printf("random: %u - Sent packet.\n", r_num);


And if you want to use doubles, you should have used '%f' of '%g' here,
instead of '%u'. In which case it works as well.

> 		}
> 	}
> }
> 
> /* Sample program output:

(long r_num):
time: 1205997021
pid: 59547
random: 1651842516 - Sent packet.
random: 658819253 - Sent packet.
random: 597332715 - Sent packet.
random: 635700682 - Sent packet.
random: 996321444 - Sent packet.
random: 870878043 - Sent packet.
random: 1977054922 - Sent packet.
random: 955816479 - Sent packet.
random: 367175873 - Sent packet.
random: 16441391 - Sent packet.
random: 1188837559 - Sent packet.
random: 1906346020 - Sent packet.
random: 151679052 - Sent packet.

(double r_num, with '%g' in printf)
time: 1205997420
pid: 59748
random: 9.87536e+08 - Sent packet.
random: 1.5497e+09 - Sent packet.
random: 2.13094e+09 - Sent packet.
random: 1.08434e+09 - Sent packet.
random: 1.94301e+09 - Sent packet.
random: 1.34453e+09 - Sent packet.
random: 1.77993e+09 - Sent packet.
random: 1.10691e+09 - Sent packet.
random: 1.95755e+09 - Sent packet.
random: 1.70928e+09 - Sent packet.
random: 1.66913e+09 - Sent packet.
random: 1.90308e+09 - Sent packet.

I think this PR can be closed.

Roland
-- 
R.F.Smith                                   http://www.xs4all.nl/~rsmith/
[plain text _non-HTML_ PGP/GnuPG encrypted/signed email much appreciated]
pgp: 1A2B 477F 9970 BA3C 2914  B7CE 1277 EFB0 C321 A725 (KeyID: C321A725)
Comment 2 Lewis 2008-03-20 11:03:28 UTC
Hi,

Thanks for looking at this and spotting the problem, so much time was 
wasted trying to figure out what was wrong :( I guess much of the 
confusion was caused by the same code working on i386 but not amd64 and 
is what prompted people to suggest to me writing a PR. Would it have 
been because amd64 uses different sizes of 'double' than i386 or 
something like that?

Regards,
Lewis.

Roland Smith wrote:
> On Wed, Mar 19, 2008 at 10:02:31PM +0000, Lewis wrote:
>   
>> --- random.c begins here ---
>> #include <stdio.h>
>> #include <strings.h>
>> #include <stdlib.h>
>> #include <time.h>
>> #include <sys/types.h>
>> #include <unistd.h>
>>
>> int main(int argc, char ** argv) {
>>
>> 	srandom(time(0) * getpid());
>> 	printf("time: %d\n", time(0));
>> 	printf("pid: %d\n", getpid());
>> 	
>> 	double r_num;
>>     
>
> This should be 'long random;', see random(3).
>
> With this change it works. Or, see below.
>
>   
>> 	int i, percent = 50;
>> 	/* Constant 0x7fffffff is equal to (2**31)-1, which is the
>> 	*  maximum value returned by the random() number function.
>> 	*  http://web.mit.edu/answers/c/c_random_numbers.html 2008/03/19 */
>>
>> 	for (i = 0; i < 100; i++) {
>> 		/*r_num = ((float) random() / (float) 0x7fffffff);*/
>> 		r_num = random();
>>
>> 		if (r_num < (percent / 100)) {
>> 			printf("random: %u - Dropped packet.\n",r_num);
>> 		} else {
>> 			printf("random: %u - Sent packet.\n", r_num);
>>     
>
> And if you want to use doubles, you should have used '%f' of '%g' here,
> instead of '%u'. In which case it works as well.
>
>   
>> 		}
>> 	}
>> }
>>
>> /* Sample program output:
>>     
> (long r_num):
> time: 1205997021
> pid: 59547
> random: 1651842516 - Sent packet.
> random: 658819253 - Sent packet.
> random: 597332715 - Sent packet.
> random: 635700682 - Sent packet.
> random: 996321444 - Sent packet.
> random: 870878043 - Sent packet.
> random: 1977054922 - Sent packet.
> random: 955816479 - Sent packet.
> random: 367175873 - Sent packet.
> random: 16441391 - Sent packet.
> random: 1188837559 - Sent packet.
> random: 1906346020 - Sent packet.
> random: 151679052 - Sent packet.
>
> (double r_num, with '%g' in printf)
> time: 1205997420
> pid: 59748
> random: 9.87536e+08 - Sent packet.
> random: 1.5497e+09 - Sent packet.
> random: 2.13094e+09 - Sent packet.
> random: 1.08434e+09 - Sent packet.
> random: 1.94301e+09 - Sent packet.
> random: 1.34453e+09 - Sent packet.
> random: 1.77993e+09 - Sent packet.
> random: 1.10691e+09 - Sent packet.
> random: 1.95755e+09 - Sent packet.
> random: 1.70928e+09 - Sent packet.
> random: 1.66913e+09 - Sent packet.
> random: 1.90308e+09 - Sent packet.
>
> I think this PR can be closed.
>
> Roland
>
Comment 3 rsmith 2008-03-20 12:45:57 UTC
On Thu, Mar 20, 2008 at 11:03:28AM +0000, Lewis wrote:
> Hi,
> 

<snip> (please don't top-post)

>>> 	double r_num;
>> 
>> This should be 'long r_num;', see random(3).

[fixed spelling :)]

>> With this change it works. Or, see below.

<snip>
>>> 		if (r_num < (percent / 100)) {
>>> 			printf("random: %u - Dropped packet.\n",r_num);
>>> 		} else {
>>> 			printf("random: %u - Sent packet.\n", r_num);
>> 
>> And if you want to use doubles, you should have used '%f' of '%g' here,
>> instead of '%u'. In which case it works as well.

<snip>

> Thanks for looking at this and spotting the problem, so much time was 
> wasted trying to figure out what was wrong :( I guess much of the confusion 
> was caused by the same code working on i386 but not amd64 and is what 
> prompted people to suggest to me writing a PR. Would it have been because 
> amd64 uses different sizes of 'double' than i386 or something like that?


I think it is rather the size of 'long', which is 32 bits on i386 and 64
bits on amd64. Compare /usr/src/sys/i386/include/_types.h and
/usr/src/sys/amd64/include/_types.h 

I'll send you the source for a program that determines the lengths of
fundamental types off-list.

Roland
-- 
R.F.Smith                                   http://www.xs4all.nl/~rsmith/
[plain text _non-HTML_ PGP/GnuPG encrypted/signed email much appreciated]
pgp: 1A2B 477F 9970 BA3C 2914  B7CE 1277 EFB0 C321 A725 (KeyID: C321A725)
Comment 4 John Baldwin freebsd_committer freebsd_triage 2008-03-20 12:59:14 UTC
State Changed
From-To: open->closed

Not an OS bug.
Comment 5 Lewis 2008-03-20 13:19:00 UTC
Roland Smith wrote:
> On Thu, Mar 20, 2008 at 11:03:28AM +0000, Lewis wrote:
>   
>> Thanks for looking at this and spotting the problem, so much time was 
>> wasted trying to figure out what was wrong :( I guess much of the confusion 
>> was caused by the same code working on i386 but not amd64 and is what 
>> prompted people to suggest to me writing a PR. Would it have been because 
>> amd64 uses different sizes of 'double' than i386 or something like that?
>>     
>
> I think it is rather the size of 'long', which is 32 bits on i386 and 64
> bits on amd64. Compare /usr/src/sys/i386/include/_types.h and
> /usr/src/sys/amd64/include/_types.h 
>
> I'll send you the source for a program that determines the lengths of
> fundamental types off-list.
>
> Roland
>   

Oh right, yeah that makes sense. Thanks for the source code, it is 
really useful, and again for your help.

Regards,
Lewis.