challenge 2進数の記述

 コンピューターの原理は2進数だというのに、多くのプログラミング言語で8進数や16進数しか記述できないのは少し変だとは思いませんか?
 そこで、ソース中に2進数を定数として書く方法、またはその代替手段を考えてください。

ある程度の評価基準を示します(できるところまでで構いません)。
・2進数の表示方法は0と1
・桁数は可変長
・コンパイル等の後に最適化等によって定数に変換されることが見込まれる

Cで関数として実装したものを示しておきます。
1
2
3
4
5
int bin(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8){
    return b1<<7 | b2 <<6 | b3<<5 | b4<<4 | b5<<3 | b6<<2 | b7<<1 | b8;
}

int byte = bin(0, 1, 1, 0, 1, 0, 0, 1);

Posted feedbacks - C

 コンピューターの原理は2進数だというのに、多くのプログラミング言語で8進数や16進数しか記述できないのは少し変だとは思いませんか?
 そこで、ソース中に2進数を定数として書く方法、またはその代替手段を考えてください。

ある程度の評価基準を示します(できるところまでで構いません)。
・2進数の表示方法は0と1
・桁数は可変長
・コンパイル等の後に最適化等によって定数に変換されることが見込まれる

Cで関数として実装したものを示しておきます。
1
2
3
4
5
int bin(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8){
    return b1<<7 | b2 <<6 | b3<<5 | b4<<4 | b5<<3 | b6<<2 | b7<<1 | b8;
}

int byte = bin(0, 1, 1, 0, 1, 0, 0, 1);

カンマがいらない形で....。これ使うくらいなら素直にビットフィールドの構造体定義するか、std::bitset使うけど;;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
inline unsigned long bin(unsigned long n)
{
    return ((((n % 100000000) / 10000000) * 0x80) |
            (((n %  10000000) /  1000000) * 0x40) |
            (((n %   1000000) /   100000) * 0x20) |
            (((n %    100000) /    10000) * 0x10) |
            (((n %     10000) /     1000) * 0x08) |
            (((n %      1000) /      100) * 0x04) |
            (((n %       100) /       10) * 0x02) |
            (((n %        10) /        1) * 0x01));
}

void func()
{
    unsigned long n = bin(1000000);
}

さっき同じこと実験しててハマりました。

最上位が0の場合8進数として認識されます。

ってことでマクロで修正。

あと最適化されないけど、文字列版も

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/*bin_n(00111100)と書きます。
*/
#define  bin_n(n) \
    ((((0##n%0100000000)/010000000)<<7)\
    +(((0##n%0010000000)/001000000)<<6)\
    +(((0##n%0001000000)/000100000)<<5)\
    +(((0##n%0000100000)/000010000)<<4)\
    +(((0##n%0000010000)/000001000)<<3)\
    +(((0##n%0000001000)/000000100)<<2)\
    +(((0##n%0000000100)/000000010)<<1)\
    +(((0##n%0000000010)/000000001)   ))

/*文字列使用版
こちらも同じくbin_s(00111100)と書きます。
*/
#define bin_s(str)\
    (((#str[0]-'0')<<7)+((#str[1]-'0')<<6)+((#str[2]-'0')<<5)\
    +((#str[3]-'0')<<4)+((#str[4]-'0')<<3)+((#str[5]-'0')<<2)\
    +((#str[6]-'0')<<1)+#str[7]-'0')
}

なるほど。 先頭0付けると8進数って、0x付けると16進数ってぇのと大差ない感覚だったんですけど。

マクロは、拡張も楽な感じ。(コードは試してません)

1
2
3
4
#define bin_8(a)                bin_n(a)
#define bin_16(a,b)             ((bin_8(a)<<8)|bin_8(b))
#define bin_32(a,b,c,d)         ((bin_16(a,b)<<16)|bin_16(c,d))
#define bin_64(a,b,c,d,e,f,g,h) ((bin_32(a,b,c,d)<<32)|bin_32(e,f,g,h))

来てみたらもう次のお題が出てしまっていたので、用意していた私の案を公開します。

Cのマクロによる実装です。
引数に二進数表現を受け取り、#によってダブルクォーテーションでくくって文字列にします。
ここで、文字列リテラルのサイズ(NULL文字含む)がsizeof("str")で取得できる(この場合4)を利用して、左の方が足りないときは0と見なします。そうでないなら文字コードの'0'と'1'で判定します。
#4585を任意文字数にした感じでしょうか。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* 使用例 0を詰めても桁数が半端でも大丈夫 bintest.c */
#include <stdio.h>
#include "binary.h"

int main(){
    printf("%u\n", bin(0111));
    printf("%u\n", bin(11111));
    printf("%u\n", bin(11111111111111111111111111111111));
}


/* 2進数記述マクロ binary.h */
#ifndef BINARY_H_INCLUDE
#define BINARY_H_INCLUDE

#define bin(n) ((sizeof(#n)<33?0:(#n[sizeof(#n)-33]-'0') << 31) |\
(sizeof(#n)<32?0:(#n[sizeof(#n)-32]-'0') << 30) |\
(sizeof(#n)<31?0:(#n[sizeof(#n)-31]-'0') << 29) |\
(sizeof(#n)<30?0:(#n[sizeof(#n)-30]-'0') << 28) |\
(sizeof(#n)<29?0:(#n[sizeof(#n)-29]-'0') << 27) |\
(sizeof(#n)<28?0:(#n[sizeof(#n)-28]-'0') << 26) |\
(sizeof(#n)<27?0:(#n[sizeof(#n)-27]-'0') << 25) |\
(sizeof(#n)<26?0:(#n[sizeof(#n)-26]-'0') << 24) |\
(sizeof(#n)<25?0:(#n[sizeof(#n)-25]-'0') << 23) |\
(sizeof(#n)<24?0:(#n[sizeof(#n)-24]-'0') << 22) |\
(sizeof(#n)<23?0:(#n[sizeof(#n)-23]-'0') << 21) |\
(sizeof(#n)<22?0:(#n[sizeof(#n)-22]-'0') << 20) |\
(sizeof(#n)<21?0:(#n[sizeof(#n)-21]-'0') << 19) |\
(sizeof(#n)<20?0:(#n[sizeof(#n)-20]-'0') << 18) |\
(sizeof(#n)<19?0:(#n[sizeof(#n)-19]-'0') << 17) |\
(sizeof(#n)<18?0:(#n[sizeof(#n)-18]-'0') << 16) |\
(sizeof(#n)<17?0:(#n[sizeof(#n)-17]-'0') << 15) |\
(sizeof(#n)<16?0:(#n[sizeof(#n)-16]-'0') << 14) |\
(sizeof(#n)<15?0:(#n[sizeof(#n)-15]-'0') << 13) |\
(sizeof(#n)<14?0:(#n[sizeof(#n)-14]-'0') << 12) |\
(sizeof(#n)<13?0:(#n[sizeof(#n)-13]-'0') << 11) |\
(sizeof(#n)<12?0:(#n[sizeof(#n)-12]-'0') << 10) |\
(sizeof(#n)<11?0:(#n[sizeof(#n)-11]-'0') << 9) |\
(sizeof(#n)<10?0:(#n[sizeof(#n)-10]-'0') << 8) |\
(sizeof(#n)<9?0:(#n[sizeof(#n)-9]-'0') << 7) |\
(sizeof(#n)<8?0:(#n[sizeof(#n)-8]-'0') << 6) |\
(sizeof(#n)<7?0:(#n[sizeof(#n)-7]-'0') << 5) |\
(sizeof(#n)<6?0:(#n[sizeof(#n)-6]-'0') << 4) |\
(sizeof(#n)<5?0:(#n[sizeof(#n)-5]-'0') << 3) |\
(sizeof(#n)<4?0:(#n[sizeof(#n)-4]-'0') << 2) |\
(sizeof(#n)<3?0:(#n[sizeof(#n)-3]-'0') << 1) |\
(sizeof(#n)<2?0:(#n[sizeof(#n)-2]-'0') << 0))

#endif


/* binary.h生成プログラム binary.c */
#include <stdio.h>

#define BIT 32

int main(){
    int i;
    freopen("binary.h", "w", stdout);
    puts("#ifndef BINARY_H_INCLUDE");
    puts("#define BINARY_H_INCLUDE");
    puts("");

    printf("#define bin(n) (");
    for(i=0; i<BIT; i++){
        printf("(sizeof(#n)<%d?0:(#n[sizeof(#n)-%d]-'0') << %d)", BIT-i+1, BIT-i+1, BIT-i-1);
        if(i != BIT-1)
            printf(" |\\\n");
    }
    printf(")\n");

    puts("");
    puts("#endif");
}

アセンブリであれば、直接指定できます。
0b0101  = 5

# gcc main2.c
#./a.out
5#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>
int main()
{
        int b;

        __asm__("movl $0b0101, %0;" : "=r"(b));

        printf("%x", b );
        return 0;
}

Index

Feed

Other

Link

Pathtraq

loading...