[python] bit 操作與易經
從沒有機會需要操作 bit,沒想到寫易經的程式非得用到不可。
第一個最需要的是,把數字轉成 0101 的字串。這個內建的 bin() 函數可用,只是它會在字串前多加0b。依實際需要,得把 0b 去掉。
>>> bin(13)
'0b1100'
>>> bin(13)[2:]
'1101'
第二個就是把 0101 的字串轉回數字,這可以用 eval,或是 int('0b1100', 2) 來達成。
>>> int('0b1101',2)
13
>>> int('1101',2)
13
第三個,易經是 6-bits 系統,而且非常需要補 0 在高位數。
>>> bin(13)[2:].rjust(6,'0')
'001101'
第四個,因為我手上的易經參考書,低位寫在前面,高位寫在後面,我得把字串反過來。從字串轉回數字也得一樣照辦。
>>> bin(13)[2:].rjust(6,'0')[::-1]
'101100'
>>> int('101100'[::-1], 2)
13
第五個,對某個 bit 做反轉運算,因為對 6-bits 的操作沒有把握再加上高低位已經反轉,已經夠亂了,所以採取直接對字串操作,但因為 python 的字串沒法單獨對第某個字元操作,所以寫了個函數代替。主要是拆開字串為 list,操作完再組回去。index 從 0 開始。
def _invert_at(s, index):
ss = list(s)
if ss[index] == '0':
ss[index] = '1'
else:
ss[index] = '0'
return ''.join(ss)>>> _invert_at('101100', 1)
'111100'
更新:經過研究測試之後,相同的功能可以用 bin(int(s, 2) ^ 2 ** (5 - index))[2:].rjust(6, '0') 來解決。
基礎工程結束,接下來應用開始。因為用 bit 來表達了,原本常用的 1~8,都得用 0~7 這種以 0 開始的 index 系統。
一般卜卦是在得到一個卦(叫做「本卦」)之後,都會再求一個「變卦」及「互卦」。在一般簡易數字型卜卦中,本卦、變卦、互卦的求法是:
- 本卦是得到兩個 0~7 之間的數字,一個代表上卦,一個代表下卦。例如,上卦 1、下卦 7,就是 101100,豐卦。(下卦在前面,低位在前面)
- 變卦是從 0~5 之間得到一個數字,代表動爻的位置,然後把本卦的對應的 bit 反轉。例如,101100,我們得到 2 爻動,就是得到 111100,大壯卦。
- 互卦的求法是把本卦234爻做為下卦,把345爻做為上卦。011110,大過卦。
互卦用程式來表示很清楚:
>>> s = '101100'
>>> s[1:4] + s[2:5]
'011110'
接下來,用程式表示八宮卦象變化大概就是這樣:
def get_8_change(s, step):
if step == 0:
return s
elif step == 1:
return _invert_at(s, 0)
elif step == 2:
return _invert_at(s, 1)
elif step == 3:
return _invert_at(s, 2)
elif step == 4:
return _invert_at(s, 3)
elif step == 5:
return _invert_at(s, 4)
elif step == 6:
return _invert_at(s, 3)
elif step == 7:
ss = _invert_at(s, 2)
ss = _invert_at(ss, 1)
ss = _invert_at(ss, 0)
return ss
拿坎宮的八個卦的程式是
s = '010010'
for i in range(8):
s = get_8_change(s, i)
print s, _int_from_bin_r(s), money64[s]
執行結果是:
010010 18 坎
110010 19 節
100010 17 屯
101010 21 既濟
101110 29 革
101100 13 豐
101000 5 明夷
010000 2 師
八宮卦象變化的函式 get_8_change 的 step 0~6 跟京房 16 卦一樣,可以做為基礎繼續改造。