えぐち@エスアンドイー です。 >>> On Thu, 11 Feb 1999 06:06:00 +0900, gotoken / math.sci.hokudai.ac.jp (GOTO Kentaro) said: gotoken> ごとけんです gotoken> gotoken> In message "[ruby-dev:4994] Re: compare to NaN (Re: Re: call for finite/isnan testers)" gotoken> on 99/02/11, EGUCHI Osamu <eguchi / shizuokanet.ne.jp> writes: gotoken> gotoken> >えぐち@エスアンドイー です。 gotoken> gotoken> >#finite() の出番なのですが、まだ出演できないのですよね。 gotoken> gotoken> うーん,どうしたもんだか困ってます. gotoken> ぼくもここまで暗黒な世界だとは思ってなかったので (^^;; gotoken> gotoken> 直観的にはえぐちさんの言う gotoken> gotoken> finite(x){ return x != x+1.0; } gotoken> isnan(x){ return x != x; } これですけど、isnan() は考える限り安全ですが、 x != x+1.0 は、1.0e16 ぐらいの小さな数でも無限と判断してしまい 問題がありました。 isinf(x) { return x == x * 1.1 + 1.0 } ビット毎の比較をしないのであれば、このへんが妥当でしょう。 が、いかがわしいですね ^^;;;;; gotoken> が一番ポータビリティがありそうなんですが,WATCOM C では gotoken> NaN を検知してくれないみたいですね. あれ x != x が NaN で真にならないんでしたっけ? #そうすると考えないと、、 gotoken> 1. {finit(),isinf(),isnan()} のうち2つに相当するものが gotoken> あればそれを使う gotoken> 2. さもなくば IEEE754 フォーマットと信じてビット比較をする gotoken> gotoken> が現実的なようです. gotoken> gotoken> ですが,ぼくには configure.in の書き方が分からないので, gotoken> 「10e999.to_i が無限ループになる」ことに対するパッチを gotoken> 上の路線でお願いできませんか?? configure.in と missing/{isinf,isnan,finite}.c をこしらえてみました。 isinf() は 2. に相当しますが isnan() は n != n です。 また rb_dbl2big() に無限/非数対策をしましたので % ./ruby -e '1e999.to_i' /var/tmp//rbX10817:1: warning: Float 1e999 out of range /var/tmp//rbX10817:1:in `to_i': Inifinity (ArgumentError) from /var/tmp//rbX10817:1 % ./ruby -e '-1e999.to_i' /var/tmp//rbk10825:1: warning: Float -1e999 out of range /var/tmp//rbk10825:1:in `to_i': Inifinity (ArgumentError) from /var/tmp//rbk10825:1 % ./ruby -e '(1.0%0.0).to_i' /var/tmp//rbA10824:1:in `to_i': NaN (ArgumentError) from /var/tmp//rbA10824:1 となります。(ArgumentError は妥当でないかも、、) 評価をお願いします。>みんなさま。 (autoconf が必要です。) gotoken> ちなみに,IEEE754 では,double の場合,bigendian 表記で gotoken> gotoken> +Inf 7ff0000000000000 gotoken> -Inf fff0000000000000 gotoken> NaN 7ff????????????? もしくは fff????????????? gotoken> gotoken> ただし,????????????? はすべてが 0 ではない gotoken> gotoken> となってます.その意味では [ruby-dev:4918] の有馬さんの gotoken> 報告によれば WATCOM C でも以下の2関数は,望んだものを gotoken> 返してきています. gotoken> gotoken> double nan1() gotoken> { gotoken> double a,b,c; gotoken> a = 0.0; b = 0.0; c = a/b; gotoken> return c; gotoken> } gotoken> ==> fff80000 00000000 gotoken> gotoken> double inf() gotoken> { gotoken> double a,b,c; gotoken> a = 1.0; b = 0.0; c = a/b; gotoken> return c; gotoken> } gotoken> ==> 7ff00000 00000000 gotoken> gotoken> gotoken> ただし,厳密に規格を解釈するとワード内での位置しか gotoken> 指定していないのでワードの並びとかはあくまで gotoken> プロセッサ依存ではあります. これは memcmp() 的な解決方法で問題ないです。 えぐち
diff --exclude=configure -rudN ../ruby-1.3.1-990210/bignum.c ./bignum.c --- ../ruby-1.3.1-990210/bignum.c Wed Feb 10 17:44:23 1999 +++ ./bignum.c Thu Feb 11 13:11:38 1999 @@ -403,6 +403,13 @@ VALUE z; double u = (d < 0)?-d:d; + if (isinf(d)) { + rb_raise(rb_eArgError, "Inifinity"); + } + if (isnan(d)) { + rb_raise(rb_eArgError, "NaN"); + } + while (!POSFIXABLE(u) || 0 != (long)u) { u /= (double)(BIGRAD); i++; diff --exclude=configure -rudN ../ruby-1.3.1-990210/configure.in ./configure.in --- ../ruby-1.3.1-990210/configure.in Wed Feb 10 14:40:12 1999 +++ ./configure.in Thu Feb 11 13:04:28 1999 @@ -187,7 +187,8 @@ AC_FUNC_VFORK AC_FUNC_MEMCMP AC_REPLACE_FUNCS(dup2 memmove mkdir strcasecmp strerror strftime\ - strchr strstr strtoul strdup crypt flock vsnprintf) + strchr strstr strtoul strdup crypt flock vsnprintf\ + isinf isnan finite) AC_CHECK_FUNCS(fmod killpg drand48 random wait4 waitpid syscall getcwd\ truncate chsize times utimes fcntl lockf setitimer\ setruid seteuid setreuid setrgid setegid setregid\ diff --exclude=configure -rudN ../ruby-1.3.1-990210/missing/finite.c ./missing/finite.c --- ../ruby-1.3.1-990210/missing/finite.c Thu Jan 1 09:00:00 1970 +++ ./missing/finite.c Thu Feb 11 13:03:06 1999 @@ -0,0 +1,6 @@ +int +finite(n) + double n; +{ + return !isnan(n) && !isinf(n); +} diff --exclude=configure -rudN ../ruby-1.3.1-990210/missing/isinf.c ./missing/isinf.c --- ../ruby-1.3.1-990210/missing/isinf.c Thu Jan 1 09:00:00 1970 +++ ./missing/isinf.c Thu Feb 11 13:03:11 1999 @@ -0,0 +1,18 @@ +static double zero() { return 0.0; } +static double one() { return 1.0; } +static double inf() { return one() / zero(); } + +int +isinf(n) + double n; +{ + static double pinf = 0.0; + static double ninf = 0.0; + + if (pinf == 0.0) { + pinf = inf(); + ninf = -pinf; + } + return memcmp(&n, &pinf, sizeof n) == 0 + || memcmp(&n, &ninf, sizeof n) == 0; +} diff --exclude=configure -rudN ../ruby-1.3.1-990210/missing/isnan.c ./missing/isnan.c --- ../ruby-1.3.1-990210/missing/isnan.c Thu Jan 1 09:00:00 1970 +++ ./missing/isnan.c Thu Feb 11 13:03:13 1999 @@ -0,0 +1,6 @@ +int +isnan(n) + double n; +{ + return n != n; +}