From e5ff9d58effb093653bcb12ed2865e1509e2b265 Mon Sep 17 00:00:00 2001 From: akr Date: Sun, 28 Jul 2013 02:14:58 +0000 Subject: * include/ruby/intern.h (rb_absint_size): Declaration moved from internal.h to calculate required buffer size to pack integers. (rb_absint_numwords): Ditto. (rb_absint_singlebit_p): Ditto. [ruby-core:42813] [Feature #6065] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42208 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 8 +++++++ bignum.c | 28 ++++++++++++++++++++++++ ext/-test-/bignum/intpack.c | 23 ++++++++++++++++++++ include/ruby/intern.h | 3 +++ internal.h | 3 --- test/-ext-/bignum/test_pack.rb | 49 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 111 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b3b08059f0..44bc48cd55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Jul 28 11:12:07 2013 Tanaka Akira + + * include/ruby/intern.h (rb_absint_size): Declaration moved from + internal.h to calculate required buffer size to pack integers. + (rb_absint_numwords): Ditto. + (rb_absint_singlebit_p): Ditto. + [ruby-core:42813] [Feature #6065] + Sun Jul 28 10:54:26 2013 Nobuyoshi Nakada * win32/win32.c (rb_w32_pipe): fix pipe name formatting. as "%x" may diff --git a/bignum.c b/bignum.c index b028434b04..f07f869c98 100644 --- a/bignum.c +++ b/bignum.c @@ -3275,6 +3275,34 @@ rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret) return numwords; } +/* Test abs(val) consists only a bit or not. + * + * Returns 1 if abs(val) == 1 << n for some n >= 0. + * Returns 0 otherwise. + * + * rb_absint_singlebit_p can be used to determine required buffer size + * for rb_integer_pack used with INTEGER_PACK_2COMP (two's complement). + * + * Following example calculates number of bits required to + * represent val in two's complement number, without sign bit. + * + * size_t size; + * int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : RBIGNUM_NEGATIVE_P(val); + * size = rb_absint_numwords(val, 1, NULL) + * if (size == (size_t)-1) ...overflow... + * if (neg && rb_absint_singlebit_p(val)) + * size--; + * + * Following example calculates number of bytes required to + * represent val in two's complement number, with sign bit. + * + * size_t size; + * int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : RBIGNUM_NEGATIVE_P(val); + * int nlz_bits; + * size = rb_absint_size(val, &nlz_bits); + * if (nlz_bits == 0 && !(neg && rb_absint_singlebit_p(val))) + * size++; + */ int rb_absint_singlebit_p(VALUE val) { diff --git a/ext/-test-/bignum/intpack.c b/ext/-test-/bignum/intpack.c index 909294d88c..03023196e6 100644 --- a/ext/-test-/bignum/intpack.c +++ b/ext/-test-/bignum/intpack.c @@ -45,6 +45,26 @@ rb_integer_unpack_m(VALUE klass, VALUE buf, VALUE numwords, VALUE wordsize, VALU NUM2SIZET(nails), NUM2INT(flags)); } +static VALUE +rb_integer_test_numbits_2comp_without_sign(VALUE val) +{ + size_t size; + int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : RBIGNUM_NEGATIVE_P(val); + size = rb_absint_numwords(val, 1, NULL) - (neg && rb_absint_singlebit_p(val)); + return SIZET2NUM(size); +} + +static VALUE +rb_integer_test_numbytes_2comp_with_sign(VALUE val) +{ + int neg = FIXNUM_P(val) ? FIX2LONG(val) < 0 : RBIGNUM_NEGATIVE_P(val); + int nlz_bits; + size_t size = rb_absint_size(val, &nlz_bits); + if (nlz_bits == 0 && !(neg && rb_absint_singlebit_p(val))) + size++; + return SIZET2NUM(size); +} + void Init_intpack(VALUE klass) { @@ -62,4 +82,7 @@ Init_intpack(VALUE klass) rb_define_const(rb_cInteger, "INTEGER_PACK_FORCE_BIGNUM", INT2NUM(INTEGER_PACK_FORCE_BIGNUM)); rb_define_const(rb_cInteger, "INTEGER_PACK_NEGATIVE", INT2NUM(INTEGER_PACK_NEGATIVE)); rb_define_const(rb_cInteger, "INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION", INT2NUM(INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION)); + + rb_define_method(rb_cInteger, "test_numbits_2comp_without_sign", rb_integer_test_numbits_2comp_without_sign, 0); + rb_define_method(rb_cInteger, "test_numbytes_2comp_with_sign", rb_integer_test_numbytes_2comp_with_sign, 0); } diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 99e6e3e6cd..4393246744 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -157,6 +157,9 @@ VALUE rb_big_rshift(VALUE, VALUE); INTEGER_PACK_MSBYTE_FIRST) 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); +size_t rb_absint_size(VALUE val, int *nlz_bits_ret); +size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret); +int rb_absint_singlebit_p(VALUE val); /* rational.c */ VALUE rb_rational_raw(VALUE, VALUE); diff --git a/internal.h b/internal.h index 4bcf9c0e46..b7a8a75669 100644 --- a/internal.h +++ b/internal.h @@ -141,9 +141,6 @@ VALUE rb_big_fdiv(VALUE x, VALUE y); VALUE rb_big_uminus(VALUE x); VALUE rb_integer_float_cmp(VALUE x, VALUE y); VALUE rb_integer_float_eq(VALUE x, VALUE y); -size_t rb_absint_size(VALUE val, int *nlz_bits_ret); -size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret); -int rb_absint_singlebit_p(VALUE val); /* class.c */ VALUE rb_obj_methods(int argc, VALUE *argv, VALUE obj); diff --git a/test/-ext-/bignum/test_pack.rb b/test/-ext-/bignum/test_pack.rb index e5fb358ce8..0614e1046c 100644 --- a/test/-ext-/bignum/test_pack.rb +++ b/test/-ext-/bignum/test_pack.rb @@ -322,4 +322,53 @@ class TestBignum < Test::Unit::TestCase } end end + + def test_numbits_2comp + assert_equal(4, -9.test_numbits_2comp_without_sign) + assert_equal(3, -8.test_numbits_2comp_without_sign) + assert_equal(3, -7.test_numbits_2comp_without_sign) + assert_equal(3, -6.test_numbits_2comp_without_sign) + assert_equal(3, -5.test_numbits_2comp_without_sign) + assert_equal(2, -4.test_numbits_2comp_without_sign) + assert_equal(2, -3.test_numbits_2comp_without_sign) + assert_equal(1, -2.test_numbits_2comp_without_sign) + assert_equal(0, -1.test_numbits_2comp_without_sign) + assert_equal(0, 0.test_numbits_2comp_without_sign) + assert_equal(1, 1.test_numbits_2comp_without_sign) + assert_equal(2, 2.test_numbits_2comp_without_sign) + assert_equal(2, 3.test_numbits_2comp_without_sign) + assert_equal(3, 4.test_numbits_2comp_without_sign) + assert_equal(3, 5.test_numbits_2comp_without_sign) + assert_equal(3, 6.test_numbits_2comp_without_sign) + assert_equal(3, 7.test_numbits_2comp_without_sign) + assert_equal(4, 8.test_numbits_2comp_without_sign) + assert_equal(4, 9.test_numbits_2comp_without_sign) + end + + def test_numbytes_2comp + assert_equal(6, -0x8000000001.test_numbytes_2comp_with_sign) + assert_equal(5, -0x8000000000.test_numbytes_2comp_with_sign) + assert_equal(5, -0x80000001.test_numbytes_2comp_with_sign) + assert_equal(4, -0x80000000.test_numbytes_2comp_with_sign) + assert_equal(4, -0x800001.test_numbytes_2comp_with_sign) + assert_equal(3, -0x800000.test_numbytes_2comp_with_sign) + assert_equal(3, -0x8001.test_numbytes_2comp_with_sign) + assert_equal(2, -0x8000.test_numbytes_2comp_with_sign) + assert_equal(2, -0x81.test_numbytes_2comp_with_sign) + assert_equal(1, -0x80.test_numbytes_2comp_with_sign) + assert_equal(1, -1.test_numbytes_2comp_with_sign) + assert_equal(1, 0.test_numbytes_2comp_with_sign) + assert_equal(1, 1.test_numbytes_2comp_with_sign) + assert_equal(1, 0x7f.test_numbytes_2comp_with_sign) + assert_equal(2, 0x80.test_numbytes_2comp_with_sign) + assert_equal(2, 0x7fff.test_numbytes_2comp_with_sign) + assert_equal(3, 0x8000.test_numbytes_2comp_with_sign) + assert_equal(3, 0x7fffff.test_numbytes_2comp_with_sign) + assert_equal(4, 0x800000.test_numbytes_2comp_with_sign) + assert_equal(4, 0x7fffffff.test_numbytes_2comp_with_sign) + assert_equal(5, 0x80000000.test_numbytes_2comp_with_sign) + assert_equal(5, 0x7fffffffff.test_numbytes_2comp_with_sign) + assert_equal(6, 0x8000000000.test_numbytes_2comp_with_sign) + end + end -- cgit v1.2.3