14

私は C 標準 (1999 年以降) を調べましたが、それはRAND_MAX少なくとも 32767 であるべきだと言っているだけで、このマクロが signed または unsigned int に展開されるべきかどうかについては何も述べていません。Single UNIX Specification ( link 1link 2 ) と Linux man ( link ) は、明確さを追加していません。

それが返さRAND_MAXれるので、 a であるべきだと思うでしょう。signed intrand()

ただし、一部のコンパイラでは署名なしとして定義されていることがわかりました。

  • 古い Turbo C++ 1.01: #define RAND_MAX 0x7FFFU
  • それほど古くない C++ Builder 5.5: #define RAND_MAX 0x7FFFU
  • まだ生きている Open Watcom C/C++ 1.9: #define RAND_MAX 32767U
  • DJGPP (DOS 用 gcc 3.3.4): #define RAND_MAX 2147483647
  • MinGW (Windows 用 gcc 4.6.2): #define RAND_MAX 0x7FFF
  • MS Visual Studio 2010 (リンク): RAND_MAX は値 0x7fff として定義されます
  • Tiny C コンパイラ 0.9.25: #define RAND_MAX 0x7FFF
  • lcc-win32 3.8: #define RAND_MAX 0x7fff
  • Pelles C 6.50: #define RAND_MAX 0x3fffffffまたは#define RAND_MAX 0x7fff
  • Digital Mars C/C++ 8.52: #define RAND_MAX 32767

これにより、以下のような一見無害なコードが移植不能になり、署名付きから未署名への昇格のために爆発します。

cos(w * t) + (rand() - RAND_MAX / 2) * 0.1 / (RAND_MAX / 2);

rand()signed int[0, RAND_MAX]の範囲でa を返します。

RAND_MAXが として定義されている場合unsigned int、 からの値もrand()に昇格されunsigned intます。

その場合、差は、範囲 [0, - /2] & [ +1- /2, -1](rand() - RAND_MAX / 2)の値を持つ符号なし整数の符号なし差になります。[- /2, - /2] の範囲の値。RAND_MAXRAND_MAXUINT_MAXRAND_MAXUINT_MAXRAND_MAXRAND_MAXRAND_MAX

とにかく、RAND_MAX署名する必要があるようで、ほとんどの(?)コンパイラはそのように定義していますが、署名する必要があると言う信頼できるソースはありますか? 古い規格?K&R? 別の UNIX 仕様ですか?

4

2 に答える 2

7

はい、これは標準の欠陥のようです。

まず、最近ではおそらく誰も.rand()を返すと定義していませんint。意図は明らかに正の数を返すことであり、負の戻り値を使用できるエラー戻り値はありません。そのような関数が今日導入された場合、戻り値の型として符号なし整数型を使用して設計されます。私の推測では、C89 および符号なし整数の概念が言語に導入される前のことです。

次に、明らかに、関数が返す最大値の定義が関数の定義と同じ型を持つことを期待する必要があります。他の場所では、マクロは特定の型の式に展開されるように明確に定義されているため、ここでも可能でした。

あなたの問題に関しては、移植可能なものを持つ最も簡単な方法は、次のようなことをして最初に値を double にスケーリングし、そこからすべての計算を導出する[0, 1)ことだと思います。rand()/(RAND_MAX+1.0)いずれにせよrand()、プラットフォームでより適切な擬似乱数発生器が利用できない場合は、最後の手段としてのみ使用してください。たとえば、POSIX システムでは、rand48ファミリは適切に記述されたプロパティで便利に置き換えられます。

于 2012-05-22T19:35:39.097 に答える
3

答えは、コードが不当な仮定を行っているため、修正する必要があるということです。そのコードが行うべきことは、使用時にキャストRAND_MAX(int)れます。

コンパイラがマクロを署名付きとして定義することは、もう少し理にかなっていRAND_MAXますが、標準では、そうするように要求することを慎重に避けています。そのため、コードが署名されていると盲目的に想定することは、移植性のバグになります。

于 2012-05-24T18:37:49.820 に答える