From: shugo@... (Shugo Maeda) Date: 1998-03-11T01:10:56+09:00 Subject: [ruby-dev:1661] Re: infinity 前田です。 In message "[ruby-dev:1659] Re: [ruby-list:7057] Re: infinity" 石塚圭樹 wrote: |最近, ruby-listでもレベルの高い話しが多くてついていけない(^^;;; ですね、気づいたらなるべく早目にruby-devに移るようにしましょう(^^; |もう一度整理すると | |1. 数学的な無限大を扱いたい |2. FloatのInf/Nanはどうするか? |3. rubyの標準の動作である例外との擦り合わせはどうするか? (snip) |ただし, Inf/Nanがあるとそれなりに結果が出るので, そういうことでも良い |と思う人のために, 例外を出さないモードを用意するというのはどうでしょう |か? デフォルトでFloat.raise_infnan_error == trueということですね。 そうなるように書き直してみましたので、パッチを付けておきます。 # 1.1b9へのパッチです。 |最後に数学的な無限大ですが, Inf/Nanとは別にNumericかRealの下にクラスを |導入して定数として実装するというのはどうでしょう? それで、require 'mathn'すると1 / 0でその無限大定数を返すと良さそうですね。 # あれ、現状だと、 # rbc0> 1 / 0 # # となってしまいますね(^^; -- 前田 修吾 diff -u numeric.c.orig numeric.c --- numeric.c.orig Tue Mar 10 00:49:47 1998 +++ numeric.c Wed Mar 11 00:20:15 1998 @@ -23,6 +23,9 @@ VALUE eZeroDiv; +static VALUE eInfNaN; +static int raise_infnan_error = 1; + ID rb_frame_last_func(); VALUE float_new(); double big2dbl(); @@ -150,11 +153,31 @@ return num; } +static VALUE +float_s_get_raise_infnan_error(recv) + VALUE recv; +{ + return raise_infnan_error?TRUE:FALSE; +} + +static VALUE +float_s_set_raise_infnan_error(recv, val) + VALUE recv, val; +{ + raise_infnan_error = RTEST(val); + return val; +} + VALUE float_new(d) double d; { - NEWOBJ(flt, struct RFloat); + struct RFloat *flt; + + if (raise_infnan_error && (isinf(d) || isnan(d))) + Raise(eInfNaN, "%f", d); + + flt = (struct RFloat*)rb_newobj(); OBJSETUP(flt, cFloat, T_FLOAT); flt->value = d; @@ -168,7 +191,7 @@ char buf[32]; sprintf(buf, "%g", RFLOAT(flt)->value); - if (strchr(buf, '.') == 0) { + if (finite(RFLOAT(flt)->value) && strchr(buf, '.') == 0) { int len = strlen(buf); char *ind = strchr(buf, 'e'); @@ -254,20 +277,12 @@ flo_div(x, y) VALUE x, y; { - INT f_y; - double d; - switch (TYPE(y)) { case T_FIXNUM: - f_y = FIX2INT(y); - if (f_y == 0) num_zerodiv(); - return float_new(RFLOAT(x)->value / (double)f_y); + return float_new(RFLOAT(x)->value / (double)FIX2INT(y)); case T_BIGNUM: - d = big2dbl(y); - if (d == 0.0) num_zerodiv(); - return float_new(RFLOAT(x)->value / d); + return float_new(RFLOAT(x)->value / big2dbl(y)); case T_FLOAT: - if (RFLOAT(y)->value == 0.0) num_zerodiv(); return float_new(RFLOAT(x)->value / RFLOAT(y)->value); default: return num_coerce_bin(x, y); @@ -443,6 +458,37 @@ } static VALUE +flo_is_inf(flt) + VALUE flt; +{ + int ret = isinf(RFLOAT(flt)->value); + if (ret) + return INT2FIX(ret); + else + return FALSE; +} + +static VALUE +flo_is_nan(flt) + VALUE flt; +{ + if (isnan(RFLOAT(flt)->value)) + return TRUE; + else + return FALSE; +} + +static VALUE +flo_is_finite(flt) + VALUE flt; +{ + if (finite(RFLOAT(flt)->value)) + return TRUE; + else + return FALSE; +} + +static VALUE to_integer(val) VALUE val; { @@ -1072,6 +1118,8 @@ void Init_Numeric() { + VALUE Inf, NaN; + coerce = rb_intern("coerce"); to_i = rb_intern("to_i"); @@ -1144,8 +1192,19 @@ rb_define_method(cFixnum, "step", fix_step, 2); rb_define_method(cFixnum, "times", fix_dotimes, 0); + eInfNaN = rb_define_class("InfNaNError", eException); cFloat = rb_define_class("Float", cNumeric); + Inf = float_new(0.0); RFLOAT(Inf)->value = 1.0 / 0.0; + rb_define_const(cFloat, "Inf", Inf); + NaN = float_new(0.0); RFLOAT(NaN)->value = 0.0 / 0.0; + rb_define_const(cFloat, "NaN", NaN); + + rb_define_singleton_method(cFloat, "raise_infnan_error", + float_s_get_raise_infnan_error, 0); + rb_define_singleton_method(cFloat, "raise_infnan_error=", + float_s_set_raise_infnan_error, 1); + rb_undef_method(CLASS_OF(cFloat), "new"); rb_define_method(cFloat, "to_s", flo_to_s, 0); @@ -1164,4 +1223,7 @@ rb_define_method(cFloat, "to_i", flo_to_i, 0); rb_define_method(cFloat, "to_f", flo_to_f, 0); rb_define_method(cFloat, "abs", flo_abs, 0); + rb_define_method(cFloat, "inf?", flo_is_inf, 0); + rb_define_method(cFloat, "nan?", flo_is_nan, 0); + rb_define_method(cFloat, "finite?", flo_is_finite, 0); }