diff options
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 346 |
1 files changed, 160 insertions, 186 deletions
@@ -671,7 +671,7 @@ num_div(VALUE x, VALUE y) * Of the Core and Standard Library classes, * only Rational uses this implementation. * - * For \Rational +r+ and real number +n+, these expressions are equivalent: + * For Rational +r+ and real number +n+, these expressions are equivalent: * * r % n * r-n*(r/n).floor @@ -836,7 +836,7 @@ int_zero_p(VALUE num) if (FIXNUM_P(num)) { return FIXNUM_ZERO_P(num); } - assert(RB_BIGNUM_TYPE_P(num)); + RUBY_ASSERT(RB_BIGNUM_TYPE_P(num)); return rb_bigzero_p(num); } @@ -862,6 +862,8 @@ rb_int_zero_p(VALUE num) * Of the Core and Standard Library classes, * Integer, Float, Rational, and Complex use this implementation. * + * Related: #zero? + * */ static VALUE @@ -948,7 +950,7 @@ num_negative_p(VALUE num) * So you should know its esoteric system. See following: * * - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html - * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#floats_imprecise + * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#-why-are-rubys-floats-imprecise * - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems * * You can create a \Float object explicitly with: @@ -963,7 +965,10 @@ num_negative_p(VALUE num) * * First, what's elsewhere. \Class \Float: * - * - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here]. + * - Inherits from + * {class Numeric}[rdoc-ref:Numeric@What-27s+Here] + * and {class Object}[rdoc-ref:Object@What-27s+Here]. + * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here]. * * Here, class \Float provides methods for: * @@ -999,10 +1004,10 @@ num_negative_p(VALUE num) * - #/: Returns the quotient of +self+ and the given value. * - #ceil: Returns the smallest number greater than or equal to +self+. * - #coerce: Returns a 2-element array containing the given value converted to a \Float - and +self+ + * and +self+ * - #divmod: Returns a 2-element array containing the quotient and remainder * results of dividing +self+ by the given value. - * - #fdiv: Returns the Float result of dividing +self+ by the given value. + * - #fdiv: Returns the \Float result of dividing +self+ by the given value. * - #floor: Returns the greatest number smaller than or equal to +self+. * - #next_float: Returns the next-larger representable \Float. * - #prev_float: Returns the next-smaller representable \Float. @@ -1078,7 +1083,7 @@ flo_to_s(VALUE flt) s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0); if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1; memcpy(buf, p, digs); - xfree(p); + free(p); if (decpt > 0) { if (decpt < digs) { memmove(buf + decpt + 1, buf + decpt, digs - decpt); @@ -1550,8 +1555,8 @@ rb_float_pow(VALUE x, VALUE y) * 1.eql?(Rational(1, 1)) # => false * 1.eql?(Complex(1, 0)) # => false * - * \Method +eql?+ is different from +==+ in that +eql?+ requires matching types, - * while +==+ does not. + * \Method +eql?+ is different from <tt>==</tt> in that +eql?+ requires matching types, + * while <tt>==</tt> does not. * */ @@ -1683,12 +1688,12 @@ rb_dbl_cmp(double a, double b) * Examples: * * 2.0 <=> 2 # => 0 - 2.0 <=> 2.0 # => 0 - 2.0 <=> Rational(2, 1) # => 0 - 2.0 <=> Complex(2, 0) # => 0 - 2.0 <=> 1.9 # => 1 - 2.0 <=> 2.1 # => -1 - 2.0 <=> 'foo' # => nil + * 2.0 <=> 2.0 # => 0 + * 2.0 <=> Rational(2, 1) # => 0 + * 2.0 <=> Complex(2, 0) # => 0 + * 2.0 <=> 1.9 # => 1 + * 2.0 <=> 2.1 # => -1 + * 2.0 <=> 'foo' # => nil * * This is the basis for the tests in the Comparable module. * @@ -2335,7 +2340,7 @@ int_half_p_half_down(VALUE num, VALUE n, VALUE f) } /* - * Assumes num is an Integer, ndigits <= 0 + * Assumes num is an \Integer, ndigits <= 0 */ static VALUE rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode) @@ -2449,7 +2454,7 @@ rb_int_truncate(VALUE num, int ndigits) /* * call-seq: - * round(ndigits = 0, half: :up]) -> integer or float + * round(ndigits = 0, half: :up) -> integer or float * * Returns +self+ rounded to the nearest value with * a precision of +ndigits+ decimal digits. @@ -2834,7 +2839,7 @@ ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl) } if (RTEST(rb_funcall(from, cmp, 1, to))) return INT2FIX(0); result = rb_funcall(rb_funcall(to, '-', 1, from), id_div, 1, step); - if (!excl || RTEST(rb_funcall(rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step)), cmp, 1, to))) { + if (!excl || RTEST(rb_funcall(to, cmp, 1, rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step))))) { result = rb_funcall(result, '+', 1, INT2FIX(1)); } return result; @@ -2946,88 +2951,88 @@ num_step_size(VALUE from, VALUE args, VALUE eobj) * step(by: , to: nil) {|n| ... } -> self * step(by: , to: nil) -> enumerator * - * Generates a sequence of numbers; with a block given, traverses the sequence. + * Generates a sequence of numbers; with a block given, traverses the sequence. * - * Of the Core and Standard Library classes, - * Integer, Float, and Rational use this implementation. - * - * A quick example: - * - * squares = [] - * 1.step(by: 2, to: 10) {|i| squares.push(i*i) } - * squares # => [1, 9, 25, 49, 81] - * - * The generated sequence: - * - * - Begins with +self+. - * - Continues at intervals of +step+ (which may not be zero). - * - Ends with the last number that is within or equal to +limit+; - * that is, less than or equal to +limit+ if +step+ is positive, - * greater than or equal to +limit+ if +step+ is negative. - * If +limit+ is not given, the sequence is of infinite length. - * - * If a block is given, calls the block with each number in the sequence; - * returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence. - * - * <b>Keyword Arguments</b> - * - * With keyword arguments +by+ and +to+, - * their values (or defaults) determine the step and limit: - * - * # Both keywords given. - * squares = [] - * 4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4 - * squares # => [16, 36, 64, 100] - * cubes = [] - * 3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3 - * cubes # => [27.0, 3.375, 0.0, -3.375, -27.0] - * squares = [] - * 1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) } - * squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0] - * - * squares = [] - * Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) } - * squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0] - * - * # Only keyword to given. - * squares = [] - * 4.step(to: 10) {|i| squares.push(i*i) } # => 4 - * squares # => [16, 25, 36, 49, 64, 81, 100] - * # Only by given. - * - * # Only keyword by given - * squares = [] - * 4.step(by:2) {|i| squares.push(i*i); break if i > 10 } - * squares # => [16, 36, 64, 100, 144] - * - * # No block given. - * e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3)) - * e.class # => Enumerator::ArithmeticSequence - * - * <b>Positional Arguments</b> - * - * With optional positional arguments +limit+ and +step+, - * their values (or defaults) determine the step and limit: - * - * squares = [] - * 4.step(10, 2) {|i| squares.push(i*i) } # => 4 - * squares # => [16, 36, 64, 100] - * squares = [] - * 4.step(10) {|i| squares.push(i*i) } - * squares # => [16, 25, 36, 49, 64, 81, 100] - * squares = [] - * 4.step {|i| squares.push(i*i); break if i > 10 } # => nil - * squares # => [16, 25, 36, 49, 64, 81, 100, 121] + * Of the Core and Standard Library classes, + * Integer, Float, and Rational use this implementation. + * + * A quick example: + * + * squares = [] + * 1.step(by: 2, to: 10) {|i| squares.push(i*i) } + * squares # => [1, 9, 25, 49, 81] + * + * The generated sequence: + * + * - Begins with +self+. + * - Continues at intervals of +by+ (which may not be zero). + * - Ends with the last number that is within or equal to +to+; + * that is, less than or equal to +to+ if +by+ is positive, + * greater than or equal to +to+ if +by+ is negative. + * If +to+ is +nil+, the sequence is of infinite length. + * + * If a block is given, calls the block with each number in the sequence; + * returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence. + * + * <b>Keyword Arguments</b> + * + * With keyword arguments +by+ and +to+, + * their values (or defaults) determine the step and limit: + * + * # Both keywords given. + * squares = [] + * 4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4 + * squares # => [16, 36, 64, 100] + * cubes = [] + * 3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3 + * cubes # => [27.0, 3.375, 0.0, -3.375, -27.0] + * squares = [] + * 1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) } + * squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0] + * + * squares = [] + * Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) } + * squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0] + * + * # Only keyword to given. + * squares = [] + * 4.step(to: 10) {|i| squares.push(i*i) } # => 4 + * squares # => [16, 25, 36, 49, 64, 81, 100] + * # Only by given. + * + * # Only keyword by given + * squares = [] + * 4.step(by:2) {|i| squares.push(i*i); break if i > 10 } + * squares # => [16, 36, 64, 100, 144] + * + * # No block given. + * e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3)) + * e.class # => Enumerator::ArithmeticSequence + * + * <b>Positional Arguments</b> + * + * With optional positional arguments +to+ and +by+, + * their values (or defaults) determine the step and limit: + * + * squares = [] + * 4.step(10, 2) {|i| squares.push(i*i) } # => 4 + * squares # => [16, 36, 64, 100] + * squares = [] + * 4.step(10) {|i| squares.push(i*i) } + * squares # => [16, 25, 36, 49, 64, 81, 100] + * squares = [] + * 4.step {|i| squares.push(i*i); break if i > 10 } # => nil + * squares # => [16, 25, 36, 49, 64, 81, 100, 121] * * <b>Implementation Notes</b> * - * If all the arguments are integers, the loop operates using an integer - * counter. + * If all the arguments are integers, the loop operates using an integer + * counter. * - * If any of the arguments are floating point numbers, all are converted - * to floats, and the loop is executed - * <i>floor(n + n*Float::EPSILON) + 1</i> times, - * where <i>n = (limit - self)/step</i>. + * If any of the arguments are floating point numbers, all are converted + * to floats, and the loop is executed + * <i>floor(n + n*Float::EPSILON) + 1</i> times, + * where <i>n = (limit - self)/step</i>. * */ @@ -3210,7 +3215,7 @@ rb_num2ulong(VALUE val) void rb_out_of_int(SIGNED_VALUE num) { - rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `int'", + rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to 'int'", num, num < 0 ? "small" : "big"); } @@ -3229,12 +3234,12 @@ check_uint(unsigned long num, int sign) if (sign) { /* minus */ if (num < (unsigned long)INT_MIN) - rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned int'", (long)num); + rb_raise(rb_eRangeError, "integer %ld too small to convert to 'unsigned int'", (long)num); } else { /* plus */ if (UINT_MAX < num) - rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned int'", num); + rb_raise(rb_eRangeError, "integer %lu too big to convert to 'unsigned int'", num); } } @@ -3309,7 +3314,7 @@ NORETURN(static void rb_out_of_short(SIGNED_VALUE num)); static void rb_out_of_short(SIGNED_VALUE num) { - rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `short'", + rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to 'short'", num, num < 0 ? "small" : "big"); } @@ -3327,12 +3332,12 @@ check_ushort(unsigned long num, int sign) if (sign) { /* minus */ if (num < (unsigned long)SHRT_MIN) - rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned short'", (long)num); + rb_raise(rb_eRangeError, "integer %ld too small to convert to 'unsigned short'", (long)num); } else { /* plus */ if (USHRT_MAX < num) - rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned short'", num); + rb_raise(rb_eRangeError, "integer %lu too big to convert to 'unsigned short'", num); } } @@ -3488,7 +3493,10 @@ rb_num2ull(VALUE val) * * First, what's elsewhere. \Class \Integer: * - * - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here]. + * - Inherits from + * {class Numeric}[rdoc-ref:Numeric@What-27s+Here] + * and {class Object}[rdoc-ref:Object@What-27s+Here]. + * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here]. * * Here, class \Integer provides methods for: * @@ -3568,7 +3576,7 @@ rb_int_odd_p(VALUE num) return RBOOL(num & 2); } else { - assert(RB_BIGNUM_TYPE_P(num)); + RUBY_ASSERT(RB_BIGNUM_TYPE_P(num)); return rb_big_odd_p(num); } } @@ -3580,7 +3588,7 @@ int_even_p(VALUE num) return RBOOL((num & 2) == 0); } else { - assert(RB_BIGNUM_TYPE_P(num)); + RUBY_ASSERT(RB_BIGNUM_TYPE_P(num)); return rb_big_even_p(num); } } @@ -3837,7 +3845,7 @@ rb_int_uminus(VALUE num) return fix_uminus(num); } else { - assert(RB_BIGNUM_TYPE_P(num)); + RUBY_ASSERT(RB_BIGNUM_TYPE_P(num)); return rb_big_uminus(num); } } @@ -4096,7 +4104,13 @@ static double fix_fdiv_double(VALUE x, VALUE y) { if (FIXNUM_P(y)) { - return double_div_double(FIX2LONG(x), FIX2LONG(y)); + long iy = FIX2LONG(y); +#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG + if ((iy < 0 ? -iy : iy) >= (1L << DBL_MANT_DIG)) { + return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy)); + } +#endif + return double_div_double(FIX2LONG(x), iy); } else if (RB_BIGNUM_TYPE_P(y)) { return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y); @@ -4114,7 +4128,7 @@ rb_int_fdiv_double(VALUE x, VALUE y) { if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) { VALUE gcd = rb_gcd(x, y); - if (!FIXNUM_ZERO_P(gcd)) { + if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) { x = rb_int_idiv(x, gcd); y = rb_int_idiv(y, gcd); } @@ -4236,14 +4250,14 @@ fix_idiv(VALUE x, VALUE y) * Performs integer division; returns the integer result of dividing +self+ * by +numeric+: * - * 4.div(3) # => 1 - * 4.div(-3) # => -2 - * -4.div(3) # => -2 - * -4.div(-3) # => 1 - * 4.div(3.0) # => 1 - * 4.div(Rational(3, 1)) # => 1 + * 4.div(3) # => 1 + * 4.div(-3) # => -2 + * -4.div(3) # => -2 + * -4.div(-3) # => 1 + * 4.div(3.0) # => 1 + * 4.div(Rational(3, 1)) # => 1 * - * Raises an exception if +numeric+ does not have method +div+. + * Raises an exception if +numeric+ does not have method +div+. * */ @@ -4347,7 +4361,7 @@ int_remainder(VALUE x, VALUE y) if (FIXNUM_P(x)) { if (FIXNUM_P(y)) { VALUE z = fix_mod(x, y); - assert(FIXNUM_P(z)); + RUBY_ASSERT(FIXNUM_P(z)); if (z != INT2FIX(0) && (SIGNED_VALUE)(x ^ y) < 0) z = fix_minus(z, y); return z; @@ -4697,7 +4711,7 @@ rb_int_cmp(VALUE x, VALUE y) return rb_big_cmp(x, y); } else { - rb_raise(rb_eNotImpError, "need to define `<=>' in %s", rb_obj_classname(x)); + rb_raise(rb_eNotImpError, "need to define '<=>' in %s", rb_obj_classname(x)); } } @@ -5157,7 +5171,7 @@ fix_rshift(long val, unsigned long i) * */ -static VALUE +VALUE rb_int_rshift(VALUE x, VALUE y) { if (FIXNUM_P(x)) { @@ -5339,7 +5353,7 @@ int_aref(int const argc, VALUE * const argv, VALUE const num) * 1.to_f # => 1.0 * -1.to_f # => -1.0 * - * If the value of +self+ does not fit in a \Float, + * If the value of +self+ does not fit in a Float, * the result is infinity: * * (10**400).to_f # => Infinity @@ -5432,7 +5446,7 @@ rb_fix_digits(VALUE fix, long base) VALUE digits; long x = FIX2LONG(fix); - assert(x >= 0); + RUBY_ASSERT(x >= 0); if (base < 2) rb_raise(rb_eArgError, "invalid radix %ld", base); @@ -5441,11 +5455,12 @@ rb_fix_digits(VALUE fix, long base) return rb_ary_new_from_args(1, INT2FIX(0)); digits = rb_ary_new(); - while (x > 0) { + while (x >= base) { long q = x % base; rb_ary_push(digits, LONG2NUM(q)); x /= base; } + rb_ary_push(digits, LONG2NUM(x)); return digits; } @@ -5455,7 +5470,7 @@ rb_int_digits_bigbase(VALUE num, VALUE base) { VALUE digits, bases; - assert(!rb_num_negative_p(num)); + RUBY_ASSERT(!rb_num_negative_p(num)); if (RB_BIGNUM_TYPE_P(base)) base = rb_big_norm(base); @@ -5655,53 +5670,7 @@ int_downto(VALUE from, VALUE to) static VALUE int_dotimes_size(VALUE num, VALUE args, VALUE eobj) { - if (FIXNUM_P(num)) { - if (NUM2LONG(num) <= 0) return INT2FIX(0); - } - else { - if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) return INT2FIX(0); - } - return num; -} - -/* - * call-seq: - * times {|i| ... } -> self - * times -> enumerator - * - * Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>: - * - * a = [] - * 5.times {|i| a.push(i) } # => 5 - * a # => [0, 1, 2, 3, 4] - * - * With no block given, returns an Enumerator. - * - */ - -static VALUE -int_dotimes(VALUE num) -{ - RETURN_SIZED_ENUMERATOR(num, 0, 0, int_dotimes_size); - - if (FIXNUM_P(num)) { - long i, end; - - end = FIX2LONG(num); - for (i=0; i<end; i++) { - rb_yield_1(LONG2FIX(i)); - } - } - else { - VALUE i = INT2FIX(0); - - for (;;) { - if (!RTEST(int_le(i, num))) break; - rb_yield(i); - i = rb_int_plus(i, INT2FIX(1)); - } - } - return num; + return int_neg_p(num) ? INT2FIX(0) : num; } /* @@ -6032,9 +6001,9 @@ int_s_try_convert(VALUE self, VALUE num) /* * Document-class: Numeric * - * Numeric is the class from which all higher-level numeric classes should inherit. + * \Numeric is the class from which all higher-level numeric classes should inherit. * - * Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as + * \Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as * Integer are implemented as immediates, which means that each Integer is a single immutable * object which is always passed by value. * @@ -6048,9 +6017,9 @@ int_s_try_convert(VALUE self, VALUE num) * 1.dup #=> 1 * 1.object_id == 1.dup.object_id #=> true * - * For this reason, Numeric should be used when defining other numeric classes. + * For this reason, \Numeric should be used when defining other numeric classes. * - * Classes which inherit from Numeric must implement +coerce+, which returns a two-member + * Classes which inherit from \Numeric must implement +coerce+, which returns a two-member * Array containing an object that has been coerced into an instance of the new class * and +self+ (see #coerce). * @@ -6243,7 +6212,6 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "nobits?", int_nobits_p, 1); rb_define_method(rb_cInteger, "upto", int_upto, 1); rb_define_method(rb_cInteger, "downto", int_downto, 1); - rb_define_method(rb_cInteger, "times", int_dotimes, 0); rb_define_method(rb_cInteger, "succ", int_succ, 0); rb_define_method(rb_cInteger, "next", int_succ, 0); rb_define_method(rb_cInteger, "pred", int_pred, 0); @@ -6286,19 +6254,25 @@ Init_Numeric(void) rb_define_method(rb_cInteger, "digits", rb_int_digits, -1); - rb_fix_to_s_static[0] = rb_fstring_literal("0"); - rb_fix_to_s_static[1] = rb_fstring_literal("1"); - rb_fix_to_s_static[2] = rb_fstring_literal("2"); - rb_fix_to_s_static[3] = rb_fstring_literal("3"); - rb_fix_to_s_static[4] = rb_fstring_literal("4"); - rb_fix_to_s_static[5] = rb_fstring_literal("5"); - rb_fix_to_s_static[6] = rb_fstring_literal("6"); - rb_fix_to_s_static[7] = rb_fstring_literal("7"); - rb_fix_to_s_static[8] = rb_fstring_literal("8"); - rb_fix_to_s_static[9] = rb_fstring_literal("9"); - for(int i = 0; i < 10; i++) { - rb_gc_register_mark_object(rb_fix_to_s_static[i]); - } +#define fix_to_s_static(n) do { \ + VALUE lit = rb_fstring_literal(#n); \ + rb_fix_to_s_static[n] = lit; \ + rb_vm_register_global_object(lit); \ + RB_GC_GUARD(lit); \ + } while (0) + + fix_to_s_static(0); + fix_to_s_static(1); + fix_to_s_static(2); + fix_to_s_static(3); + fix_to_s_static(4); + fix_to_s_static(5); + fix_to_s_static(6); + fix_to_s_static(7); + fix_to_s_static(8); + fix_to_s_static(9); + +#undef fix_to_s_static rb_cFloat = rb_define_class("Float", rb_cNumeric); |