Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
Pythonの数学機能を学ぼう! その仕組も学ぼう!! PyCon JP 2024.9.28 Track3 11:10 - 11:40 Recustomer株式会社 CTO Shugo Manabe @curekoshimizu
Slide 2
Slide 2 text
Profile : 眞鍋 秀悟 ( X: @curekoshimizu ) 略歴 ● 京都大学 / 大学院 ○ 入試一位合格 ○ 数学系 (多倍長数値計算を専門) [今回のお話と少し関係が深い] ● Fixstars ○ Executive Engineer ● Mujin ○ Architect ● Preferred Networks ○ Engineering Mananger ● Hacobu ○ 研究開発部部長・CTO室室長 ● want.jp ○ VPoP ● [Now] Recustomer ○ CTO かなり長い間 Pythonを 業務で使ってきた 2
Slide 3
Slide 3 text
今日のわかることの一例 3
Slide 4
Slide 4 text
-5と-6は違う! 4
Slide 5
Slide 5 text
-5と-6はやっぱり違う! 5
Slide 6
Slide 6 text
とかとか 6
Slide 7
Slide 7 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 7
Slide 8
Slide 8 text
数学的な機能で最も重要なのは? 8
Slide 9
Slide 9 text
数の概念 9
Slide 10
Slide 10 text
Pythonはどのような数を 表現できるのであろうか? 10
Slide 11
Slide 11 text
Pythonが標準的に公開している数表現 1. 整数型 (int) 2. 浮動小数点数型 (float) 3. 複素数型 (complex) 4. 10進多倍長演算型 (Decimal) 5. 有理数型 (Fraction) 11
Slide 12
Slide 12 text
Pythonが標準的に公開している数表現 1. 整数型 (int) 2. 浮動小数点数型 (float) 3. 複素数型 (complex) 4. 10進多倍長演算型 (Decimal) 5. 有理数型 (Fraction) 本日は普段我々が最も使っているであろう、 int・floatという2つの型についてお話していく 12
Slide 13
Slide 13 text
数学の世界との対応 整数 有理数 実数 複素数 13
Slide 14
Slide 14 text
一般的な数学の世界との対応 整数型 (int 型) 有理数型 (Fraction型) ・浮動小数点数型 (float型) ・10進数多倍長型 (Decimal型) ・ 整数型 (int型) : (固定小数点と思うと) 複素数型 (complex型) 14
Slide 15
Slide 15 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 15
Slide 16
Slide 16 text
その前に あなたにとって その前に理想の整数型とは? 16
Slide 17
Slide 17 text
高速であること? 17
Slide 18
Slide 18 text
n + 1 の計算が 絶対にできること? 18
Slide 19
Slide 19 text
例えば同じスクリプト言語として 比較されることもある JavaScript / TypeScript の場合 19
Slide 20
Slide 20 text
例えば同じスクリプト言語として 比較されることもある JavaScript / TypeScript の場合 n + 1 != n となる 20
Slide 21
Slide 21 text
例えば同じスクリプト言語として 比較されることもある JavaScript / TypeScript の場合 n + 1 != n となる n + 1 == n な場合がある 21
Slide 22
Slide 22 text
n + 1 の計算が n と 違うことを保証するのも プログラミング言語に よって違う (JavaScriptはこれを保証していない言語) 22
Slide 23
Slide 23 text
Go言語のようなコンパイル言語の場合 n + 1 をすると 0 などの裏回った値をとりうる 18446744073709551614 + 1 = 18446744073709551615 18446744073709551615 + 1 = 0 23
Slide 24
Slide 24 text
一方で Pythonは任意の整数nに対して n+1 が数学的な「n+1」が一致する 計算結果になる特徴をもつ (当たり前のようで当たり前ではない特徴) 24
Slide 25
Slide 25 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 25
Slide 26
Slide 26 text
整数型 (int) 整数を表すものが整数型 例. ● 0 ● 1 ● 2 ● -5 ● -32 ● 123 ● 10000000000000000000000000000000 26
Slide 27
Slide 27 text
整数型 (int) 整数を表すものが整数型 例. ● 0 ● 1 ● 2 ● -5 ● -32 ● 123 ● 10000000000000000000000000000000 今日はPythonの気持ちで 2つのグループに 分けてみましょう 27
Slide 28
Slide 28 text
正解はいろいろあるのですが あるPythonのお気持ちで分類をするとこんな感じな気がする ● 0 ● 1 ● 2 ● -5 ● 123 ● -32 ● 10000000000000000000000000000000 青グループ 赤グループ 28
Slide 29
Slide 29 text
この分類を正当化するために id 関数を導入することにする 29
Slide 30
Slide 30 text
id 関数 オブジェクトのメモリアドレスを示すもの 上の例では 10 という生成されたオブジェクトの位置がわかる 10 この場所 30
Slide 31
Slide 31 text
id 関数の実行結果例 (環境:Python3.12.6, x86-64) x id(x) 0 4354799288 1 4354799320 2 4354799352 -5 4354799128 123 4354803224 -32 4342934352 10000000000000000000000000000000 4347138224 値がとても近い! 31
Slide 32
Slide 32 text
id 関数の実行結果例2回目 (環境:Python3.12.6, x86-64) x id(x) 0 4354799288 1 4354799320 2 4354799352 -5 4354799128 123 4354803224 -32 4342936240 10000000000000000000000000000000 4347135200 値が不変 値が変化 32
Slide 33
Slide 33 text
id 関数の実行結果例3回目 (環境:Python3.12.6, x86-64) x id(x) 0 4354799288 1 4354799320 2 4354799352 -5 4354799128 123 4354803224 -32 4342934352 10000000000000000000000000000000 4347136640 値が不変 値が変化 33
Slide 34
Slide 34 text
確かに何やらこういう分類がある気がしてきた ● 0 ● 1 ● 2 ● -5 ● 123 ● -32 ● 10000000000000000000000000000000 青グループ 赤グループ 34
Slide 35
Slide 35 text
CPythonより抜粋 -5, -4, .., 255, 256 に属する整数は 実はPython初期化時に 既にオブジェクトが生成されている (CPythonの特徴の一つといえる) 35
Slide 36
Slide 36 text
SMALL_INT -5, -4, .., 255, 256 (SMALL_INT) という数字か否かを確認するコードがあり、特殊扱いされていることがわかる 36
Slide 37
Slide 37 text
同様に初期化時に生成されるオブジェクトとは? -5, -4, .., 255, 256 以外にも初期化時に生成されるオブジェクトがある 例えば True・False・None オブジェクトである。 これらTrue・False・None は x is None などと is 関数で比較することができるオブジェクトである 37
Slide 38
Slide 38 text
is関数のCPythonでの実装 is 関数というのはオブジェクトのPointerが一致しているかを確認している 先ほどの True・False・None や -5, -4, .., 255, 256 という数は 初期化時に一度だけ生成されて、 それ以降はそのオブジェクトを使い回す。 そのため、これらのオブジェクトは isの比較をすることができる 38
Slide 39
Slide 39 text
x=y=True x=y=1 x=5000 y=5000 Trueや1は初期化時に1度だけ生成され、 そのobjectをプログラムで使い回す そのため、objectのポインターがすべて同じになる 5000 は 動的にobjectが生成され、 xとyのobjectは別物。そのためそれぞれのオブ ジェクトのポインターが異なるため is の比較は失敗 39
Slide 40
Slide 40 text
isによる比較ができるものとできないもの このように -5, -4, .., 255, 256 という数は is でも比較できてしまう特殊な実装 になっている。 だから、idも同じ値を返していた。 注意. だからといって、数値型を is をつかって比較すべきではなく、= を使って 比較すべきである 40
Slide 41
Slide 41 text
なぜ特殊実装になっているのか? -5, -4, .., 255, 256 という数は よく使われる可能性が高いためオブジェクトの生成コストを抑えるという 目的で生成されています。 例えば 0 という数は頻繁に登場する値 であり、 生成回数を抑えることにより高速化をしています 41
Slide 42
Slide 42 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 42
Slide 43
Slide 43 text
PyObjectはすべてのルーツ Pythonではすべてのオブジェクトが PyObject の継承になっています。 そのため、 これからお話をする数値型の構造をお話するには、大前提な型になります。 43
Slide 44
Slide 44 text
PyObject型の大雑把な構造 Python3.11のPyObjectの実装 簡易的だが特徴を掴んでいる内容 44
Slide 45
Slide 45 text
PyObject型をC言語がわからない人向けにざっくり 簡易的だが特徴を掴んでいる内容 Python流に表すとこういう構造体 (全体は16Byteのデータ) 45
Slide 46
Slide 46 text
PyObjectは本当に16Byteなのか? sys.getsizeof:生成されたオブジェクトのサイズをPythonから知る方法 46
Slide 47
Slide 47 text
PyObjectからの継承 PyObject PyLongObject : 整数型 PyComplexObject : 複素数型 PyFloatObject : 浮動小数点数型 PyDecObject:10進数多倍長型 Fraction class :有理数 型 47
Slide 48
Slide 48 text
PyObjectからの継承 PyObject PyLongObject : 整数型 PyComplexObject : 複素数型 PyFloatObject : 浮動小数点数型 PyDecObject:10進数多倍長型 Fraction class :有理数 型 こちらをみていくことに! 48
Slide 49
Slide 49 text
PyLongObject型のC言語の正確な構造 PyObject型 を _PyLongValue で Wrapしているような構成 (PyObject型 + _PyLongValue) (C言語で継承を実現しようとすると例えばこうなる) 49
Slide 50
Slide 50 text
PyLongObject型の正確さを犠牲にしたわかりやすい表現 不正確だがわかりやすくした PyLongObject (整数型) PyLongObject のPython流の表現 継承 50
Slide 51
Slide 51 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 51
Slide 52
Slide 52 text
ob_digit が Python の整数型の “long” な特徴 可変長な構造をもっている! (longっぽい) 52
Slide 53
Slide 53 text
Longという用語は Python2からの系譜 PyLongObject : 任意精度の整数 (python long integer object) PyIntObject : 固定長整数 Python2 PyLongObject Python3 統合 もはや対比的についていた名前 “long”は比べる相手がいなくなったのだが 名前としては残っている 53
Slide 54
Slide 54 text
ob_digit という特徴 ob_digt[0] ob_digt[1] ob_digt[2] ob_digt[3] ob_digt[n-1] (必ず非0) ・・・ nが定まる 大きい桁 メモリーが許す限りいくらでも大きな整数を表現できる 54
Slide 55
Slide 55 text
小さい数の表現 ob_digt[0] (必ず非0) 小さい数は1つだけで成立する 55 n = 1
Slide 56
Slide 56 text
0の表現 empty list 0の場合には ob_digit は0個で成立する 56 n = 0
Slide 57
Slide 57 text
大きい数になると可変長領域が増えて objectの大きさが大きくなる PyObject : 16Byte 一番小さい PyLongObject は 28Byte 大きい整数になるにつれてPyLongObjectは 大きくなる 57
Slide 58
Slide 58 text
(余談) str から int を作ろうとしたときは 任意の大きさにはつくれない 58
Slide 59
Slide 59 text
メモリーの中身をみてみよう -5 -4 -3 -2 -1 0 1 int型の意味 参照カウント (最大値) の意味 SMALL_INT(-5, -4, …) は連続してメモリー上に生成されていた! type(...)で int が 返ってくる理由 59
Slide 60
Slide 60 text
(余談) 参照カウントはメモリーをみなくとも Pythonから取得できる SMALL_INTである1は初期化時に生成して 以降削除することはないobjectなので、最大 値をとっている。 一方で、一般的なobjectである1000は その参照カウントが その関数での参照と、x、yの3となる。 生成と破棄はガベージコレクションに任され ることを表している。 60
Slide 61
Slide 61 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 61
Slide 62
Slide 62 text
PyLong同士の足し算を眺める 小さな数 (Compact)とは digits[] が0か1であるかということ 1個だけであれば 足し算をしても、桁上りが発生して、 digitsが増えることはほとんどない だから高速に計算できる! 符号部 * (digits[0]) が実際の数なのでその2数 の足し合わせで計算可能 小さな数同士の足し算の場合 (実用上多くの場合でこのケース) 62
Slide 63
Slide 63 text
PyLong同士の足し算を眺める 符号部を考えて、足し算か引きかを決定 複数のdigitsをもつ計算になる O(digits) の計算量の加減算 (多倍長数の計算になり遅い) 63
Slide 64
Slide 64 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 64
Slide 65
Slide 65 text
浮動小数点数型 (PyFloatObject) PyObject PyLongObject : 整数型 PyComplexObject : 複素数型 PyFloatObject : 浮動小数点数型 PyDecObject:10進数多倍長型 Fraction class :有理数 型 こちら! 65
Slide 66
Slide 66 text
PyFloatObject は simple な構造 PyObjectに一つ 倍精度浮動小数点数 (8Byte) が付与されている構造 PyFloatObjectのPython流な表現 PyFloatObjectのC言語の実装 66
Slide 67
Slide 67 text
整数型に比べて四則演算がとてもシンプル PyFloatObject型の四則演算は単純 CPUが直接計算できる レジスタレベルの計算 ここの中身を 加減乗除 して終わり と 思って大体間違いではないコードになっている 67
Slide 68
Slide 68 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 68
Slide 69
Slide 69 text
mathモジュールは PyFloatObject型のための計算機能 ● acos ● acosh ● asin ● asinh ● atan ● atan2 ● atanh ● cbrt ● ceil ● comb ● copysign ● cos ● cosh ● degrees ● dist ● e ● erf ● erfc ● exp ● exp2 ● expm1 ● fabs ● factorial ● floor ● fmod ● frexp ● fsum ● gamma ● gcd ● hypot ● inf ● isclose ● isfinite ● isinf ● isnan ● isqrt ● lcm ● ldexp ● lgamma ● log ● log10 ● log1p ● log2 ● modf ● nan ● nextafter ● perm ● pi ● pow ● prod ● radians ● remainder ● sin ● sinh ● sqrt ● tan ● tanh ● tau ● trunc ● ulp とてもたくさん! 69
Slide 70
Slide 70 text
これらの呼び出しで 一体何が起こるのだろうか? math.exp関数を例にとりあげる 70
Slide 71
Slide 71 text
exp関数の呼び出しはどうなっているのだろうか? math_exp 関数を呼ぶと math_1 という関数に exp という関数ポインタ を渡すという実装になっている ここの func が exp 関数の本体! 71
Slide 72
Slide 72 text
exp関数の呼び出しはどうなっているのだろうか? 共有ライブラリ libm の expf64 を呼び出しているだけ (環境は x86_64, linux) 72
Slide 73
Slide 73 text
exp関数の呼び出しはどうなっているのだろうか? ここに書いている通り 「libmのwrapperなのである」 73
Slide 74
Slide 74 text
(余談) Go言語はexp関数を自作している点が面白い 多くのプログラミング言語が libmに依存している中 Go はこういうところに ユニークさをもった言語でもある 74
Slide 75
Slide 75 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 75
Slide 76
Slide 76 text
mathライブラリに 久々に追加される関数がありますね math.fma が Python3.13 で追加されます 76
Slide 77
Slide 77 text
fma関数とは? fma(x, y, z) をすると x * y + z をする関数です 77
Slide 78
Slide 78 text
そんな普通の関数って なにかすごいんですか? 78
Slide 79
Slide 79 text
fma関数とは? x * y + z という積和演算を1度に計算してくれるんです! (注. CPUがサポートしている場合にのみ) 79
Slide 80
Slide 80 text
いまいち良さがわからないです… という 感想が聞こえてきそう 80
Slide 81
Slide 81 text
コンピュータの 理論ピーク性能ってどうやって 計算するんだったか を思い出してみる 81
Slide 82
Slide 82 text
GeForce RTX 4090 の単精度理論ピーク性能 を計算してみる (注. どんなアーキテクチャでもこの計算方法というわけではない) 16384 (Cores) × 2.52 (GHz) × 2 (FLOPS/CLOCK × Cores)) = 82.58TFLOPS 1度の計算で積和演算 (FMA) という 2回の浮動小数点計算をすることが 前提の「2」 積和演算がないと「1」になってしまう FLOPSとは 1秒間に何回浮動小数点の 計算ができるかの意味 82
Slide 83
Slide 83 text
FMAは計算機の 理論ピーク性能の計算にも 利用されている 性能を引き出すために必要な 命令の一つ 83
Slide 84
Slide 84 text
今日は2024.9.28! Python3.13 2024.10.1 のリリースが より楽しみになりましたね! 84
Slide 85
Slide 85 text
まだまだ進化の止まらない 数学関数の今後に期待です! 85
Slide 86
Slide 86 text
● Pythonにおける数値型について ● 整数型について深堀り ○ SMALL_INTの導入 ○ CPythonにおける整数型の実装 ○ 整数型と多倍長整数 ○ 四則演算について ● 浮動小数点型について深堀り ● math moduleの関数について深堀り ○ 関数の呼び出し方 ○ Python3.13とmath moduleの展望 ● 最後に 本日お話をすること 86
Slide 87
Slide 87 text
本当は喋りたかったがスライドを作ってみた結果 時間の都合上入らなかった内容 ● SMALL_INTだけではなくMEDIUM_INT・COMPACTについて ● INTの多倍長整数演算の実装について ● libmの中身の数学関数の実装について ● Pythonのバイトコードへの展開と工夫について ● 有理数型と浮動小数点数型など数値型の使い分けについて ● 今回登場していたCPythonのデバッグ方法について ● numpyの素晴らしさ (なぜ自前で行列計算ライブラリを実装してはいけないか) いつかこういうお話ができる機会があると 非常にうれしいです! 87
Slide 88
Slide 88 text
全員で7名のエンジニア しかいないため Pythonが大好きな方 大募集中です! 27番ブースでお待ちしております 88
Slide 89
Slide 89 text
ご清聴ありがとうございました @curekoshimizu 89