意味((フロート)のrand()/(フロート)((1 << 31) - 1))私はラインと.hファイルが含まれてCプログラムを理解しようとしている
#define random ((float) rand()/(float)((1 << 31) - 1))
Cプログラムには<math.h>
も含まれています。
私は、これは単に区間[0,1]の一様分布から乱数を生成すると考えています。これは正しいです?
意味((フロート)のrand()/(フロート)((1 << 31) - 1))私はラインと.hファイルが含まれてCプログラムを理解しようとしている
#define random ((float) rand()/(float)((1 << 31) - 1))
Cプログラムには<math.h>
も含まれています。
私は、これは単に区間[0,1]の一様分布から乱数を生成すると考えています。これは正しいです?
表面上はい。しかし、それは2つの主要な方法で間違っています。
代わりにRAND_MAX
を使用してください。それがそこにあるのです。それは1 << 31 - 1
よりずっと小さいかもしれません。
1 << 31
が格段によくある32ビットint
以下、とあなたのプラットフォーム上で未定義の動作を与えるだろう。それをしないでください! (しばしばそうであるように)あなたは値1を、回復したくない場合は、分母にRAND_MAX + 1.0
を使用することを
注意。 1.0
浮動小数点の評価を強制する:RAND_MAX + 1
と書いた場合、整数型のオーバーフローの危険があります。
16ビット以上33ビット未満のプラットフォームでもUBを呼び出します。 'RAND_MAX + 1'はすべてのプラットフォームでUBを呼び出す可能性が非常に高いです。 – Olaf
あなたが気にしないなら、私は答えを編集しました。両方とも非常に良い点です。ありがとうございました。 –
'RAND_MAX + 1.0'は' double'型ではありませんか? –
rand
関数は、0とRAND_MAX
の間の値を返します。このプログラムは、RAND_MAX
が2^31 - 1であり、その数値で結果を除算していると仮定しています。
上記の仮定が真であれば、このマクロは[0,1]からの数値を返します。あまり均一なランダム分布ではなく、むしろ「疑似ランダム」値です。
少なくともそれはと思われます。とします。この式(1 << 31)
は、1
の型がint
で、31が左シフトするとint
の範囲外になるため、未定義の動作が発生します(int
は32ビット以下です)。実際には、2の補数表現が使用されている場合、コンパイラによってはこのシフトが許され、次に-1
がそれを範囲に戻しますが、依存することはできません。
(1U << 31)
を使用すると、定義されていない動作を避けることができます。この場合、定数1
はunsigned int
となり、範囲内にシフトします。より良い選択肢は、シフトを忘れて、控除して0x7fffffff
を使用することです。
しかし、最大の移植のために、次のように定義する必要があります。
#define random ((float)rand()/RAND_MAX)
しかし、問題はまだあります。 float
は、通常、23ビットの仮数を有する。 rand
が32ビットの値を返す場合は、適切な数値の分布が得られません。52ビットの仮数を有する活用使用double
:
#define random ((double)rand()/RAND_MAX)
私の推測では、これは単に区間[0,1]上の一様分布から乱数を生成することです。これは正しいです?
コードは決して1.0f
を返すことはありません。
#define random ((float) rand()/(float)((1 << 31) - 1))
には多くの問題があります。弱いコードです。
精度の失われた:標準float
精度の約24ビットを有しています。 rand()
の結果を変換すると、24ビットを超えるとfloat
となり、丸めによって元の値と異なる場合があります。これにより、乱数生成のの均一性が弱められ/破壊されます。異なるrand()
の結果には同じ回答が出てくるでしょう。参照@Olaf
OPが明らかに集合から一様乱数たいとしての修正は問題がある可能性が高い精度所与不可能である[0、1/2,147,483,648、2/2,147,483,648を、.../2,147,483,648 2,147,483,647]制限はfloat
です。
最悪は、int
が少なくとも33ビット長である場合を除き(1 << 31)
が未定義の動作 UBであることです。記号位置に1を移動するのはUBです。 C11dr§6.5.74.
UBを避けるには、((1ul << 31) - 1)
を使用してください。
しかし、マジックナンバー((1ul << 31) - 1)
を使用すると、RAND_MAX
の分数を基準にするほど頑丈ではありません。
さらに(float) ((1ul << 31) - 1)
は、値2147483648.0f
を形成し、入手不可能な2147483647.0f
を形成しないので、上記のように精度が低下する可能性があります。オペレーターのコードは1.0f
を生成することはありません。
OPには[0..1]の結果が必要で、[0..1]は必要ないと思われます。どちらも以下の通りです。
// generate a `double` in the range [0 ... 1)
#define random0to_almost1 (rand()/(RAND_MAX + 1.0))
// or
// generate a `double` in the range [0 ... 1]
#define random0to1 (rand()/(RAND_MAX + 0.0))
これはOPの元のコードのように苦しんでいることを注意double
(標準53ビット)の精度がRAND_MAX
ニーズを超えているべきです。
対処するには、RAND_MAX + 1.0
が正確に行われることを確実にすることです。 では、非常に一般的なが指定されていますが、Cは指定されていません。RAND_MAX
は2のべき乗です_minus_1です。したがってRAND_MAX/2 + 1
はint
であり、正確なの2の累乗です。int
からdouble
への変換は確かに正確なです。
#define random0to_almost1 (rand()/(2.0*(RAND_MAX/2 + 1)))
float
溶液)はせいぜい32ビットを有するないint` `とすべてのプラットフォームで
// This value is platform dependent, but very common
// Do not a a highly portable generation method yet.
#define FLT_POWER2_INTEGER_LIMIT (1ul << 24)
#define random0to_almost1 (\
(rand() % FLT_POWER2_INTEGER_LIMIT)/\
(RAND_MAX % FLT_POWER2_INTEGER_LIMIT + 1.0f) \
)
'FLT_RADIX'が2の累乗でない場合、' int'値の 'double'への変換は正確ではないかもしれません。 –
@Ian Abbottはい - 合意しました。 Cは '2,3,4,5 ...'の 'FLT_RADIX'を許します。私は' 2,10,16'以外の 'FLT_RADIX'にはまだ来ていません。もちろん将来は異なるかもしれません。確かに '2,4,8,16、.. 'の値は上記の答えには問題ではありません。ベース10では、上記の方法を使用しても利点はありますが、_exactness_に達しない可能性があります。今日使用されているベース以外の2台のシステムについて知っていれば、それらのヒアリングに最も興味があります。 – chux
未定義の挙動であろう。何かが起きることがあります。 – Olaf
sizeof(int)== 4の場合、[Is 1 << 31はCで十分に定義されています。](https://stackoverflow.com/questions/45268467/is-131-well-defined-in-c-when- sizeofint-4) –