�����餷����

2009-07-04 - ����C#��.NET�ʵ�Ͽ
����������Ϥ����ޤǤˤ��ơ������ɤξҲ�Ǥ���Hacker's delight �Υ����ɤ��4��5��®���������ơ����ߥղø���Ⱦü����ʤ��������Ĥ� 64bit �Ͱʲ��Τ��٤Ƥ��ͤ��б��Ǥ��ޤ���

�Ǥ⡢�ºݤˤɤ줯�餤���Ϥ����뤫��Ƥߤ����ä��Τ�C�˰ܿ����Ƥߤ����ճ��ʷ�̤��ФƤ���ޤ���

0x03F566ED27179461ULL

�ޤ��Ϲ���ѡ�������Ѥäݤ����Ƥߤޤ�����

typedef unsigned long long U64;

#define HASH 0x03F566ED27179461ULL
static int ntzhash[64];

void init_ntzhash(){
    U64 h = HASH;
    int i;
    for (i = 0; i < 64; i++, h <<= 1) ntzhash[ h >> 58 ] = i;
}

int ntz_hash(U64 n){
    return n ? ntzhash[ (int)( ( ( n & -n ) * HASH ) >> 58) ] : 64;
}

�����ե�

�Ǥ�ʥ����֤ʼ����Ǥ��͡�O(n)

int ntz_shift(U64 n){
    int i;
    for (i = 0; i < 64; i++) if ( (n >> i) & 1 ) return i;
    return 64;
}

��ʬõ��

Hacker's delight P. 85�˽ФƤ��ޤ���O(log n)��64bit�ξ��ǹ�8��ξ��ʬ���Ȥ������Ȥˤʤ�ޤ�������黻�Ҥ�Ȥä��������䤹���ΤǤ������ޤ�����

int ntz_bsrch( U64 n ) {
    n &= -n;
    return n == 0 ? 64
    : n == 0x80000000ULL ? 31
    : (n <  0x80000000ULL ? n == 0x8000ULL ? 15
    /* 60�Ԥۤ���ά */
               : (n <  0x4000000000000000ULL ? 61
              : 63))))));
}

����ʤҤ����ɤ�������Τϼ�ǽ񤤤Ƥ����ʤ��Τǡ��ʲ���Perl Script�˼�ư�������Ƥ�餤�ޤ���(��use64bitint)��

sub foo{
    my ($head, $tail) = @_;
    my $mid = int(($head + $tail) / 2);
    return $mid if $head >= $tail;
    my $ret = sprintf "n == 0x%xULL ? %d\n", 2**$mid, $mid;
    $ret .= 
        sprintf ": (n <  0x%xULL ? %s\n: %s)", 2**$mid,
        foo($head, $mid-1),    foo($mid+1, $tail);
    $ret =~ s/\n+/\n/g;
    $ret;
}

print foo(0,63)

frexp

n & -n�ǡ�����̥ӥåȤ���Ω�Ƥ���Ȥ������Ȥϡ���Υ٥���ˤ��ǤˤʤäƤ���櫓�Ǥ�����������ɤ���äƥӥåȿ��˥ޥåפ��뤫��������ѤΤ������Ȥ����ʤΤǤ������⤦���������ߤΤʤ�������Ȥ��ơ�frexp()��Ȥ��Ȥ���������⤢��ޤ���

#include <math.h>

int ntz_frexp(U64 n){
    int z;
    if ( n == 0 ) return 64;
    frexp( (double)( n & -n ), &z);
    return z - 1;
}

x86��bsf̿��

�ǡ�x86��bsf̿���Ȥ�������Ǥ����ɤ�x86�Ǥ�ư���褦�������Ǥ�32bit�ʾ�ʤΤ��ݤ��Ǿ��ʬ�������Ƥ��ޤ���

int ntz_bsf(U64 n){
    if (n == 0) return 64;
    unsigned int lo = n & 0xffffffff;
    int z;
    if (lo){
        __asm__("bsf %1, %0;" :"=r"(z) :"r"(lo));
    return z;
    }else{
        n >>= 32;
        __asm__("bsf %1, %0;" :"=r"(z) :"r"(n));
        return z + 32;
    }
}

�ޤȤ�ƥ٥���ޡ���

�ǡ����Σ��Ĥ�ޤȤ�ƥ٥���ޡ������Ƥߤޤ����������˷����֤��������ꤹ��ȥ٥���ޡ���������ʤ���Хƥ��Ȥˤʤ�ޤ���Codepad�Ǥ�ư���ޤ�����

http://codepad.org/9UXR2cOu
#include <sys/time.h>

double time_hires(){
    struct timeval now;
    gettimeofday(&now, NULL);
    return now.tv_sec + now.tv_usec/1e6;
}

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define D63 ((U64)1 << 63)

typedef struct { char *name; int (*func)(U64); } nfpair;

static nfpair ntz[] = {
    {"ntz_shift", ntz_shift },
    {"ntz_bsrch", ntz_bsrch },
    {"ntz_frexp", ntz_frexp },
    {"ntz_hash",  ntz_hash  },
    {"ntz_bsf",   ntz_bsf   }
};

int main (int argc, char **argv){
    U64 n;
    int i, j, count = 0;
    double timer;
    if (ntzhash[63] != 6) init_ntzhash();
    if (argc > 1){ /* benchmark */
        count = (int)strtod(argv[1], NULL);
        for (j = 0; j < 5; j++){
            timer = time_hires();
            for (i = 0; i < count; i++){
                assert(ntz[j].func(D63) == 63);
            }
            printf("%9s: %gs\n", ntz[j].name, time_hires() - timer);
        }
    }else{ /* test */
	printf("%d\n", ntz_bsrch(D63));
        for (j = 0; j < 5; j++){
            for (i = 0, n = 1 ; i <= 64; i++, n += n){
                assert(ntz[j].func(n) == i);
                printf("ok %d # %s(0x%016llx) = %d\n", 
                       ++count, ntz[j].name, n, ntz[j].func(n));
            }
        }
        printf("1..%d\n", count);
    }
    return 0;
}

�ǡ��ʲ�����̤Ǥ���

Core 2 Duo 2.4GHz, Mac OS X v10.5.7
% gcc -W -Wall -O6 ntz.c && ./a.out 1e8
ntz_shift: 16.1367s
ntz_bsrch: 1.8118s
ntz_frexp: 2.79462s
 ntz_hash: 1.18244s
  ntz_bsf: 0.475164s
Dual Xeon 2.66GHz, FreeBSD 7.2
% gcc -W -Wall -O6 ntz.c && ./a.out 1e8
ntz_shift: 25.2944s
ntz_bsrch: 1.65888s
ntz_frexp: 7.1559s
 ntz_hash: 1.50684s
  ntz_bsf: 0.905658s

�٥���ޡ����ǻȤäƤ�����ͤϡ�O(c)�Ǥʤ����르�ꥺ��Ǻǰ��ˤʤ�褦��1<<63�ˤ��Ƥ���ޤ������Ƥ��̤ꡢ��ʬõ���ȹ���Ѥκ����ʳ��ȽФƤޤ���64bit�ξ軻�Υ����Ȥ��ʤ�....

���ޤ�

Perl�ΰ����Ϻ���Ȥ���ʤǤ��礦����0�ξ����б����Ƥ��ޤ��������Ϻ�γ�ˤ���ľ������....

sub ntz{ length(sprintf("%064b", shift) =~ /(0+)$/ && $1) }

Dan the Bit Counter