popcount.patch

Akira Tanaka, 08/07/2013 09:51 PM

Download (8.02 KB)

View differences:

configure.in (working copy)
1853 1853
RUBY_CHECK_BUILTIN_FUNC(__builtin_clz, [__builtin_clz(0)])
1854 1854
RUBY_CHECK_BUILTIN_FUNC(__builtin_clzl, [__builtin_clzl(0)])
1855 1855
RUBY_CHECK_BUILTIN_FUNC(__builtin_clzll, [__builtin_clzll(0)])
1856
RUBY_CHECK_BUILTIN_FUNC(__builtin_popcount, [__builtin_popcount(0)])
1857
RUBY_CHECK_BUILTIN_FUNC(__builtin_popcountl, [__builtin_popcountl(0)])
1858
RUBY_CHECK_BUILTIN_FUNC(__builtin_popcountll, [__builtin_popcountll(0)])
1856 1859

  
1857 1860
# Some platform need -lrt for clock_gettime, but the other don't.
1858 1861
if test x"$ac_cv_func_clock_gettime" != xyes; then
numeric.c (working copy)
2410 2410

  
2411 2411
/*
2412 2412
 *  call-seq:
2413
 *     int.popcount  ->  integer
2414
 *
2415
 *  Returns the number of one bits in the absolute number of +int+.
2416
 *
2417
 *     0.popcount               #=> 0
2418
 *     0b1010.popcount          #=> 2
2419
 *     (-0b1011).popcount       #=> 3
2420
 */
2421

  
2422
static VALUE
2423
fix_popcount(VALUE num)
2424
{
2425
    long i = FIX2LONG(num);
2426

  
2427
    if (i < 0)
2428
        i = -i;
2429

  
2430
    return LONG2FIX(popcount_long((unsigned long)i));
2431
}
2432

  
2433
/*
2434
 *  call-seq:
2413 2435
 *     int.next  ->  integer
2414 2436
 *     int.succ  ->  integer
2415 2437
 *
......
3868 3890
    rb_define_method(rb_cFixnum, "odd?", fix_odd_p, 0);
3869 3891
    rb_define_method(rb_cFixnum, "even?", fix_even_p, 0);
3870 3892
    rb_define_method(rb_cFixnum, "succ", fix_succ, 0);
3893
    rb_define_method(rb_cFixnum, "popcount", fix_popcount, 0);
3871 3894

  
3872 3895
    rb_cFloat  = rb_define_class("Float", rb_cNumeric);
3873 3896

  
bignum.c (working copy)
6582 6582
}
6583 6583

  
6584 6584
/*
6585
 *  call-seq:
6586
 *     int.popcount  ->  integer
6587
 *
6588
 *  Returns the number of one bits in the absolute number of +int+.
6589
 *
6590
 *     (2**100).popcount        #=> 1
6591
 *     (2**100-1).popcount      #=> 100
6592
 *     (-2**100).popcount       #=> 1
6593
 *     (10**100).popcount       #=> 105
6594
 *     (257**257).popcount      #=> 999
6595
 */
6596

  
6597
static VALUE
6598
rb_big_popcount(VALUE num)
6599
{
6600
    long n = RBIGNUM_LEN(num);
6601
    BDIGIT *ds = BDIGITS(num);
6602
    VALUE result = LONG2FIX(0);
6603
    long r = 0;
6604
    int pop;
6605

  
6606
    while (0 < n) {
6607
        n--;
6608
#if SIZEOF_BDIGITS <= SIZEOF_INT
6609
        pop = popcount_int((unsigned int)ds[n]);
6610
#elif SIZEOF_BDIGITS <= SIZEOF_LONG
6611
        pop = popcount_long((unsigned long)ds[n]);
6612
#elif defined(HAVE_LONG_LONG) && SIZEOF_BDIGITS <= SIZEOF_LONG_LONG
6613
        pop = popcount_long_long((unsigned LONG_LONG)ds[n]);
6614
#else
6615
# error too big BDIGIT type.
6616
#endif
6617
        r += pop;
6618
        if (FIXNUM_MAX < r) {
6619
            if (result == LONG2FIX(0))
6620
                result = rb_uint2big(r);
6621
            else
6622
                result = bigadd_int(result, r);
6623
        }
6624
    }
6625
    if (r != 0) {
6626
        if (result == LONG2FIX(0))
6627
            result = LONG2NUM(r);
6628
        else
6629
            result = bigadd_int(result, r);
6630
    }
6631
    return result;
6632
}
6633

  
6634
/*
6585 6635
 *  Bignum objects hold integers outside the range of
6586 6636
 *  Fixnum. Bignum objects are created
6587 6637
 *  automatically when integer calculations would otherwise overflow a
......
6642 6692
    rb_define_method(rb_cBignum, "size", rb_big_size, 0);
6643 6693
    rb_define_method(rb_cBignum, "odd?", rb_big_odd_p, 0);
6644 6694
    rb_define_method(rb_cBignum, "even?", rb_big_even_p, 0);
6695
    rb_define_method(rb_cBignum, "popcount", rb_big_popcount, 0);
6645 6696

  
6646 6697
    power_cache_init();
6647 6698
}
internal.h (working copy)
106 106
# endif
107 107
#endif
108 108

  
109
#define MASK_8x2(mask) (((mask) << 8) | (mask))
110
#define MASK_8x4(mask) ((MASK_8x2(mask) << 16) | MASK_8x2(mask))
111
#define MASK_8x8(mask) ((MASK_8x4(mask) << 32) | MASK_8x4(mask))
112
#define MASK_8x16(mask) ((MASK_8x8(mask) << 64) | MASK_8x8(mask))
113

  
114
#if SIZEOF_INT * CHAR_BIT <= 16
115
# define MASK_INT(byte) MASK_8x2((unsigned int)(byte))
116
#elif SIZEOF_INT * CHAR_BIT <= 32
117
# define MASK_INT(byte) MASK_8x4((unsigned int)(byte))
118
#elif SIZEOF_INT * CHAR_BIT <= 64
119
# define MASK_INT(byte) MASK_8x8((unsigned int)(byte))
120
#elif SIZEOF_INT * CHAR_BIT <= 128
121
# define MASK_INT(byte) MASK_8x16((unsigned int)(byte))
122
#else
123
# error too big integer type
124
#endif
125

  
126
#if SIZEOF_LONG * CHAR_BIT <= 16
127
# define MASK_LONG(byte) MASK_8x2((unsigned long)(byte))
128
#elif SIZEOF_LONG * CHAR_BIT <= 32
129
# define MASK_LONG(byte) MASK_8x4((unsigned long)(byte))
130
#elif SIZEOF_LONG * CHAR_BIT <= 64
131
# define MASK_LONG(byte) MASK_8x8((unsigned long)(byte))
132
#elif SIZEOF_LONG * CHAR_BIT <= 128
133
# define MASK_LONG(byte) MASK_8x16((unsigned long)(byte))
134
#else
135
# error too big integer type
136
#endif
137

  
138
#ifdef HAVE_LONG_LONG
139
# if SIZEOF_LONG_LONG * CHAR_BIT <= 16
140
#  define MASK_LONG_LONG(byte) MASK_8x2((unsigned LONG_LONG)(byte))
141
# elif SIZEOF_LONG_LONG * CHAR_BIT <= 32
142
#  define MASK_LONG_LONG(byte) MASK_8x4((unsigned LONG_LONG)(byte))
143
# elif SIZEOF_LONG_LONG * CHAR_BIT <= 64
144
#  define MASK_LONG_LONG(byte) MASK_8x8((unsigned LONG_LONG)(byte))
145
# elif SIZEOF_LONG_LONG * CHAR_BIT <= 128
146
#  define MASK_LONG_LONG(byte) MASK_8x16((unsigned LONG_LONG)(byte))
147
# else
148
#  error too big integer type
149
# endif
150
#endif
151

  
152
#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNT)
153
# define popcount_int(x) __builtin_popcount(x)
154
#else
155
static inline int
156
popcount_int(unsigned int x)
157
{
158
    x -= (x >> 1) & MASK_INT(0x55);
159
    x = ((x >> 2) & MASK_INT(0x33)) + (x & MASK_INT(0x33));
160
    x = ((x >> 4) + x) & MASK_INT(0x0f);
161
    x += (x >> 8);
162
    x += (x >> 16);
163
#if 32 < SIZEOF_INT * CHAR_BIT
164
    x += (x >> 32);
165
#endif
166
#if 64 < SIZEOF_INT * CHAR_BIT
167
    x += (x >> 64);
168
#endif
169
#if 128 < SIZEOF_INT * CHAR_BIT
170
# error too big integer type
171
#endif
172
    return (int)(x & 0xff);
173
}
174
#endif
175

  
176
#if defined(HAVE_BUILTIN___BUILTIN_POPCOUNTL)
177
# define popcount_long(x) __builtin_popcountl(x)
178
#else
179
static inline int
180
popcount_long(unsigned long x)
181
{
182
    x -= (x >> 1) & MASK_LONG(0x55);
183
    x = ((x >> 2) & MASK_LONG(0x33)) + (x & MASK_LONG(0x33));
184
    x = ((x >> 4) + x) & MASK_LONG(0x0f);
185
    x += (x >> 8);
186
    x += (x >> 16);
187
#if 32 < SIZEOF_LONG * CHAR_BIT
188
    x += (x >> 32);
189
#endif
190
#if 64 < SIZEOF_LONG * CHAR_BIT
191
    x += (x >> 64);
192
#endif
193
#if 128 < SIZEOF_LONG * CHAR_BIT
194
# error too big integer type
195
#endif
196
    return (int)(x & 0xff);
197
}
198
#endif
199

  
200
#ifdef HAVE_LONG_LONG
201
# if defined(HAVE_BUILTIN___BUILTIN_POPCOUNTLL)
202
#  define popcount_long_long(x) __builtin_popcountll(x)
203
# else
204
static inline int
205
popcount_long_long(unsigned LONG_LONG x)
206
{
207
    x -= (x >> 1) & MASK_LONG_LONG(0x55);
208
    x = ((x >> 2) & MASK_LONG_LONG(0x33)) + (x & MASK_LONG_LONG(0x33));
209
    x = ((x >> 4) + x) & MASK_LONG_LONG(0x0f);
210
    x += (x >> 8);
211
    x += (x >> 16);
212
#if 32 < SIZEOF_LONG_LONG * CHAR_BIT
213
    x += (x >> 32);
214
#endif
215
#if 64 < SIZEOF_LONG_LONG * CHAR_BIT
216
    x += (x >> 64);
217
#endif
218
#if 128 < SIZEOF_LONG_LONG * CHAR_BIT
219
# error too big integer type
220
#endif
221
    return (int)(x & 0xff);
222
}
223
# endif
224
#endif
225

  
109 226
struct rb_deprecated_classext_struct {
110 227
    char conflict[sizeof(VALUE) * 3];
111 228
};
test/ruby/test_integer.rb (working copy)
241 241
    end
242 242
    assert_equal(3 ^ 10, 3 ^ obj)
243 243
  end
244

  
245
  def test_popcount
246
    assert_equal(1, -1.popcount)
247
    assert_equal(0, 0.popcount)
248
    assert_equal(1, 1.popcount)
249

  
250
    -100.upto(100) {|n|
251
      assert_equal(n.abs.to_s(2).count("1"), n.popcount)
252
    }
253

  
254
    0.upto(100) {|k|
255
      n = 3**k
256
      assert_equal(n.abs.to_s(2).count("1"), n.popcount)
257
      n = -n
258
      assert_equal(n.abs.to_s(2).count("1"), n.popcount)
259
    }
260
  end
244 261
end