diff options
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 115 |
1 files changed, 93 insertions, 22 deletions
@@ -6,13 +6,16 @@ $Date$ created at: Fri Aug 13 18:33:09 JST 1993 - Copyright (C) 1993-1998 Yukihiro Matsumoto + Copyright (C) 1993-1999 Yukihiro Matsumoto ************************************************/ #include "ruby.h" #include <math.h> #include <stdio.h> +#ifdef __FreeBSD__ +#include <floatingpoint.h> +#endif static ID coerce; static ID to_i; @@ -22,7 +25,8 @@ VALUE rb_cFloat; VALUE rb_cInteger; VALUE rb_cFixnum; -VALUE rb_eZeroDiv; +VALUE rb_eZeroDivError; +VALUE rb_eFloatDomainError; ID rb_frame_last_func(); VALUE rb_float_new(); @@ -31,7 +35,7 @@ double rb_big2dbl(); void rb_num_zerodiv() { - rb_raise(rb_eZeroDiv, "divided by 0"); + rb_raise(rb_eZeroDivError, "divided by 0"); } static VALUE @@ -183,10 +187,19 @@ static VALUE flo_to_s(flt) VALUE flt; { - char buf[32]; - - sprintf(buf, "%g", RFLOAT(flt)->value); - if (strchr(buf, '.') == 0) { + char buf[24]; + char *s; + double value = RFLOAT(flt)->value; + + if (isinf(value)) + return rb_str_new2(value < 0 ? "-Infinity" : "Infinity"); + else if(isnan(value)) + return rb_str_new2("NaN"); + else + sprintf(buf, "%-.10g", value); + if (s = strchr(buf, ' ')) *s = '\0'; + s = buf; if (s[0] == '-') s++; + if (strchr(s, '.') == 0) { int len = strlen(buf); char *ind = strchr(buf, 'e'); @@ -274,14 +287,11 @@ flo_div(x, y) switch (TYPE(y)) { case T_FIXNUM: f_y = FIX2LONG(y); - if (f_y == 0) rb_num_zerodiv(); return rb_float_new(RFLOAT(x)->value / (double)f_y); case T_BIGNUM: d = rb_big2dbl(y); - if (d == 0.0) rb_num_zerodiv(); return rb_float_new(RFLOAT(x)->value / d); case T_FLOAT: - if (RFLOAT(y)->value == 0.0) rb_num_zerodiv(); return rb_float_new(RFLOAT(x)->value / RFLOAT(y)->value); default: return rb_num_coerce_bin(x, y); @@ -666,8 +676,12 @@ rb_num2long(val) return (long)(RFLOAT(val)->value); } else { - rb_raise(rb_eTypeError, "float %g out of rang of integer", - RFLOAT(val)->value); + char buf[24]; + char *s; + + sprintf(buf, "%-.10g", RFLOAT(val)->value); + if (s = strchr(buf, ' ')) *s = '\0'; + rb_raise(rb_eTypeError, "float %s out of rang of integer", buf); } case T_BIGNUM: @@ -677,6 +691,11 @@ rb_num2long(val) rb_raise(rb_eTypeError, "no implicit conversion from string"); return Qnil; /* not reached */ + case T_TRUE: + case T_FALSE: + rb_raise(rb_eTypeError, "no implicit conversion from boolean"); + return Qnil; /* not reached */ + default: val = rb_rescue(to_integer, val, fail_to_integer, val); if (!rb_obj_is_kind_of(val, rb_cInteger)) { @@ -704,7 +723,7 @@ rb_num2int(val) long num = rb_num2long(val); if (num < INT_MIN || INT_MAX < num) { - rb_raise(rb_eArgError, "integer %d too big to convert to `int'.", num); + rb_raise(rb_eArgError, "integer %d too big to convert to `int'", num); } return (int)num; } @@ -716,7 +735,7 @@ rb_fix2int(val) long num = FIXNUM_P(val)?FIX2LONG(val):rb_num2long(val); if (num < INT_MIN || INT_MAX < num) { - rb_raise(rb_eArgError, "integer %d too big to convert to `int'.", num); + rb_raise(rb_eArgError, "integer %d too big to convert to `int'", num); } return (int)num; } @@ -778,6 +797,45 @@ int_chr(num) } static VALUE +rb_fix_induced_from(klass, x) + VALUE klass, x; +{ + return rb_num2fix(x); +} + +static VALUE +rb_int_induced_from(klass, x) + VALUE klass, x; +{ + switch (TYPE(x)) { + case T_FIXNUM: + case T_BIGNUM: + return x; + case T_FLOAT: + return rb_funcall(x, rb_intern("to_i"), 0); + default: + rb_raise(rb_eTypeError, "failed to convert %s into Integer", + rb_class2name(CLASS_OF(x))); + } +} + +static VALUE +rb_flo_induced_from(klass, x) + VALUE klass, x; +{ + switch (TYPE(x)) { + case T_FIXNUM: + case T_BIGNUM: + return rb_funcall(x, rb_intern("to_f"), 0); + case T_FLOAT: + return x; + default: + rb_raise(rb_eTypeError, "failed to convert %s into Float", + rb_class2name(CLASS_OF(x))); + } +} + +static VALUE fix_uminus(num) VALUE num; { @@ -797,7 +855,7 @@ rb_fix2str(x, base) else if (base == 8) fmt[2] = 'o'; else rb_fatal("fixnum cannot treat base %d", base); - sprintf(buf, fmt, FIX2LONG(x)); + snprintf(buf, 22, fmt, FIX2LONG(x)); return rb_str_new2(buf); } @@ -940,15 +998,13 @@ fix_pow(x, y) b = FIX2LONG(y); if (b == 0) return INT2FIX(1); + if (b == 1) return x; a = FIX2LONG(x); if (b > 0) { return rb_big_pow(rb_int2big(a), y); } return rb_float_new(pow((double)a, (double)b)); } - else if (NIL_P(y)) { - return INT2FIX(1); - } return rb_num_coerce_bin(x, y); } @@ -1309,20 +1365,23 @@ fix_step(from, to, step) if (!FIXNUM_P(to) || !FIXNUM_P(step)) return int_step(from, to, step); + i = FIX2LONG(from); end = FIX2LONG(to); diff = FIX2LONG(step); if (diff == 0) { rb_raise(rb_eArgError, "step cannot be 0"); } - else if (diff > 0) { - for (i=FIX2LONG(from); i <= end; i+=diff) { + if (diff > 0) { + while (i <= end) { rb_yield(INT2FIX(i)); + i += diff; } } else { - for (i=FIX2LONG(from); i >= end; i+=diff) { + while (i >= end) { rb_yield(INT2FIX(i)); + i += diff; } } return from; @@ -1354,10 +1413,15 @@ fix_zero_p(num) void Init_Numeric() { +#ifdef __FreeBSD__ + /* allow divide by zero -- Inf */ + fpsetmask(fpgetmask() & ~(FP_X_DZ|FP_X_INV|FP_X_OFL)); +#endif coerce = rb_intern("coerce"); to_i = rb_intern("to_i"); - rb_eZeroDiv = rb_define_class("ZeroDivisionError", rb_eStandardError); + rb_eZeroDivError = rb_define_class("ZeroDivisionError", rb_eStandardError); + rb_eFloatDomainError = rb_define_class("FloatDomainError", rb_eStandardError); rb_cNumeric = rb_define_class("Numeric", rb_cObject); rb_include_module(rb_cNumeric, rb_mComparable); @@ -1380,11 +1444,15 @@ Init_Numeric() rb_define_method(rb_cInteger, "downto", int_downto, 1); rb_define_method(rb_cInteger, "step", int_step, 2); rb_define_method(rb_cInteger, "times", int_dotimes, 0); + rb_include_module(rb_cInteger, rb_mPrecision); rb_define_method(rb_cInteger, "succ", int_succ, 0); rb_define_method(rb_cInteger, "next", int_succ, 0); rb_define_method(rb_cInteger, "chr", int_chr, 0); rb_cFixnum = rb_define_class("Fixnum", rb_cInteger); + rb_include_module(rb_cFixnum, rb_mPrecision); + rb_define_singleton_method(rb_cFixnum, "induced_from", rb_fix_induced_from, 1); + rb_define_singleton_method(rb_cInteger, "induced_from", rb_int_induced_from, 1); rb_undef_method(CLASS_OF(rb_cFixnum), "new"); @@ -1437,6 +1505,9 @@ Init_Numeric() rb_undef_method(CLASS_OF(rb_cFloat), "new"); + rb_define_singleton_method(rb_cFloat, "induced_from", rb_flo_induced_from, 1); + rb_include_module(rb_cFloat, rb_mPrecision); + rb_define_method(rb_cFloat, "to_s", flo_to_s, 0); rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); rb_define_method(rb_cFloat, "-@", flo_uminus, 0); |