mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* internal.h (rb_big_mul_normal): Declared.
(rb_big_mul_balance): Ditto. (rb_big_mul_karatsuba): Ditto. * bignum.c (rb_big_mul_normal): New function for tests. (rb_big_mul_balance): Ditto. (rb_big_mul_karatsuba): Ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41824 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d7c2f3f8a4
commit
29634bca31
6 changed files with 145 additions and 0 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
Sun Jul 7 22:59:06 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* internal.h (rb_big_mul_normal): Declared.
|
||||
(rb_big_mul_balance): Ditto.
|
||||
(rb_big_mul_karatsuba): Ditto.
|
||||
|
||||
* bignum.c (rb_big_mul_normal): New function for tests.
|
||||
(rb_big_mul_balance): Ditto.
|
||||
(rb_big_mul_karatsuba): Ditto.
|
||||
|
||||
Sun Jul 7 19:21:30 2013 Tanaka Akira <akr@fsij.org>
|
||||
|
||||
* bignum.c: Reorder functions to decrease forward reference.
|
||||
|
|
37
bignum.c
37
bignum.c
|
@ -1489,6 +1489,17 @@ bary_mul_normal(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds, siz
|
|||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_big_mul_normal(VALUE x, VALUE y)
|
||||
{
|
||||
size_t xn = RBIGNUM_LEN(x), yn = RBIGNUM_LEN(y), zn = xn + yn;
|
||||
VALUE z = bignew(zn, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
|
||||
bary_mul_normal(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn);
|
||||
RB_GC_GUARD(x);
|
||||
RB_GC_GUARD(y);
|
||||
return z;
|
||||
}
|
||||
|
||||
/* efficient squaring (2 times faster than normal multiplication)
|
||||
* ref: Handbook of Applied Cryptography, Algorithm 14.16
|
||||
* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
|
||||
|
@ -1558,6 +1569,19 @@ bary_mul_balance(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds, si
|
|||
ALLOCV_END(work);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_big_mul_balance(VALUE x, VALUE y)
|
||||
{
|
||||
size_t xn = RBIGNUM_LEN(x), yn = RBIGNUM_LEN(y), zn = xn + yn;
|
||||
VALUE z = bignew(zn, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
|
||||
if (!(2 * xn <= yn || 3 * xn <= 2*(yn+2)))
|
||||
rb_raise(rb_eArgError, "invalid bignum length");
|
||||
bary_mul_balance(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn);
|
||||
RB_GC_GUARD(x);
|
||||
RB_GC_GUARD(y);
|
||||
return z;
|
||||
}
|
||||
|
||||
/* multiplication by karatsuba method */
|
||||
static void
|
||||
bary_mul_karatsuba(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds, size_t yl)
|
||||
|
@ -1720,6 +1744,19 @@ bary_mul_karatsuba(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds,
|
|||
ALLOCV_END(work);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_big_mul_karatsuba(VALUE x, VALUE y)
|
||||
{
|
||||
size_t xn = RBIGNUM_LEN(x), yn = RBIGNUM_LEN(y), zn = xn + yn;
|
||||
VALUE z = bignew(zn, RBIGNUM_SIGN(x)==RBIGNUM_SIGN(y));
|
||||
if (!(xn <= yn && yn < 2 * xn))
|
||||
rb_raise(rb_eArgError, "invalid bignum length");
|
||||
bary_mul_karatsuba(BDIGITS(z), zn, BDIGITS(x), xn, BDIGITS(y), yn);
|
||||
RB_GC_GUARD(x);
|
||||
RB_GC_GUARD(y);
|
||||
return z;
|
||||
}
|
||||
|
||||
static void
|
||||
bary_mul1(BDIGIT *zds, size_t zl, BDIGIT *xds, size_t xl, BDIGIT *yds, size_t yl)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
$(OBJS): $(HDRS) $(ruby_headers)
|
||||
|
||||
pack.o: pack.c $(top_srcdir)/internal.h
|
||||
mul.o: mul.c $(top_srcdir)/internal.h
|
||||
|
|
41
ext/-test-/bignum/mul.c
Normal file
41
ext/-test-/bignum/mul.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "ruby.h"
|
||||
#include "internal.h"
|
||||
|
||||
static VALUE
|
||||
big(VALUE x)
|
||||
{
|
||||
if (FIXNUM_P(x))
|
||||
return rb_int2big(FIX2LONG(x));
|
||||
if (RB_TYPE_P(x, T_BIGNUM))
|
||||
return x;
|
||||
rb_raise(rb_eTypeError, "can't convert %s to Bignum",
|
||||
rb_obj_classname(x));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mul_normal(VALUE x, VALUE y)
|
||||
{
|
||||
return rb_big_norm(rb_big_mul_normal(big(x), big(y)));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mul_balance(VALUE x, VALUE y)
|
||||
{
|
||||
return rb_big_norm(rb_big_mul_balance(big(x), big(y)));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
mul_karatsuba(VALUE x, VALUE y)
|
||||
{
|
||||
return rb_big_norm(rb_big_mul_karatsuba(big(x), big(y)));
|
||||
}
|
||||
|
||||
void
|
||||
Init_mul(VALUE klass)
|
||||
{
|
||||
rb_define_const(rb_cBignum, "SIZEOF_BDIGITS", INT2NUM(SIZEOF_BDIGITS));
|
||||
rb_define_const(rb_cBignum, "BITSPERDIG", INT2NUM(SIZEOF_BDIGITS * CHAR_BIT));
|
||||
rb_define_method(rb_cInteger, "big_mul_normal", mul_normal, 1);
|
||||
rb_define_method(rb_cInteger, "big_mul_balance", mul_balance, 1);
|
||||
rb_define_method(rb_cInteger, "big_mul_karatsuba", mul_karatsuba, 1);
|
||||
}
|
|
@ -515,6 +515,9 @@ VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, in
|
|||
/* bignum.c */
|
||||
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags);
|
||||
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags);
|
||||
VALUE rb_big_mul_normal(VALUE x, VALUE y);
|
||||
VALUE rb_big_mul_balance(VALUE x, VALUE y);
|
||||
VALUE rb_big_mul_karatsuba(VALUE x, VALUE y);
|
||||
|
||||
/* io.c */
|
||||
void rb_maygvl_fd_fix_cloexec(int fd);
|
||||
|
|
53
test/-ext-/bignum/test_mul.rb
Normal file
53
test/-ext-/bignum/test_mul.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
require 'test/unit'
|
||||
require "-test-/bignum"
|
||||
|
||||
class TestBignum < Test::Unit::TestCase
|
||||
class TestMul < Test::Unit::TestCase
|
||||
|
||||
SIZEOF_BDIGITS = Bignum::SIZEOF_BDIGITS
|
||||
BITSPERDIG = Bignum::BITSPERDIG
|
||||
|
||||
def test_mul_normal
|
||||
x = (1 << BITSPERDIG) | 1
|
||||
y = (1 << BITSPERDIG) | 1
|
||||
z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1
|
||||
assert_equal(z, x.big_mul_normal(y))
|
||||
end
|
||||
|
||||
def test_mul_normal_zero_in_x
|
||||
x = (1 << (2*BITSPERDIG)) | 1
|
||||
y = (1 << BITSPERDIG) | 1
|
||||
z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1
|
||||
assert_equal(z, x.big_mul_normal(y))
|
||||
end
|
||||
|
||||
def test_mul_normal_zero_in_y
|
||||
x = (1 << BITSPERDIG) | 1
|
||||
y = (1 << (2*BITSPERDIG)) | 1
|
||||
z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1
|
||||
assert_equal(z, x.big_mul_normal(y))
|
||||
end
|
||||
|
||||
def test_mul_normal_max_max
|
||||
x = (1 << (2*BITSPERDIG)) - 1
|
||||
y = (1 << (2*BITSPERDIG)) - 1
|
||||
z = (1 << (4*BITSPERDIG)) - (1 << (2*BITSPERDIG+1)) + 1
|
||||
assert_equal(z, x.big_mul_normal(y))
|
||||
end
|
||||
|
||||
def test_mul_balance
|
||||
x = (1 << BITSPERDIG) | 1
|
||||
y = (1 << BITSPERDIG) | 1
|
||||
z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1
|
||||
assert_equal(z, x.big_mul_balance(y))
|
||||
end
|
||||
|
||||
def test_mul_karatsuba
|
||||
x = (1 << BITSPERDIG) | 1
|
||||
y = (1 << BITSPERDIG) | 1
|
||||
z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1
|
||||
assert_equal(z, x.big_mul_karatsuba(y))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue