えぐち@エスアンドイー です。

>>> 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; +}