成瀬です。

(2009/12/27 1:39), Yukihiro Matsumoto wrote:
> まつもと ゆきひろです
> 
> In message "Re: [ruby-list:46707] Re: Float::INFINITY"
>     on Fri, 25 Dec 2009 23:22:13 +0900, "NARUSE, Yui" <naruse / airemix.jp> writes:
> 
> |IEEE754 を仮定するならば、+infinity と -infinity のバイナリ表現が
> |決まっているので、無理矢理作ればいいんじゃないですか。
> |http://babbage.cs.qc.edu/courses/cs341/IEEE-754references.html
> 
> それはありえますね。ただ、実質的にIEEE754を仮定せざるをえない
> のはわかっているのですが、なかなかそこまで踏み込めない私が居
> ます。

このパッチで本当に仮定しているのは IEEE754 ではなく、
「そのプラットフォームに infinity が存在する事」ですので、
実際には必ずしも IEEE754 準拠である必要はありません。
IEEE754 準拠ならば必ず存在すると言うだけの話です。

もし、IEEE754 に準拠していなくても、そのプラットフォームに合わせて、
バイト列を変更すれば infinity を作り出す事が出来ます。
ポータブルな方法がないならば、プラットフォームごとにがんばればいい、
というのがこのパッチの趣旨です。

で、Psychs さんから Middle Endian というものが存在するという指摘を受け、
そのような一部の変態環境では先のパッチでは対応しづらいので、
後述の通り変更します。
これならば、以下の 2 つさえ満たせばどの環境でも対応可能なはずです。
* コンパイル時と実行時のエンディアンが同じ
* そのプラットフォームに double の infinity が存在する

> |ところで、SVID3 や SVR4、C90、VC 2003 あたりの時点では少なくとも
> |HUGE_VAL が入っていてかつ、
> |Ruby の Float の内部表現は double なので HUGE_VAL で
> |特に問題がないと思うのですが、なんでこれじゃダメなんですか?
> 
> C90の範囲では、HUGE_VALはオーバーフロー値で、かならずしも無限
> とは定義されてなかったように思うのですが、勘違いですか?

オーバーフロー値でも、無限かのように振る舞えば問題ない、
と思っていたのですが、akr さんに HUGE_VAL が DBL_MAX として
定義される環境の存在を指摘されたので、HUGE_VAL はダメでした。

diff --git a/numeric.c b/numeric.c
index 11d67fe..8dee37b 100644
--- a/numeric.c
+++ b/numeric.c
@@ -62,6 +62,17 @@
 #ifndef DBL_EPSILON
 #define DBL_EPSILON 2.2204460492503131e-16
 #endif
+union rb_double_u {
+    unsigned char ucs[sizeof(double)];
+    double d;
+};
+const union rb_double_u rb_infinity = {
+#if BYTE_ORDER == LITTLE_ENDIAN
+    {0, 0, 0, 0, 0, 0, 0xf0, 0x7f}
+#else
+    {0x7f, 0xf0, 0, 0, 0, 0, 0, 0}
+#endif
+};

 extern double round(double);

@@ -3305,6 +3316,7 @@ Init_Numeric(void)
     rb_define_const(rb_cFloat, "MIN", DBL2NUM(DBL_MIN));
     rb_define_const(rb_cFloat, "MAX", DBL2NUM(DBL_MAX));
     rb_define_const(rb_cFloat, "EPSILON", DBL2NUM(DBL_EPSILON));
+    rb_define_const(rb_cFloat, "INFINITY", DBL2NUM(rb_infinity.d));

     rb_define_method(rb_cFloat, "to_s", flo_to_s, 0);
     rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);

-- 
NARUSE, Yui  <naruse / airemix.jp>