90765


乱数で取り出した数字がいくつ以上ならば、変数valにインクリメントするといったプログラムを作成しているのですが、取り出す乱数がすべて `-1`
になってしまうという現象が発生してしまいました。

乱数の取り出す式はあってると思うのですが、どの箇所に問題点があるのか教えて下さい。

実行環境はこちらです。  
<https://play.google.com/store/apps/details?id=app.compiler>

"scanfが使えない"とありますが、やり方がややこしいだけでちゃんと使えます。

以下コード

[code]

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
        
    int GETRANDOM(int,int);
    
    int main(void){
        int i,val,p;
        srand((unsigned int)time(NULL));
        
        for(i=0;i<=100;i++){
            val=GETRANDOM(0,100);
            if(val>5)
                p++;
        }
        printf("%d\n",p);
        return 0;
    }
    int GETRANDOM(int min,int max){
        return min+(int)(rand()*(max-min+1.0))/(RAND_MAX+1.0);
    }
    
[/code]


CC BY-SA 4.0
2022-08-26T03:27:35.470
90763
2022-08-29T03:11:37.817
2022-08-26T14:20:02.757
19110
52948
question
c
取り出す乱数がすべて -1 になってしまう

[code]

        return min+(int)(rand()*(max-min+1.0))/(RAND_MAX+1.0);
    
[/code]

`(int)(rand()*(max-min+1.0))` の掛け算で`int`の範囲を超える可能性があるので、その値を `int`
にキャストするとおかしな値になることがあります。割り算をした結果を `int` にキャストしたほうがよいでしょう。


CC BY-SA 4.0
2022-08-26T03:45:14.393
90765
2022-08-26T03:45:14.393
3475
90763
answer

[code]

    min+(int)(rand()*(max-min+1.0))/(RAND_MAX+1.0)
    
[/code]

処理系によるかもしれませんが、RAND_MAXに加算すべきではありません(絶対値の最も大きな負の値になることがあります)。手元に確認環境がないのですが、

[code]

    min+(int)(rand()*(max-min)/RAND_MAX
    
[/code]

でよいのではありませんか。


CC BY-SA 4.0
2022-08-26T03:53:53.473
90766
2022-08-26T03:53:53.473
8077
90763
answer


int32_t さんの言うように、関数呼び出しのときにキャストしてみたらうまくいきました。

[code]

    /* main.c */ 
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
        
    int GETRANDOM(int,int);
    
    int main(void){
        int i,a,p;
        srand((unsigned int)time(NULL));
        
        for(i=0;i<=100;i++){
            a=(int)GETRANDOM(0,100);
            if(a>5)
                p++;
        }
        printf("%d\n",p);
        return 0;
    }
    int GETRANDOM(int min,int max){
        return min+(rand()*(max-min+1.0))/(RAND_MAX+1.0);
    }
    
[/code]


CC BY-SA 4.0
2022-08-26T05:01:13.900
90768
2022-08-26T05:08:56.903
2022-08-26T05:08:56.903
3060
52948
90763
answer


関連する規則を列挙します。

  * 四則演算では演算前に左右の型を同じに揃える暗黙の型変換がある
  * 四則演算での暗黙の型変換は原則として表現範囲が広い側に揃えられる (詳細な規則は仕様を参照のこと。 この場合のように `double` と `int` なら `double` に揃えられる)
  * 四則演算の結果の型は上のルールで調整した両辺の型と同じ
  * 型変換したときに値が変換後の型で表せない場合、かつ変換後の型が符号付き整数である場合には結果は処理系定義の値となるか処理系定義のシグナルを生成する
  * 処理系定義とは未規定の動作のうちで各処理系が選択した動作を文書化するもの (言語仕様では決めないが処理系が決めてそのことをドキュメントに明記することを要求している)

以上の規則をあてはめて

[code]

    rand()*(max-min+1.0)
    
[/code]

という式で起こる暗黙の変換を陽に書くと

[code]

    (double)rand()*((double)(max-min)+1.0)
    
[/code]

という変換が起きています。 そして全体の型は `double` です。

`rand()` の結果が `int` の上限に近い値だった場合には `int` の表現範囲を超えてしまう可能性があります。 そのとき `int`
に変換すると上述の規則によって処理系定義の結果になるのですが、 [GCC
のドキュメントによれば](https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Integers-
implementation.html)変換結果の型の幅を法とするという挙動が示されています。 符号が負となることもあるでしょう。

* * *

言語仕様と処理系の規定では質問者が書いたコードに期待されているような一定範囲の乱数が得られないということは有りうるのですが常に `-1`
ということにはなりません。

どうやって常に `-1` であることを確認しましたか？

* * *

# 追記

すいません。 考慮するのを忘れていた規則がありました。

  * 実浮動小数点型から整数型 (`_Bool` 型以外) への変換では小数部を捨てた結果になる
  * 実浮動小数点型から整数型 (`_Bool` 型以外) への変換において、値を変換後の型で表せない場合は結果を未定義とする
  * 未定義とは、言語仕様は結果について何の要求も課さない。 状況を無視して予測不可能な結果を返してもよい

この場合はこの規則に引っかかり、結果は未定義となります。 未定義というのは「何が起きても良い」という規則なので `-1`
になったのが何故なのか言語仕様的に意味のある説明はできないです。

結果が未定義というのは事実上はプログラマに対して禁止していることだと考えてください。


CC BY-SA 4.0
2022-08-27T01:13:25.347
90778
2022-08-29T03:11:37.817
2022-08-29T03:11:37.817
3364
3364
90763
answer