Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
889 views
in Technique[技术] by (71.8m points)

c - Strange behaviour of rand() in Xcode

While using Apple Xcode, the C program I include below will always return a 5 for y but z will return a random number, even though they have the same expression. Can you identify a reason for this behaviour?

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

int main()
{
    int x,y,z;
    srand((unsigned int)time(NULL));
    x = ((unsigned int)time(NULL));
    y=((double)rand()/(double)(RAND_MAX)*10);
    z=((double)rand()/(double)(RAND_MAX)*10);
    printf("Time %d
", x);
    printf("
");
    printf("Number y %d
", y);
    printf("
");
    printf("Number z %d
", z);
    printf("
");
    return 0;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

rand-31

Here's an adaptation of your program which shows more detail of what's going on:

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

int main(void)
{
    int x = ((unsigned int)time(NULL));
    srand((unsigned int)x);
    int r1 = rand();
    int y  = ((double)r1/(double)(RAND_MAX)*10);
    int r2 = rand();
    int z  = ((double)r2/(double)(RAND_MAX)*10);
    printf("Time %d
", x);
    printf("Random 1: %d
", r1);
    printf("Number y: %d
", y);
    printf("Random 2: %d
", r2);
    printf("Number z: %d
", z);
    return 0;
}

It captures the result of the two rand() calls independently of the calculation so that they can be printed. It also ensures that the value passed to time() is the same as the value printed, though the chances of them being different are pretty small.

When I ran it a few times, I got the outputs:

Time 1508694677
Random 1: 1292016210
Number y: 6
Random 2: 1709286653
Number z: 7

Time 1508694685
Random 1: 1292150666
Number y: 6
Random 2: 1821604998
Number z: 8

Time 1508694701
Random 1: 1292419578
Number y: 6
Random 2: 2046241688
Number z: 9

Time 1508694841
Random 1: 1294772558
Number y: 6
Random 2: 790587255
Number z: 3

As you can see, the values returned by rand() are different, but not very different, and consequently the computed value isn't all that different.

rand-23

One easy upgrade option is to use the drand48() functions, like this:

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

int main(void)
{
    int x = ((unsigned int)time(NULL));
    srand48((unsigned int)x);
    int r1 = lrand48();
    int y  = ((double)r1/(double)(RAND_MAX)*10);
    int r2 = lrand48();
    int z  = ((double)r2/(double)(RAND_MAX)*10);
    printf("RAND_MAX: %d
", RAND_MAX);
    printf("Time:     %d
", x);
    printf("Random 1: %d
", r1);
    printf("Number y: %d
", y);
    printf("Random 2: %d
", r2);
    printf("Number z: %d
", z);
    return 0;
}

The code prints RAND_MAX mainly to show that it is compatible with the range of values returned by lrand48(), which is documented to return a value in the range 0..231-1.

This gives different and arguably better results:

RAND_MAX: 2147483647
Time:     1508695069
Random 1: 705270938
Number y: 3
Random 2: 1758232243
Number z: 8

RAND_MAX: 2147483647
Time:     1508695074
Random 1: 1465504939
Number y: 6
Random 2: 733780153
Number z: 3

RAND_MAX: 2147483647
Time:     1508695080
Random 1: 1948289010
Number y: 9
Random 2: 1222424564
Number z: 5

rand-13

Alternatively, you can do what the macOS documentation says and switch to arc4random(). The link is to 'legacy' XCode 5 documentation, but the functionality hasn't changed recently.

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

int main(void)
{
    int x = ((unsigned int)time(NULL));
    int r1 = arc4random_uniform(INT_MAX);
    int y  = ((double)r1/(double)(RAND_MAX)*10);
    int r2 = arc4random_uniform(INT_MAX);
    int z  = ((double)r2/(double)(RAND_MAX)*10);
    printf("INT_MAX:  %d
", INT_MAX);
    printf("RAND_MAX: %d
", RAND_MAX);
    printf("Time:     %d
", x);
    printf("Random 1: %d
", r1);
    printf("Number y: %d
", y);
    printf("Random 2: %d
", r2);
    printf("Number z: %d
", z);
    return 0;
}

This uses arc4random_uniform() to generate a value in the range 0..INT_MAX, the same range as the other functions generated. There is no analogue to srand() with the arc4random() family of functions.

Sample runs:

INT_MAX:  2147483647
RAND_MAX: 2147483647
Time:     1508695894
Random 1: 938614006
Number y: 4
Random 2: 851262647
Number z: 3

INT_MAX:  2147483647
RAND_MAX: 2147483647
Time:     1508695900
Random 1: 1332829945
Number y: 6
Random 2: 386007903
Number z: 1

INT_MAX:  2147483647
RAND_MAX: 2147483647
Time:     1508695913
Random 1: 1953583540
Number y: 9
Random 2: 1273643162
Number z: 5

rand-83

Note that if you want a random integer between 0 and 10, then you should use arc4random_uniform(10) directly and not do the computations.

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

int main(void)
{
    int x = ((unsigned int)time(NULL));
    int y = arc4random_uniform(10);
    int z = arc4random_uniform(10);
    printf("Time:     %d
", x);
    printf("Number y: %d
", y);
    printf("Number z: %d
", z);
    return 0;
}

Example outputs:

Time:     1508696162
Number y: 5
Number z: 3

Time:     1508696163
Number y: 7
Number z: 5

Time:     1508696165
Number y: 3
Number z: 8

One further advantage of arc4random() et al is shown when I managed to run the program 3 times in a single second. With the other generators, these would have produced the same results because of using the same seed.

$ rand-83;rand-83;rand-83
Time:     1508696213
Number y: 4
Number z: 0
Time:     1508696213
Number y: 0
Number z: 1
Time:     1508696213
Number y: 9
Number z: 6
$

$ rand-31;rand-31;rand-31
Time 1508696334
Random 1: 1319865409
Number y: 6
Random 2: 1619339200
Number z: 7
Time 1508696334
Random 1: 1319865409
Number y: 6
Random 2: 1619339200
Number z: 7
Time 1508696334
Random 1: 1319865409
Number y: 6
Random 2: 1619339200
Number z: 7
$

JFTR: Code compiled on a MacBook Pro running macOS High Sierra 10.13. I used GCC 7.2.0 (rather than XCode 9) to compile, but the system library — and it is the library that is critical here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...