Project

General

Profile

Feature #4787 ยป each_modulo.patch

mrkn (Kenta Murata), 05/27/2011 01:18 PM

View differences:

numeric.c
3296 3296

  
3297 3297
/*
3298 3298
 *  call-seq:
3299
 *     int.each_modulo(n) -> 
3300
 *
3301
 *  If a block given, enumerates with iterated modulo and returns self.
3302
 *  Otherwise, returns an Enumerator.
3303
 */
3304

  
3305
static VALUE
3306
int_each_modulo(VALUE num, VALUE modulus)
3307
{
3308
    VALUE big_q, qr;
3309
    long q, r, m;
3310

  
3311
    switch (TYPE(modulus)) {
3312
    case T_BIGNUM:
3313
	if (rb_big_cmp(modulus, rb_int2big(1)) <= 0) {
3314
	    goto arg_must_be_lt_1;
3315
	}
3316
	break;
3317

  
3318
    case T_FIXNUM:
3319
	if (FIX2INT(modulus) <= 1) {
3320
arg_must_be_lt_1:
3321
	    rb_raise(rb_eArgError, "argument must be larger than 1");
3322
	}
3323
	break;
3324

  
3325
    default:
3326
	rb_raise(rb_eArgError, "argument must be an Integer (%s)",
3327
		 rb_obj_classname(modulus));
3328
    }
3329

  
3330
    RETURN_ENUMERATOR(num, 1, &modulus);
3331

  
3332
    big_q = num;
3333
    if (TYPE(big_q) == T_BIGNUM) {
3334
	while (TYPE(big_q) == T_BIGNUM) {
3335
	    qr = rb_big_divmod(big_q, modulus);
3336
	    rb_yield(RARRAY_PTR(qr)[1]);
3337
	    big_q = RARRAY_PTR(qr)[0];
3338
	}
3339
    }
3340

  
3341
    q = NUM2INT(big_q);
3342
    switch (TYPE(modulus)) {
3343
    case T_BIGNUM:
3344
	while (q > 0) {
3345
	    qr = rb_big_divmod(rb_int2big(q), modulus);
3346
	    rb_yield(RARRAY_PTR(qr)[1]);
3347
	    q = NUM2INT(RARRAY_PTR(qr)[0]);
3348
	}
3349
	break;
3350

  
3351
    case T_FIXNUM:
3352
	m = FIX2INT(modulus);
3353
	while (q > 0) {
3354
	    fixdivmod(q, m, &q, &r);
3355
	    rb_yield(INT2FIX(r));
3356
	}
3357
	break;
3358
    }
3359

  
3360
    return num;
3361
}
3362

  
3363
/*
3364
 *  call-seq:
3299 3365
 *     fix.zero?  ->  true or false
3300 3366
 *
3301 3367
 *  Returns <code>true</code> if <i>fix</i> is zero.
......
3454 3520
    rb_define_method(rb_cInteger, "truncate", int_to_i, 0);
3455 3521
    rb_define_method(rb_cInteger, "round", int_round, -1);
3456 3522

  
3523
    rb_define_method(rb_cInteger, "each_modulo", int_each_modulo, 1);
3524

  
3457 3525
    rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);
3458 3526

  
3459 3527
    rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1);
test/ruby/test_integer.rb
198 198
    assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1))
199 199
    assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class)
200 200
  end
201

  
202
  def test_each_modulo_returns_Enumerator_unless_block_given
203
    assert_instance_of(Enumerator, 1111.each_modulo(10))
204
    assert_instance_of(Enumerator, 1111.each_modulo(2**100))
205
    assert_instance_of(Enumerator, (2**100).each_modulo(10))
206
    assert_instance_of(Enumerator, (2**100).each_modulo(2**100))
207
  end
208

  
209
  def test_each_modulo_calls_block_with_values_of_iterated_modulo
210
    assert_equal([1, 2, 2, 1, 1], 133.each_modulo(3).to_a)
211
    assert_equal([133], 133.each_modulo(2**100).to_a)
212
    assert_equal([1, 2, 1], (2**200).each_modulo(2**100-1).to_a)
213
  end
214

  
215
  def test_each_modulo_raise_ArgumentError_when_arg_le_1
216
    assert_raise(ArgumentError) { 111.each_modulo(1) }
217
    assert_raise(ArgumentError) { 111.each_modulo(0) }
218
    assert_raise(ArgumentError) { 111.each_modulo(-42) }
219
    assert_raise(ArgumentError) { (2**100).each_modulo(1) }
220
    assert_raise(ArgumentError) { (2**100).each_modulo(0) }
221
    assert_raise(ArgumentError) { (2**100).each_modulo(-42) }
222
  end
223

  
224
  def test_each_modulo_raise_ArgumentError_when_arg_not_int
225
    assert_raise(ArgumentError) { 111.each_modulo(Object.new) }
226
    assert_raise(ArgumentError) { 111.each_modulo(1.0) }
227
    assert_raise(ArgumentError) { 111.each_modulo(1.quo(3)) }
228
    assert_raise(ArgumentError) { 111.each_modulo(Complex(1, 1)) }
229
    assert_raise(ArgumentError) { (2**100).each_modulo(Object.new) }
230
    assert_raise(ArgumentError) { (2**100).each_modulo(1.0) }
231
    assert_raise(ArgumentError) { (2**100).each_modulo(1.quo(3)) }
232
    assert_raise(ArgumentError) { (2**100).each_modulo(Complex(1, 1)) }
233
  end
201 234
end