ここでの問題は、float変数 ( ) を使用しているのに、それを定数 ( )gapと比較していることです。定数は、特に指定がない限り、C の浮動小数点定数は double であるためです。double0.00002double
根本的な問題は、数値がまたは0.00002で表現できないことです。(1/3 の 10 進展開のように、2 進展開は無限に長いため、2 進浮動小数点ではまったく表現できません。) したがって、プログラムを記述すると、C コンパイラは に非常に近い値に置き換えます。同様に、数値を変数に読み込むと、に非常に近い値に置き換えられます。数値は よりもビット数が多いため、値は よりも値に近くなります。floatdouble0.00002double0.00002scanf0.00002floatfloat0.00002doublefloatsdouble0.00002float
精度の異なる 2 つの浮動小数点値を比較すると、コンパイラは精度の低い値を正確に同じ値に変換し、精度を高めます。( として表現可能なdouble値の集合は、 として表現可能な値の集合のスーパーセットであるため、 aの値と同じ値を持つfloata を常に見つけることができます。) そして、が実行されるとこうなります:は に変換されます。同じ値であり、それが double (close to) と比較されます。これらの値はどちらも実際には 0.00002 よりわずかに小さく、 の方が近いため、は より小さくなります。doublefloatgap < 0.00002gapdouble0.00002doublefloatdouble
この問題は、いくつかの方法で解決できます。まず、 a を作成してフォーマットをに変更するか、 gapaと比較することで、変換を回避できます。doublescanf%lfgapfloat
while (gap < 0.00002F || gap > 0.99999F) {
しかし、いくつかの理由から、それは正しくありません。まず、C コンパイラによる浮動小数点変換が標準ライブラリによる変換と同じであるという保証は実際にはありませんscanf(実装定義の方法で選択された、最も近い表現可能な値のすぐ隣にある小さい表現可能な値。」(どちらの値が生成されるかは詳細に指定されていませんscanfが、最も近い表現可能な値であることをお勧めします。) たまたま、gcc( glibcLinux で使用される C コンパイラと標準ライブラリ) どちらも最も近い表現可能な値を生成しますが、他の実装ではしないでください。
とにかく、エラー メッセージによると、値を から の間にする必要が0.00001あり1.00000ます。したがって、テストは正確に次のようにする必要があります。
while (gap <= 0.00001F || gap >= 1.0000F) { ...
gap(あなたがとして保持すると仮定しますfloat。)
上記の解決策のいずれかが機能します。個人的には、比較をより直感的にするためにgapadoubleを作成し、比較を and と比較するように変更し0.00001ます1.0000。
ちなみにE-05接尾辞は「10 の -5 乗」というE意味ですExponent。あなたはそれをたくさん見るでしょう。これは、浮動小数点定数を記述する標準的な方法です。