diff --git a/numeric.c b/numeric.c
index a02dfd3..05f0514 100644
--- a/numeric.c
+++ b/numeric.c
@@ -3296,6 +3296,72 @@ int_round(int argc, VALUE* argv, VALUE num)
/*
* call-seq:
+ * int.each_modulo(n) ->
+ *
+ * If a block given, enumerates with iterated modulo and returns self.
+ * Otherwise, returns an Enumerator.
+ */
+
+static VALUE
+int_each_modulo(VALUE num, VALUE modulus)
+{
+ VALUE big_q, qr;
+ long q, r, m;
+
+ switch (TYPE(modulus)) {
+ case T_BIGNUM:
+ if (rb_big_cmp(modulus, rb_int2big(1)) <= 0) {
+ goto arg_must_be_lt_1;
+ }
+ break;
+
+ case T_FIXNUM:
+ if (FIX2INT(modulus) <= 1) {
+arg_must_be_lt_1:
+ rb_raise(rb_eArgError, "argument must be larger than 1");
+ }
+ break;
+
+ default:
+ rb_raise(rb_eArgError, "argument must be an Integer (%s)",
+ rb_obj_classname(modulus));
+ }
+
+ RETURN_ENUMERATOR(num, 1, &modulus);
+
+ big_q = num;
+ if (TYPE(big_q) == T_BIGNUM) {
+ while (TYPE(big_q) == T_BIGNUM) {
+ qr = rb_big_divmod(big_q, modulus);
+ rb_yield(RARRAY_PTR(qr)[1]);
+ big_q = RARRAY_PTR(qr)[0];
+ }
+ }
+
+ q = NUM2INT(big_q);
+ switch (TYPE(modulus)) {
+ case T_BIGNUM:
+ while (q > 0) {
+ qr = rb_big_divmod(rb_int2big(q), modulus);
+ rb_yield(RARRAY_PTR(qr)[1]);
+ q = NUM2INT(RARRAY_PTR(qr)[0]);
+ }
+ break;
+
+ case T_FIXNUM:
+ m = FIX2INT(modulus);
+ while (q > 0) {
+ fixdivmod(q, m, &q, &r);
+ rb_yield(INT2FIX(r));
+ }
+ break;
+ }
+
+ return num;
+}
+
+/*
+ * call-seq:
* fix.zero? -> true or false
*
* Returns true
if fix is zero.
@@ -3454,6 +3520,8 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "truncate", int_to_i, 0);
rb_define_method(rb_cInteger, "round", int_round, -1);
+ rb_define_method(rb_cInteger, "each_modulo", int_each_modulo, 1);
+
rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);
rb_define_method(rb_cFixnum, "to_s", fix_to_s, -1);
diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb
index 7f8212e..2686382 100644
--- a/test/ruby/test_integer.rb
+++ b/test/ruby/test_integer.rb
@@ -198,4 +198,37 @@ class TestInteger < Test::Unit::TestCase
assert_equal(-1111_1111_1111_1111_1111_1111_1111_1110, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1))
assert_equal(Bignum, (-1111_1111_1111_1111_1111_1111_1111_1111).round(-1).class)
end
+
+ def test_each_modulo_returns_Enumerator_unless_block_given
+ assert_instance_of(Enumerator, 1111.each_modulo(10))
+ assert_instance_of(Enumerator, 1111.each_modulo(2**100))
+ assert_instance_of(Enumerator, (2**100).each_modulo(10))
+ assert_instance_of(Enumerator, (2**100).each_modulo(2**100))
+ end
+
+ def test_each_modulo_calls_block_with_values_of_iterated_modulo
+ assert_equal([1, 2, 2, 1, 1], 133.each_modulo(3).to_a)
+ assert_equal([133], 133.each_modulo(2**100).to_a)
+ assert_equal([1, 2, 1], (2**200).each_modulo(2**100-1).to_a)
+ end
+
+ def test_each_modulo_raise_ArgumentError_when_arg_le_1
+ assert_raise(ArgumentError) { 111.each_modulo(1) }
+ assert_raise(ArgumentError) { 111.each_modulo(0) }
+ assert_raise(ArgumentError) { 111.each_modulo(-42) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(1) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(0) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(-42) }
+ end
+
+ def test_each_modulo_raise_ArgumentError_when_arg_not_int
+ assert_raise(ArgumentError) { 111.each_modulo(Object.new) }
+ assert_raise(ArgumentError) { 111.each_modulo(1.0) }
+ assert_raise(ArgumentError) { 111.each_modulo(1.quo(3)) }
+ assert_raise(ArgumentError) { 111.each_modulo(Complex(1, 1)) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(Object.new) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(1.0) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(1.quo(3)) }
+ assert_raise(ArgumentError) { (2**100).each_modulo(Complex(1, 1)) }
+ end
end