pythonで0、自然数、整数、有理数を作り、四則演算を作ります。
Pythonで0を作ろう
View Slide
はじめまして!神です。
はじめまして!今日は数を作っていきます。理由は、数を作りたいからです。
ルール● Pythonを使う● int, float型とfor文禁止(ただし、一部省略記法としてintを使います)● 有理数の四則演算まで作る
0を作りたい材料がない!
0を作ろう世界にまだ何も存在していないので、0を作る材料がありません。しかしこの世界には「材料がない」という唯一の材料があるのでこれを使いますzero = []
1を作ろうこの世界には「材料がない」という唯一の材料がありますが使ってしまいましたしかしご安心を。この世界には今、材料が生まれました!それを使いましょう!zero = []one = [zero] # = [[]]
2を作ろう2はどうしましょうか。two = [one]としてもいいし、two = [zero, zero]としてもいいです。ただ、今回はこうします。zero = []one = [zero] # = [[]]two = [zero, one] # = [[], [[]]]
自然数を作ろう実は two + [two] = [zero, one] + [two] = [zero, one, two] = threeとなります。以降はそうやって自然数を作りましょう。zero = []one = [zero] # = [[]]two = [zero, one] # = [[], [[]]]three = two + [two] # = [zero, one, two]※0は大学数学においては自然数に含む
1を足す関数を作ろうさっき言ったようにこうやって x + 1を計算できます。# 1を足す関数 後者関数 successor functiondef suc(x: Natural) -> Natural:""" x + 1 を計算する"""return x + [x]※Natural型 = list型
1を引く関数を作ろう1を引く関数はリストの一番最後を消せばいいのでこうすればいいです。int型の「-1」を使ってますが、pop()を使えばいいので省略記法として使います。def pre(x: Natural) -> Natural:""" x - 1 を計算する x=0ならエラー"""return x[:-1]今できること● 1を足す
大小関係を作ろうなんと大小関係が1行で判定できる。最高!def is_bigger(x: Natural, y: Natural) -> bool:""" x < y かを判定する"""return x in y今できること● 1を足す● 1を引く
足し算を作ろう1を足すことと1を引くことしかできず、for文も禁止なので再帰で書きます。x + 0 = x、x+y = (x+1)+(y-1)。それはそう。def plus(x: Natural, y: Natural) -> Natural:if y == zero:return x # x + 0 = xelse:return plus(suc(x), pre(y)) # x+y = (x+1)+(y-1)今できること● 1を足す● 1を引く● 大小関係
掛け算を作ろう足し算を繰り返して再帰で書きます。x * 0 = 0、x * y = x * (y-1) + x。それはそう。def mul(x: Natural, y: Natural) -> Natural:if y == zero:return zero # x * 0 = 0else:# x * y = x * (y-1) + xreturn plus(mul(x, pre(y)), x)今できること● 1を足す● 1を引く● 大小関係● 足し算
掛け算まで作れたやったー!!今できること● 1を足す● 1を引く● 大小関係● 足し算● 掛け算
引き算を作りたい引き算を「1を引く」の再帰で作ると答えが負のときに困るので、やりたくないです。どうにかして x - y = z を今できることで表現できないでしょうか…?今できること● 1を足す● 1を引く● 大小関係● 足し算● 掛け算x - y = z
引き算を作りたい引き算を「1を引く」の再帰で作ると答えが負のときに困るので、やりたくないです。どうにかして x - y = z を今できることで表現できないでしょうか…?今できること● 1を足す● 1を引く● 大小関係● 足し算● 掛け算x - y = zx = z + y ←!!!!!!
整数を作ろうa - b = c - d の時、 a + d = c + b です。整数を自然数の2つ組で表現しましょう!自然数a,bを使って整数 a-bを(a, b)と表現します!(1,4) = -3 , (0,0) = 0, (20, 21) = -1, (0,3) = -3 です!Integer = tuple[Natural, Natural]今できること● 1を足す● 1を引く● 大小関係● 足し算● 掛け算※int型とInteger型は異なる
整数を作ろうa - b = c - d の時、 a + d = c + b です。整数を自然数の2つ組で表現しましょう!自然数a,bを使って整数 a-bを(a, b)と表現します!(1,4) = -3 , (0,0) = 0, (20, 21) = -1, (0,3) = -3 です!(1,4) = (0,3) になってるけど大丈夫?Integer = tuple[Natural, Natural]今できること● 1を足す● 1を引く● 大小関係● 足し算● 掛け算※int型とInteger型は異なる
整数の「=」を作ろう整数が等しいかを判定するためにInteger型の「=」を作る。a-b = c-d なら a+d = b+c なので簡単 x[0]やx[1]はNatural型なので足し算できる!def eq_i(x: Integer, y: Integer) -> bool:"""x[0] - x[1] == y[0] - y[1] かを判定する"""return plus(x[0], y[1]) == plus(y[0], x[1])今できること● 自然数○ 1を足す○ 1を引く○ 大小関係○ 足し算○ 掛け算※Integerを型ではなくクラスで表現すれば添字 [0][1]は使わずに済むので、ここでの int型0,1は許容
整数の足し算を作ろう(a-b) + (c-d) = (a+c) - (b+d)なので自然数の足し算だけで作れる!def plus_i(x: Integer, y: Integer) -> Integer:""" x+y を計算する"""# a-b + c-d = (a+c) - (b+d)return (plus(x[0], y[0]), plus(x[1], y[1]))今できること● 自然数○ 1を足す○ 1を引く○ 大小関係○ 足し算○ 掛け算● 整数○ 「=」
整数の単項マイナスを作ろうa-b = b-aなのでそのままdef neg_i(x: Integer) -> Integer:""" -x を計算する"""return (x[1], x[0])今できること● 自然数○ 1を足す○ 1を引く○ 大小関係○ 足し算○ 掛け算● 整数○ 「=」○ 足し算
整数の引き算を作ろうx - y = x + (-y)より作れる。def minus_i(x: Integer, y: Integer) -> Integer:""" x-y を計算する"""return plus_i(x, neg_i(y)) # x-y = x + (-y)今できること● 自然数○ 1を足す○ 1を引く○ 大小関係○ 足し算○ 掛け算● 整数○ 「=」○ 足し算○ 正負逆転
整数の掛け算を作ろうテキトーにやれば面倒だが出来る。(a-b)*(c-d)=(a*c-b*c) - (a*c - b*d)def mul_i(x: Integer, y: Integer) -> Integer:x_mul_y0: Integer = (mul(x[0],y[0]), mul(x[1],y[0]))x_mul_y1: Integer = (mul(x[0],y[1]), mul(x[1],y[1]))return minus_i(x_mul_y0, x_mul_y1)今できること● 自然数○ 1を足す○ 1を引く○ 大小関係○ 足し算○ 掛け算● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算
整数と引き算が作れた今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算もう自然数は整数の下位互換なので要りませんやったー!!
割り算を作りたいx / y = z↑これを足し算引き算掛け算だけで表現できないか今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算
割り算を作りたいx / y = zx = z * y今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算←!!!!!!
有理数を作ろうなんと!有理数は2つの整数から作ることが出来ます!知ってた。有理数 x / y を(x, y) と表します!Rational = tuple[Integer, Integer]今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算
有理数の「=」を作ろうa / b = c / d ならば a * d = c * bなのでこうなります。def eq_r(x: Rational, y: Rational) -> bool:return eq_i(mul_i(x[0], y[1]),mul_i(x[1], x[0]))今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算
有理数の掛け算を作ろう有理数はみなさん御存知の通り掛け算が一番楽なので作ります。(a / b) * (c / d) = (a*c) / (b*d)def mul_r(x: Rational, y: Rational) -> Rational:""" x*y を計算する"""return (mul_i(x[0], y[0]), mul_i(x[1], y[1]))今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算● 有理数○ 「=」
有理数の割り算を作ろう有理数はみなさん御存知の通り割り算が二番楽(?)なので作ります。(a / b) / (c / d) = (a*d) / (b*c)def div_r(x: Rational, y: Rational) -> Rational:""" x/y を計算する"""return (mul_i(x[0], y[1]), mul_i(x[1], y[0]))今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算● 有理数○ 「=」○ 掛け算
有理数の単項マイナスを作ろう分数をマイナスにするのは分子にマイナスつけるだけです。def neg_r(x: Rational) -> Rational:""" -x を計算する"""return (neg_i(x[0]), x[1])今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算● 有理数○ 「=」○ 掛け算○ 割り算
有理数の足し算を作ろうなんかごちゃごちゃ計算したらできます。読まなくていいです。def plus_r(x: Rational, y: Rational) -> Rational:numerator = plus_i(mul_i(x[0], y[1]), mul_i(x[1], y[0]))denominator = mul_i(x[1], y[1])return (numerator, denominator)今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算● 有理数○ 「=」○ 掛け算○ 割り算○ 正負逆転
有理数の引き算を作ろうなんかごちゃごちゃ計算したらできます2。読まなくていいです2。…と思いきや足し算と単項マイナスがあるので楽です。今できること● 整数○ 「=」○ 足し算○ 正負逆転○ 引き算○ 掛け算● 有理数○ 「=」○ 掛け算○ 割り算○ 正負逆転○ 足し算def minus_r(x: Rational, y: Rational) -> Rational:""" x-y を計算する"""return plus_r(x, neg_r(y))
有理数と割り算が作れたもう整数は有理数の下位互換なので要りませんやったー!!今できること● 有理数○ 「=」○ 掛け算○ 割り算○ 正負逆転○ 足し算○ 引き算
結論:四則演算がリストから作れた!今回の数や演算の作り方は、数学における数の作り方の内、もっともメジャーなもの(ZFC)とほぼ同じです。数学に「リスト」という構造は、0や1がないと作れない(はず…)ので、本来は集合をつかって定義されます!なお有理数をさらに進めた実数については、デデキントカットか無限数列の極限で定義されますが、どちらも有理数を無限個使うのでコンピュータじゃ無理です。というか現実では不可能。
うれしい!満足したので帰ります。
参考資料元ネタhttps://www.nicovideo.jp/watch/sm32548726琴葉姉妹の数学キソ論:第1回「1+1=2を証明して?」 ↑全人類見ろ https://qiita.com/taketo1024/items/2ab856d21bf9b9f30357「Swiftで自然数を作ってみた(ペアノの公理)」 他、https://qiita.com/search?q=自然数を作る 内の記事 Qiitaの「数字を作る」系の記事、 だいたい足し算・掛け算までしかやらないがちなのでこのLT作った