通常大きな数字は、整数の配列として格納されています。各整数は1桁を表します。このアプローチでは、配列の単純な左シフトで任意の数に基数の累乗を掛けることができます。ここ
は私のリストベースの実装(バグを含んでいてもよい)である。
def normalize(l,b):
over = 0
for i,x in enumerate(l):
over,l[i] = divmod(x+over,b)
if over: l.append(over)
return l
def sum_lists(x,y,b):
l = min(len(x),len(y))
res = map(operator.add,x[:l],y[:l])
if len(x) > l: res.extend(x[l:])
else: res.extend(y[l:])
return normalize(res,b)
def sub_lists(x,y,b):
res = map(operator.sub,x[:len(y)],y)
res.extend(x[len(y):])
return normalize(res,b)
def lshift(x,n):
if len(x) > 1 or len(x) == 1 and x[0] != 0:
return [0 for i in range(n)] + x
else: return x
def mult_lists(x,y,b):
if min(len(x),len(y)) == 0: return [0]
m = max(len(x),len(y))
if (m == 1): return normalize([x[0]*y[0]],b)
else: m >>= 1
x0,x1 = x[:m],x[m:]
y0,y1 = y[:m],y[m:]
z0 = mult_lists(x0,y0,b)
z1 = mult_lists(x1,y1,b)
z2 = mult_lists(sum_lists(x0,x1,b),sum_lists(y0,y1,b),b)
t1 = lshift(sub_lists(z2,sum_lists(z1,z0,b),b),m)
t2 = lshift(z1,m*2)
return sum_lists(sum_lists(z0,t1,b),t2,b)
sum_lists
とsub_lists
戻る非正規化結果 - 一桁が基準値よりも大きくすることができます。 normalize
関数がこの問題を解決しました。
すべての関数は、逆の順序で桁のリストを取得することを想定しています。たとえば、基数10の12は[2,1]と書かれます。上の改善分割し、代わりに4の3つの再帰呼び出しを行うことにより、乗算アルゴリズムを征服するKarastuba乗算の目標がある9987654321.
» a = [1,2,3,4,5,6,7,8,9]
» res = mult_lists(a,a,10)
» res.reverse()
» res
[9, 7, 5, 4, 6, 1, 0, 5, 7, 7, 8, 9, 9, 7, 1, 0, 4, 1]
もちろん、再帰は停止しません。再帰を停止させる条件はどこですか? – neurino
私はおそらく、 'x0、x1 = divmod(x、bm)'を使う方が速いでしょう。 – utdemir
@neurino、最初の行にif文が返されます。 – utdemir