

以下のコードで `num` は0~6になる思うのですが、すべて4になってしまいます。  
`num=rand()%7` の7を他の数字でやると0〜その数字の間の数となります。  
7の時のみこのようになってしまうのですがなぜでしょうか？

環境は MacBook Pro、xcode Version 6.1です。

[code]

    #include<time.h>
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
        int i,num;
    
        srand(time(NULL));
        num=rand()%7;
    
        for(i=0;i<10;i++){
            printf("%d\n",num);
        }
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2015-07-03T21:23:49.240
12003
2021-03-10T05:21:57.690
2021-03-10T05:21:57.690
3060
10389
question
xcode c random
C言語での乱数生成で常に同じ値となってしまうケースがある


forループの中で `num`
の値は変更されていませんから、最初に決まった値を毎回表示することになります。必要であればforループの中で`num`の値を再設定してください。

[code]

    for(i=0;i<10;i++){
        num=rand()%7;
        printf("%d\n",num);
    }
    
[/code]

* * *

quesera2さんがXcodeにおけるrandの実装のリンクを張られています。

[code]

    static int
    do_rand(unsigned long *ctx)
    {
    #ifdef  USE_WEAK_SEEDING
    /*
     * Historic implementation compatibility.
     * The random sequences do not vary much with the seed,
     * even with overflowing.
     */
        return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
    #else   /* !USE_WEAK_SEEDING */
    /*
     * Compute x = (7^5 * x) mod (2^31 - 1)
     * wihout overflowing 31 bits:
     *      (2^31 - 1) = 127773 * (7^5) + 2836
     * From "Random number generators: good ones are hard to find",
     * Park and Miller, Communications of the ACM, vol. 31, no. 10,
     * October 1988, p. 1195.
     */
        long hi, lo, x;
    
        /* Can't be initialized with 0, so use another value. */
        if (*ctx == 0)
            *ctx = 123459876;
        hi = *ctx / 127773;
        lo = *ctx % 127773;
        x = 16807 * lo - 2836 * hi;
        if (x < 0)
            x += 0x7fffffff;
        return ((*ctx = x) % ((u_long)RAND_MAX + 1));
    #endif  /* !USE_WEAK_SEEDING */
    }
    
[/code]

となっています。`srand(time(NULL));`直後の`rand()%7`の値に限定すると、  
変数`hi`は`127773`で除算しているので127773秒ごとにしか変化しません。変数`lo`は`7^5`を乗じているので7の倍数です。つまり、127773秒（およそ35.5時間）周期でしか7の剰余の値は変化しません。


CC BY-SA 4.0
2015-07-03T21:29:44.673
12005
2021-01-25T04:33:56.133
2021-01-25T04:33:56.133
4236
4236
12003
answer


`num=rand()%7;`を`for`文に移動すれば、同じ数値が返ってくることはなくなります。

[code]

    #include<time.h>
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
        int i,num;
    
        srand((unsigned int)time(NULL)); // キャストしないと警告文が出ると思いますが？
    
        for(i=0;i<10;i++){  
            num=rand()%7;
            printf("%d\n",num);
        }
        return 0;
    }
    
[/code]

しかし、これでもじつはまだ問題が残ってしまいます。というのは、なんどビルドして実行しても初回の値がかならず4になるという現象が現れます。乱数を使用する目的からすれば、都合が悪い現象です。  
これはXcodeがインストールする、 **CLang+LLVMが内蔵する擬似乱数発生のアルゴリズム** に欠陥があるからといえると思います。  
乱数表の冒頭は捨てて、途中を採用すれば、より良い結果が得られると思います。

[code]

    #include<time.h>
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
        int i,num;
    
        srand((unsigned int)time(NULL));
        // 乱数表の冒頭10個は捨てる。
        for (i=0;i<10;i++) {
            rand();
        };
    
        for(i=0;i<10;i++){
            num=rand()%7;
            printf("%d\n",num);
        }
        return 0;
    }
    
[/code]

擬似乱数発生のアルゴリズムに完璧なものはないと言われています。用途に応じて、使い分けるか、上のような工夫が必要でしょう。  
Mac、iOS上のプログラムなら、`arc4random()`、`arc4random_uiiform()`という、Free
BSD由来の関数が使え、C言語の`rand()`関数より高い品質の乱数表を得られるといいます。


CC BY-SA 3.0
2015-07-03T22:43:49.123
12006
2015-07-05T12:09:41.713
2015-07-05T12:09:41.713
7362
7362
12003
answer