Project

General

Profile

Feature #14401 » inverse_of_digits.patch

tompng (tomoya ishida), 01/25/2018 12:43 PM

View differences:

numeric.c
5241 5241
    }
5242 5242
}
5243 5243

  
5244
static VALUE
5245
rb_int_s_from_digits(int argc, VALUE *argv, VALUE klass) {
5246
    VALUE digits, base, array;
5247
    long size, levels, level;
5248
    rb_check_arity(argc, 1, 2);
5249
    digits = rb_to_array_type(argv[0]);
5250
    base = argc == 2 ? rb_to_int(argv[1]) : INT2FIX(10);
5251
    if (FIXNUM_P(base) && FIX2LONG(base) < 2)
5252
	rb_raise(rb_eArgError, "invalid radix %ld", FIX2LONG(base));
5253
    else if (RB_TYPE_P(base, T_BIGNUM) && BIGNUM_NEGATIVE_P(base))
5254
	rb_raise(rb_eArgError, "negative radix");
5255
    array = rb_ary_dup(digits);
5256
    size = RARRAY_LEN(array);
5257
    levels = bit_length(size);
5258
    for (level = 0; level < levels; level++) {
5259
	long stride = 2 << level;
5260
	long i, n = (size + stride - 1) / stride;
5261
	if (level) base = rb_int_mul(base, base);
5262
	for (i = 0; i < n; i++) {
5263
	    VALUE div = INT2FIX(0);
5264
	    VALUE mod = rb_to_int(RARRAY_AREF(array, 2 * i));
5265
	    RARRAY_ASET(array, 2 * i, INT2FIX(0));
5266
	    if (2 * i + 1 < size) {
5267
		div = rb_to_int(RARRAY_AREF(array, 2 * i + 1));
5268
		RARRAY_ASET(array, 2 * i + 1, INT2FIX(0));
5269
	    }
5270
	    if (div == INT2FIX(0)) {
5271
		RARRAY_ASET(array, i, mod);
5272
	    } else {
5273
		div = rb_to_int(div);
5274
		RARRAY_ASET(array, i, rb_int_plus(rb_int_mul(div, base), mod));
5275
	    }
5276
	}
5277
    }
5278
    return RARRAY_AREF(array, 0);
5279
}
5280

  
5281

  
5244 5282
/*
5245 5283
 *  Document-class: ZeroDivisionError
5246 5284
 *
......
5393 5431
    rb_undef_alloc_func(rb_cInteger);
5394 5432
    rb_undef_method(CLASS_OF(rb_cInteger), "new");
5395 5433
    rb_define_singleton_method(rb_cInteger, "sqrt", rb_int_s_isqrt, 1);
5434
    rb_define_singleton_method(rb_cInteger, "from_digits", rb_int_s_from_digits, -1);
5396 5435

  
5397 5436
    rb_define_method(rb_cInteger, "to_s", int_to_s, -1);
5398 5437
    rb_define_alias(rb_cInteger, "inspect", "to_s");
test/ruby/test_integer.rb
477 477
    assert_equal([0, 1], 10.digits(o))
478 478
  end
479 479

  
480
  def test_from_digits
481
    assert_equal(Integer.from_digits([0]), 0)
482
    assert_equal(Integer.from_digits([1]), 1)
483
    assert_equal(Integer.from_digits([4, 3, 2, 1]), 1234)
484
    assert_equal(Integer.from_digits([1, 0, 1, 1, 1], 2), 29)
485
    assert_equal(Integer.from_digits((9**999).digits), 9**999)
486
    assert_equal(Integer.from_digits([1, 1, 1], 1 << 128), (1 << 256) | (1 << 128) | 1)
487
    assert_raise(TypeError) { Integer.from_digits("4321") }
488
    assert_raise(TypeError) { Integer.from_digits([4, 3, 2, 1], "10") }
489
    assert_raise(TypeError) { Integer.from_digits([4, "3", 2, 1]) }
490
    assert_raise(ArgumentError) { Integer.from_digits([4, 3, 2, 1], 1) }
491
    assert_raise(ArgumentError) { Integer.from_digits([4, 3, 2, 1], 0) }
492
    assert_raise(ArgumentError) { Integer.from_digits([4, 3, 2, 1], -9**999) }
493
  end
494

  
480 495
  def test_square_root
481 496
    assert_raise(TypeError) {Integer.sqrt("x")}
482 497
    assert_raise(Math::DomainError) {Integer.sqrt(-1)}