2

私はCに比較的慣れていないということもできますが、質問について明確にする必要があります。数値を表すchar[]があります。このchar[]がLONG_MAXよりも長い場合は、長すぎることをユーザーに伝えたいと思います。問題は、その値をfloatと比較すると、切り捨てられることです。これが私の言いたいことです。

int main(int argc, char ** argv) {

  char str[] = argv[1]; /* I set it to 9223372036854775809, only +1 higher than LONG_MAX */ 
  double l = atof(str); 
  double j = LONG_MAX; 

  printf("%lf\n", l); /* This prints 9223372036854775808.000000, which is LONG_MAX ??? WHY?? */
  printf("%lf\n", j); /* This prints same as above, 9223372036854775808.000000 */ 

  printf("%s\n", l > j ? "true" : "false"); /* false */

  return 0; /* what am I doing wrong? */

}

アップデート:

私はあなたのiretソリューションを試しましたが、それでも同じ丸めの問題が発生します

 j = LONG_MAX; 
  int iret = sscanf (str, "%lf", &l);
  if (iret != 1)
    return 0; /* conversion was bad */
  else {
    if (l > j || l < -(j))
      return 0; /* too small or too large */
  }

  printf("%lf\n", l); 
  printf("%lf\n", j);

  printf("%s\n", l > j ? "true" : "false");
4

4 に答える 4

1

でオーバーフローを簡単にチェックできますstrtolが、少し余分な作業が必要です。

const char *str = ...;
char *e;
long x;

errno = 0;
x = strtol(str, &e, 0);
if (!*str || *e) {
    fprintf(stderr, "invalid number: %s\n", str);
    exit(1);
}
if ((x == LONG_MAX || x == LONG_MIN) && errno == ERANGE) {
    fprintf(stderr, "number too large: %s\n", str);
    exit(1);
}

strtodそれでは、 (またはatof、の壊れたバージョンである)の問題について話しましょうstrtod

に変換する9223372036854775809と、double正しいです。Aの精度は53ビットで、64ビットの精度は64ビットです。浮動小数点数の操作を開始するとすぐに、丸めの準備をする必要があります。9223372036854775808doublelong

たとえば、次のコードには丸め誤差があります。見つけられますか?

double x = 0.1;

脚注:ここでは、64ビットlongとIEEEの倍精度を想定してdoubleいます。

于 2012-10-03T04:36:01.020 に答える
0

atofの「man」ページによると:

http://linux.die.net/man/3/atof

atof()関数は、nptrが指す文字列の最初の部分をdoubleに変換します。... atof()はエラーを検出しません。

そのため、代わりに「sscanf」を使用します。

int iret = sscanf (SOME_TEXT, "%lf", &SOME_DOUBLE);

「iret!= 1」の場合、エラーが発生したことがわかり、適切なアクションを実行できます。

私見では...

PS:

「l」と「j」を宣言してみませんか。いたずらいたずら!FORTRANやBasicでも、常に変数を宣言する必要があります;)

そして、それらをfloat( "%f")またはdouble( "%lf")として宣言してみませんか?

于 2012-10-03T04:06:27.460 に答える
0

両方の入力に対して値「9223372036854775808.000000」を取得する理由は、浮動小数点近似の精度の制限によるものと思います。

ちなみに、値はではありませんLONG_MAXが、LONG_MAX + 1 -> 2^63

定義上、LONG_MAX正確に(整数として)表現するには、63ビットの精度が必要です。ただし、のような64ビット浮動小数点表現ではdouble53ビットの精度しかありません。これは、他のビットが符号と指数を格納するために必要なためです。そのため、とは両方LONG_MAXLONG_MAX + 2丸められてしまい9223372036854775808 <=> 2^63ます。

このケースを適切に処理するstrtolには、入力が範囲外の場合にエラーコードが設定されることを確認してください。

于 2012-10-03T04:35:45.040 に答える
0

あなたのロングは63ビットのようです。フロートには23ビット(または先頭に1が付いた24ビット)があります。ロングは上位24ビットでまったく同じです。だから彼らは同じになります。浮動小数点数は基本的に仮数*2^指数です。指数は、大きさがまだ一致していることを確認します。しかし、仮数は23ビットしかありません。したがって、top23bitsoflong * 2 ^(numberofremainingbits)になります。これは、先行するものと指数バイアスを無視して少し単純化されています。

于 2012-10-04T04:48:38.283 に答える