2019年1月30日水曜日

開発環境

プログラマの数学第2版 (結城 浩 (著)、SBクリエイティブ)の第1章(ゼロの物語 - 「ない」ものが「ある」ことの意味)、2進法の基数変換のプログラムのコードを書いてみる。

コード

Python 3

#!/usr/bin/env python3
def to_bin(n: int) -> str:
    '''
    >>> to_bin(12)
    '1100'
    '''
    ''' 10進数を2進数に変換 '''
    b = ''
    while n != 0:
        n, r = divmod(n, 2)
        b = f'{r}{b}'
    if b == '':
        return '0'
    return b


def from_bin(bin: str) -> int:
    '''
    >>> from_bin('1100')
    12
    '''
    ''' 2進数を10進数に変換 '''
    n = 0
    for c in bin:
        n *= 2
        n += int(c)
    return n

# 一般化


def to_n(num: int, n: int) -> str:
    '''
    >>> to_n(12, 2)
    '1100'
    >>> to_n(12, 8)
    '14'
    >>> to_n(12, 16)
    'c'
    '''
    ''' 10進数をn進数に変換 '''
    m = ''
    while num != 0:
        num, r = divmod(num, n)
        if r >= 10:
            r -= 10
            m = f'{chr(ord("a") + r)}{m}'
        else:
            m = f'{r}{m}'
    if m == '':
        return '0'
    return m


def from_n(s: str, n: int) -> int:
    '''
    >>> from_n('1100', 2)
    12
    >>> from_n('14', 8)
    12
    >>> from_n('c', 16)
    12
    '''
    ''' n進数を10進数に変換 '''
    m = 0
    for c in s:
        m *= n
        if c >= 'a':
            m += 10 + ord(c) - ord('a')
        else:
            m += int(c)
    return m


def n_to_m(s: str, n: int, m: int) -> str:
    '''
    >>> n_to_m('1100', 2, 8)
    '14'
    >>> n_to_m('1100', 2, 16)
    'c'
    >>> n_to_m('14', 8, 2)
    '1100'
    >>> n_to_m('c', 16, 2)
    '1100'
    '''
    ''' n進数をm進数に変換 '''
    return to_n(from_n(s, n), m)


# 一般化関数を利用して10進数を2進数、2進数を10進数に変換する関数を定義してみる


def to_bin1(n: int) -> str:
    return to_n(n, 2)


def from_bin1(s: str) -> int:
    return from_n(s, 2)


if __name__ == '__main__':
    import doctest
    doctest.testmod()

    # Table 1-1と一致するか確認
    bs = [to_bin(n) for n in range(100)]
    ns = [from_bin(b) for b in bs]
    for n, b in zip(ns, bs):
        print(f'{n:2} {b:>8}')

    bs = [to_bin1(n) for n in list(range(10)) + [99]]
    ns = [from_bin1(b) for b in bs]
    for n, b in zip(ns, bs):
        print(f'{n:2} {b:>8}')

    # 8、16、その他あまり見かけない基数についても
    for base in [8, 16, 7, 15]:
        print(f'基数: {base}')
        bs = [to_n(m, base) for m in list(range(20)) + [99]]
        ns = [from_n(b, base) for b in bs]
        for n, b in zip(ns, bs):
            print(f'{n:2} {b:>8}')

入出力結果(cmd(コマンドプロンプト)、Terminal、Jupyter(IPython))

$ python3 sample1.py -v
Trying:
    from_bin('1100')
Expecting:
    12
ok
Trying:
    from_n('1100', 2)
Expecting:
    12
ok
Trying:
    from_n('14', 8)
Expecting:
    12
ok
Trying:
    from_n('c', 16)
Expecting:
    12
ok
Trying:
    n_to_m('1100', 2, 8)
Expecting:
    '14'
ok
Trying:
    n_to_m('1100', 2, 16)
Expecting:
    'c'
ok
Trying:
    n_to_m('14', 8, 2)
Expecting:
    '1100'
ok
Trying:
    n_to_m('c', 16, 2)
Expecting:
    '1100'
ok
Trying:
    to_bin(12)
Expecting:
    '1100'
ok
Trying:
    to_n(12, 2)
Expecting:
    '1100'
ok
Trying:
    to_n(12, 8)
Expecting:
    '14'
ok
Trying:
    to_n(12, 16)
Expecting:
    'c'
ok
3 items had no tests:
    __main__
    __main__.from_bin1
    __main__.to_bin1
5 items passed all tests:
   1 tests in __main__.from_bin
   3 tests in __main__.from_n
   4 tests in __main__.n_to_m
   1 tests in __main__.to_bin
   3 tests in __main__.to_n
12 tests in 8 items.
12 passed and 0 failed.
Test passed.
 0        0
 1        1
 2       10
 3       11
 4      100
 5      101
 6      110
 7      111
 8     1000
 9     1001
10     1010
11     1011
12     1100
13     1101
14     1110
15     1111
16    10000
17    10001
18    10010
19    10011
20    10100
21    10101
22    10110
23    10111
24    11000
25    11001
26    11010
27    11011
28    11100
29    11101
30    11110
31    11111
32   100000
33   100001
34   100010
35   100011
36   100100
37   100101
38   100110
39   100111
40   101000
41   101001
42   101010
43   101011
44   101100
45   101101
46   101110
47   101111
48   110000
49   110001
50   110010
51   110011
52   110100
53   110101
54   110110
55   110111
56   111000
57   111001
58   111010
59   111011
60   111100
61   111101
62   111110
63   111111
64  1000000
65  1000001
66  1000010
67  1000011
68  1000100
69  1000101
70  1000110
71  1000111
72  1001000
73  1001001
74  1001010
75  1001011
76  1001100
77  1001101
78  1001110
79  1001111
80  1010000
81  1010001
82  1010010
83  1010011
84  1010100
85  1010101
86  1010110
87  1010111
88  1011000
89  1011001
90  1011010
91  1011011
92  1011100
93  1011101
94  1011110
95  1011111
96  1100000
97  1100001
98  1100010
99  1100011
 0        0
 1        1
 2       10
 3       11
 4      100
 5      101
 6      110
 7      111
 8     1000
 9     1001
99  1100011
基数: 8
 0        0
 1        1
 2        2
 3        3
 4        4
 5        5
 6        6
 7        7
 8       10
 9       11
10       12
11       13
12       14
13       15
14       16
15       17
16       20
17       21
18       22
19       23
99      143
基数: 16
 0        0
 1        1
 2        2
 3        3
 4        4
 5        5
 6        6
 7        7
 8        8
 9        9
10        a
11        b
12        c
13        d
14        e
15        f
16       10
17       11
18       12
19       13
99       63
基数: 7
 0        0
 1        1
 2        2
 3        3
 4        4
 5        5
 6        6
 7       10
 8       11
 9       12
10       13
11       14
12       15
13       16
14       20
15       21
16       22
17       23
18       24
19       25
99      201
基数: 15
 0        0
 1        1
 2        2
 3        3
 4        4
 5        5
 6        6
 7        7
 8        8
 9        9
10        a
11        b
12        c
13        d
14        e
15       10
16       11
17       12
18       13
19       14
99       69
$

本著の表と一致してることも確認できた。

0 コメント:

コメントを投稿