[ruby-list:46720] Re: Float::INFINITY
From:
"NARUSE, Yui" <naruse@...>
Date:
2009-12-28 14:15:50 UTC
List:
ruby-list #46720
成瀬です。
(2009/12/28 10:20), Shugo Maeda wrote:
> 前田です。
>
> 2009年12月25日16:01 Yukihiro Matsumoto <matz@ruby-lang.org>:
>> |番兵としてInfinity値を使おうと思ったのですが、現在rubyには、
>> |0.0で割るのような方法以外に、例えば組み込みの定数のような、
>> |Infinityな値を得る方法はないのでしょうか?
>> |
>> |検索すると[ruby-dev:4760]というパッチが見つかるのですが。
>>
>> ポータブルにInfinityの値を得る方法がないから、というのが現在
>> の答えです。間違いであれば、喜んで取り込むのですが。最低限、
>> IEEE754 を仮定すれば、ポータブルな方法があるのかしら?
>
> Redmineのコメントで、すでにfix_pow()で以下のようなマクロが使われて
> いるという指摘がありましたが、これについてはどう思われますか?
>
> #define infinite_value() ruby_div0(1.0)
まつもとさんの返事の前ですが、これも置き換えたパッチを作ったので
送っておきます。
commit a2ecbec64bd01142b7d4df81edab1a43ded4fb12
Author: NARUSE, Yui <naruse@ruby-lang.org>
Date: Mon Dec 28 11:52:47 2009 +0900
Add Float::INFINITY and Float::NAN.
* numeric.c (Init_Numeric): Add Float::INFINITY and Float::NAN.
[ruby-dev:1657] [ruby-dev:4760] [ruby-list:7023] [ruby-list:46690]
[ruby-core:26632] [ruby-talk:41352] [ruby-talk:203333]
* include/ruby/defines.h (INFINITY): defined.
* include/ruby/defines.h (NAN): defined.
* include/ruby/util.h (ruby_div0): removed.
* numeric.c (fix_pow): use INFINITY and NAN instead of ruby_div0(1.0).
* marshal.c (r_object0): ditto.
* bignum.c (big_fdiv): ditto.
diff --git a/bignum.c b/bignum.c
index f6fca9f..7489ba5 100644
--- a/bignum.c
+++ b/bignum.c
@@ -2485,7 +2485,7 @@ big_fdiv(VALUE x, VALUE y)
#if SIZEOF_LONG > SIZEOF_INT
{
/* Visual C++ can't be here */
- if (l > INT_MAX) return DBL2NUM(ruby_div0(1.0));
+ if (l > INT_MAX) return DBL2NUM(INFINITY);
if (l < INT_MIN) return DBL2NUM(0.0);
}
#endif
diff --git a/include/ruby/defines.h b/include/ruby/defines.h
index 70b1685..a81aef8 100644
--- a/include/ruby/defines.h
+++ b/include/ruby/defines.h
@@ -99,6 +99,20 @@ void xfree(void*);
# define BDIGIT_DBL_SIGNED long
#endif
+#ifdef INFINITY
+# define HAVE_INFINITY
+#else
+extern const unsigned char rb_infinity[];
+# define INFINITY (*(double *)rb_infinity)
+#endif
+
+#ifdef NAN
+# define HAVE_NAN
+#else
+extern const unsigned char rb_nan[];
+# define NAN (*(double *)rb_nan)
+#endif
+
#ifdef __CYGWIN__
#undef _WIN32
#endif
diff --git a/include/ruby/util.h b/include/ruby/util.h
index 1c52c57..0c1e1c4 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -74,12 +74,6 @@ double ruby_strtod(const char *, char **);
#pragma warning(push)
#pragma warning(disable:4723)
#endif
-static inline double
-ruby_div0(double x)
-{
- double t = 0.0;
- return x / t;
-}
#if defined _MSC_VER && _MSC_VER >= 1300
#pragma warning(pop)
#endif
diff --git a/marshal.c b/marshal.c
index 549a6f6..be33546 100644
--- a/marshal.c
+++ b/marshal.c
@@ -1322,8 +1322,6 @@ obj_alloc_by_path(VALUE path, struct load_arg *arg)
return rb_obj_alloc(klass);
}
-#define div0(x) ruby_div0(x)
-
static int
has_encoding(struct load_arg *arg)
{
@@ -1449,13 +1447,13 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod)
const char *ptr = RSTRING_PTR(str);
if (strcmp(ptr, "nan") == 0) {
- d = div0(0.0);
+ d = NAN;
}
else if (strcmp(ptr, "inf") == 0) {
- d = div0(+1.0);
+ d = INFINITY;
}
else if (strcmp(ptr, "-inf") == 0) {
- d = div0(-1.0);
+ d = -INFINITY;
}
else {
char *e;
diff --git a/numeric.c b/numeric.c
index 11d67fe..319f7b2 100644
--- a/numeric.c
+++ b/numeric.c
@@ -63,6 +63,20 @@
#define DBL_EPSILON 2.2204460492503131e-16
#endif
+#ifdef HAVE_INFINITY
+#elif BYTE_ORDER == LITTLE_ENDIAN
+const unsigned char rb_infinity[] = "\x00\x00\x00\x00\x00\x00\xf0\x7f";
+#else
+const unsigned char rb_infinity[] = "\x7f\xf0\x00\x00\x00\x00\x00\x00";
+#endif
+
+#ifdef HAVE_NAN
+#elif BYTE_ORDER == LITTLE_ENDIAN
+const unsigned char rb_nan[] = "\x00\x00\x00\x00\x00\x00\xf8\x7f";
+#else
+const unsigned char rb_nan[] = "\x7f\xf8\x00\x00\x00\x00\x00\x00";
+#endif
+
extern double round(double);
#ifndef HAVE_ROUND
@@ -2467,8 +2481,6 @@ int_pow(long x, unsigned long y)
return LONG2NUM(z);
}
-#define infinite_value() ruby_div0(1.0)
-
/*
* call-seq:
* fix ** numeric -> numeric_result
@@ -2496,7 +2508,7 @@ fix_pow(VALUE x, VALUE y)
if (b == 1) return x;
if (a == 0) {
if (b > 0) return INT2FIX(0);
- return DBL2NUM(infinite_value());
+ return DBL2NUM(INFINITY);
}
if (a == 1) return INT2FIX(1);
if (a == -1) {
@@ -2524,7 +2536,7 @@ fix_pow(VALUE x, VALUE y)
case T_FLOAT:
if (RFLOAT_VALUE(y) == 0.0) return DBL2NUM(1.0);
if (a == 0) {
- return DBL2NUM(RFLOAT_VALUE(y) < 0 ? infinite_value() : 0.0);
+ return DBL2NUM(RFLOAT_VALUE(y) < 0 ? INFINITY : 0.0);
}
if (a == 1) return DBL2NUM(1.0);
{
@@ -3305,6 +3317,8 @@ 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(INFINITY));
+ rb_define_const(rb_cFloat, "NAN", DBL2NUM(NAN));
rb_define_method(rb_cFloat, "to_s", flo_to_s, 0);
rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);
diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb
index 15e17ad..c18e4f0 100644
--- a/test/ruby/test_float.rb
+++ b/test/ruby/test_float.rb
@@ -24,7 +24,7 @@ class TestFloat < Test::Unit::TestCase
assert_equal(false, (x >= y))
end
def test_nan
- nan = 0.0/0
+ nan = Float::NAN
nan_test(nan, nan)
nan_test(nan, 0)
nan_test(nan, 1)
@@ -118,7 +118,7 @@ class TestFloat < Test::Unit::TestCase
end
def test_to_s
- inf = 1.0 / 0.0
+ inf = Float::INFINITY
assert_equal("Infinity", inf.to_s)
assert_equal("-Infinity", (-inf).to_s)
assert_equal("NaN", (inf / inf).to_s)
@@ -171,7 +171,7 @@ class TestFloat < Test::Unit::TestCase
assert_equal([1.0, 0.0], 2.0.divmod(2.0))
assert_raise(TypeError) { 2.0.divmod(nil) }
- inf = 1.0 / 0.0
+ inf = Float::INFINITY
assert_raise(ZeroDivisionError) {inf.divmod(0)}
a, b = (2.0**32).divmod(1.0)
@@ -186,8 +186,8 @@ class TestFloat < Test::Unit::TestCase
end
def test_eql
- inf = 1.0 / 0.0
- nan = inf / inf
+ inf = Float::INFINITY
+ nan = Float::NAN
assert(1.0.eql?(1.0))
assert(inf.eql?(inf))
assert(!(nan.eql?(nan)))
@@ -200,8 +200,8 @@ class TestFloat < Test::Unit::TestCase
end
def test_cmp
- inf = 1.0 / 0.0
- nan = inf / inf
+ inf = Float::INFINITY
+ nan = Float::NAN
assert_equal(0, 1.0 <=> 1.0)
assert_equal(1, 1.0 <=> 0.0)
assert_equal(-1, 1.0 <=> 2.0)
@@ -232,14 +232,14 @@ class TestFloat < Test::Unit::TestCase
end
def test_infinite_p
- inf = 1.0 / 0.0
+ inf = Float::INFINITY
assert(1, inf.infinite?)
assert(1, (-inf).infinite?)
assert_nil(1.0.infinite?)
end
def test_finite_p
- inf = 1.0 / 0.0
+ inf = Float::INFINITY
assert(!(inf.finite?))
assert(!((-inf).finite?))
assert(1.0.finite?)
@@ -266,7 +266,7 @@ class TestFloat < Test::Unit::TestCase
assert_equal(-2, (-2.0).round)
assert_equal(-2, (-2.0).truncate)
- inf = 1.0/0.0
+ inf = Float::INFINITY
assert_raise(FloatDomainError) { inf.floor }
assert_raise(FloatDomainError) { inf.ceil }
assert_raise(FloatDomainError) { inf.round }
@@ -413,7 +413,7 @@ class TestFloat < Test::Unit::TestCase
assert(Float("1e10_00").infinite?)
assert_raise(TypeError) { Float(nil) }
o = Object.new
- def o.to_f; inf = 1.0/0.0; inf/inf; end
+ def o.to_f; inf = Float::INFINITY; inf/inf; end
assert(Float(o).nan?)
end
--
NARUSE, Yui <naruse@airemix.jp>