Python AtCoder入門 第2講 演算・変数・型 第1講で、入力を受け取って出力する方法を身につけました。 この講では、その真ん中の 計算する 部分を扱います。 1
今回のテーマ 四則演算そのものは難しくありません。 ただしAtCoderでは、 割り算 に関する知識が、ACとWAの分かれ目になることがあります。 2
この講のゴール この講のゴールは、 割り算で事故を起こさない体を作ること です。 特に、 / 、 // 、 % の違いをしっかり身につけます。 3
コードファイル名の方針 この講でも、コード例ごとにファイル名を付けます。 例: operators.py division.py mod.py ceil_division.py answer_2_1.py 手元では同じ名前で保存して実行してください。 4
2-1 四則演算と整数演算 Pythonの四則演算は、数学の記号とほぼ同じです。 ただし、割り算には複数の種類があります。 ここを曖昧にしたまま進むと、AtCoderではWAの原因になります。 5
基本の演算子 演算子 + * / 意味 足し算 引き算 掛け算 割り算 例 結果 7 + 2 9 7 - 2 5 7 * 2 14 7 / 2 3.5 6
整数演算でよく使う演算子 演算子 // % ** 意味 整数除算 余り 累乗 例 結果 7 // 2 3 7 % 2 1 7 ** 2 49 AtCoderでは、 // と % が特に重要です。 7
計算の優先順位 計算の優先順位は、数学とほぼ同じです。 1. ** 2. * / // % 3. + 順番を変えたいときは、丸括弧を使います。 8
operators.py print(2 + 3 * 4) print((2 + 3) * 4) 出力: 14 20 括弧を使うと、先に計算する場所を指定できます。 9
3種類の割り算 AtCoderで最も重要なのは、この3つの使い分けです。 / :普通の割り算。結果は必ず小数 // :商の整数部分 % :余り 10
/ は必ず小数になる / は、割り切れる場合でも小数になります。 print(6 / 2) print(6 // 2) 出力: 3.0 3 3 ではなく 3.0 になる点に注意してください。 11
整数の答えには // 答えが整数になる問題では、 / ではなく // を使う のが鉄則です。 6 / 2 をそのまま出力すると 3.0 になり、 3 を求める問題ではWAになります。 12
division.py A = 17 B = 5 # True division: the result is always a float print(A / B) # Floor division: the result is an integer print(A // B) # Remainder print(A % B) 13
division.py の出力 3.4 3 2 17 = 5 × 3 + 2 商は 3 余りは 2 です。 なので、 14
負の数での注意 Pythonの // は、正確には 小さいほうへ丸める 演算です。 負の数では、直感とずれることがあります。 15
negative_division.py print(-7 // 2) print(-7 % 2) 出力: -4 1 -3.5 を -4 に丸めます。 16
A・B問題では深追いしなくてよい AtCoderのA・B問題では、 負の数の割り算が重要になる場面は多くありません。 まずは、 そういう仕様がある と知っておけば十分です。 17
余りの活用 は、単に余りを求めるだけではありません。 よく使う用途は次の2つです。 1. 偶数・奇数の判定 2. 周期性の処理 % 18
偶数・奇数の判定 2で割った余りを調べます。 N % 2 なら偶数 1 なら奇数 です。 0 19
周期性の処理 ぐるぐる回るものには % が使えます。 例: 24時間で1日 → % 24 7日で1週間 → % 7 時刻や曜日の計算でよく登場します。 20
mod.py N = 25 # Check whether N is even or odd if N % 2 == 0: print("Even") else: print("Odd") # What time is it 100 hours after 20:00? hour = (20 + 100) % 24 print(hour) 21
mod.py の出力 Odd 0 は奇数です。 20時の100時間後は、24時間周期で考えると 0 時です。 25 22
if文は第3講で扱う このコードには if 文が出てきました。 if N % 2 == 0: print("Even") else: print("Odd") 詳しくは第3講で学びます。 ここでは形だけ見ておけば十分です。 23
2-2 変数と型 次は、変数と型を確認します。 AtCoderでは、難しい型の知識は必要ありません。 まずは、 整数 小数 文字列 真偽値 を押さえます。 24
代入 変数には = で値を入れます。 x = 10 これは数学の等号ではありません。 右辺の値を、左辺の変数に入れる命令 です。 25
再代入 変数には、あとから別の値を入れ直せます。 x = 10 x = x + 5 print(x) 出力: 15 26
assignment.py x = 10 print(x) x = x + 5 print(x) 出力: 10 15 x = x + 5 は、今の x に5を足して入れ直す、という意味です。 27
省略した書き方 次の2つは同じ意味です。 x = x + 5 x += 5 ほかにも、次のように書けます。 x -= 3 x *= 2 28
update_variable.py x = 10 x += 5 print(x) x -= 3 print(x) x *= 2 print(x) 出力: 15 12 24 カウント処理でよく使います。 29
AtCoderでよく使う型 型 int float str bool 意味 整数 小数 文字列 真偽値 例 , -7 , 0 3.5 , 2.0 "abc" , "5" True , False 42 30
型を確認する 型は type() で確認できます。 print(type(5)) print(type(5.0)) print(type("5")) デバッグのときに役立ちます。 31
types.py print(type(5)) print(type(5.0)) print(type("5")) 出力: <class 'int'> <class 'float'> <class 'str'> 5 、 5.0 、 "5" はすべて別物です。 32
5 と "5" は違う 5 は整数です。 "5" は文字列です。 第1講で学んだように、 input() が返すのは文字列です。 33
型を変換する 型は、次の関数で変換できます。 int(x) :整数にする float(x) :小数にする str(x) :文字列にする AtCoderでは特に int() をよく使います。 34
convert.py print(int("42") + 1) print(str(42) + "点") print(int(3.9)) 出力: 43 42点 3 int(3.9) は 4 ではなく 3 です。 35
intは四捨五入ではない は小数を整数にします。 ただし、四捨五入ではありません。 int() print(int(3.9)) 出力: 3 小数点以下を切り捨てます。 36
type_convert.py # input() always returns a string S = "42" print(S, type(S)) # Convert the string to an integer N = int(S) print(N, type(N)) # Convert the number to a string print("Answer: " + str(N)) # int() truncates the decimal part print(int(3.9)) 37
type_convert.py の出力 42 <class 'str'> 42 <class 'int'> Answer: 42 3 文字列と数値を + でつなぐときは、数値を str() に変換します。 38
printにカンマで渡す方法 文字列と数値を一緒に出したいときは、 print("Answer:", N) のようにカンマ区切りにするのも簡単です。 この場合、自動で空白が入ります。 39
2-3 AtCoderで注意すべき数値の扱い ここが本講の山場です。 次の3つは、実際にWAを生みます。 1. 浮動小数点誤差 2. 大きな整数 3. 切り上げ割り算 40
① 浮動小数点誤差 コンピュータは、小数を完全に正確には表せません。 そのため、次のようなことが起きます。 print(0.1 + 0.2) print(0.1 + 0.2 == 0.3) 41
float_error.py print(0.1 + 0.2) print(0.1 + 0.2 == 0.3) 出力: 0.30000000000000004 False 0.1 + 0.2 が 0.3 と完全には一致しません。 42
大きな数ではさらに危険 を使うと、結果は float になります。 大きな整数を float にすると、正確に表せないことがあります。 / 43
big_float_error.py print(10 ** 18 // 3) print(int(10 ** 18 / 3)) 出力: 333333333333333333 333333333333333312 同じように見える計算でも、答えがずれています。 44
教訓 整数の計算に、 / を使わない ことです。 整数の商が欲しいときは、 // を使います。 45
float_experiment.py # A small decimal error print(0.1 + 0.2) print(0.1 + 0.2 == 0.3) # A large error caused by float division print(10 ** 18 // 3) print(int(10 ** 18 / 3)) 46
float_experiment.py の出力 0.30000000000000004 False 333333333333333333 333333333333333312 / を使った時点で、 float になってしまいます。 47
② Pythonの整数は桁あふれしない Pythonの整数には、基本的に上限がありません。 非常に大きな数でも正確に計算できます。 print(2 ** 100) print(10 ** 18 * 10 ** 18) 48
big_int.py print(2 ** 100) print(10 ** 18 * 10 ** 18) 出力: 1267650600228229401496703205376 1000000000000000000000000000000000000 整数のままなら、値は壊れません。 49
壊れるのはfloatが混ざったとき 整数のまま計算している限り、Pythonでは正確です。 値が壊れるとしたら、 float が混ざったとき です。 ここでも結論は同じです。 / を避けて // を使う。 50
big_integer_calc.py A = 10 ** 18 B = 10 ** 18 # Integers never overflow in Python print(A * B) # Integer division stays exact print(A * B // 7) # Float division loses precision print(A * B / 7) 51
big_integer_calc.py の出力 1000000000000000000000000000000000000 142857142857142857142857142857142857 1.4285714285714285e+35 3つ目は指数表記になり、正確な整数としては使えません。 52
指数表記とは 次のような表示です。 1.4285714285714285e+35 これは、 1.428571... × 10^35 という意味です。 ただし、表示の問題だけではありません。 53
表示だけ直してもダメ x = 10 ** 18 * 10 ** 18 / 7 print(int(x)) print(f"{x:.0f}") 出力: 142857142857142850026702429352886272 142857142857142850026702429352886272 整数の形には見えますが、正しい値ではありません。 54
正しい値との比較 計算方法 // / 値 142857142857142857142857142857142857 のあと表示修正 142857142857142850026702429352886272 上位十数桁までしか合っていません。 55
原因は表示ではない 問題は指数表記そのものではありません。 / を使った時点で float になり、 その瞬間に情報が失われている ことが原因です。 失われた情報は、あとから戻せません。 56
表示ではなく計算方法を直す 整数の答えが欲しいなら、 // を使います。 表示を直すのではなく、そもそもfloatにしない。 これが大切です。 57
③ 切り上げ割り算の定石 よくある問題です。 N個の品物を、1箱にK個ずつ詰める。 箱はいくつ必要か? これは N ÷ K を切り上げます。 58
例:10個を3個ずつ詰める N = 10 K = 3 なら、 10 ÷ 3 = 3.33... です。 箱は3個では足りないので、答えは 4個 です。 59
math.ceil は避けたい 素直に書くと、 math.ceil(N / K) ですが、これは / を使います。 N が大きいと、誤差で狂う可能性があります。 60
整数だけで切り上げる 切り上げ割り算の定石は、 (N + K - 1) // K です。 整数だけで計算できるので、安全です。 61
なぜこれで切り上がるのか 割り切れる場合: N = 9, K = 3 (9 + 2) // 3 = 11 // 3 = 3 余計に増えません。 62
割り切れない場合 割り切れない場合: N = 10, K = 3 (10 + 2) // 3 = 12 // 3 = 4 余りがあるときだけ、商が1つ繰り上がります。 63
ceil_division.py N = 10 K = 3 # Floor division print(N // K) # Ceiling division using integers only print((N + K - 1) // K) # It also works when N is divisible by K N = 9 print((N + K - 1) // K) 64
ceil_division.py の出力 3 4 3 切り上げ割り算は、今後何度も出てきます。 形ごと覚えましょう。 65
章末まとめ 割り算は3種類あります。 / :必ず小数になる // :商の整数部分 % :余り 答えが整数の問題では、 / を使わないようにしましょう。 66
章末まとめ:余り はよく使います。 偶奇判定: N % 2 時刻計算: % 24 曜日計算: % 7 周期のある問題で便利です。 % 67
章末まとめ:変数と型 は x = x + 1 と同じ 主な型は int / float / str / bool 型は type() で確認できる int() は四捨五入ではなく切り捨て x += 1 68
章末まとめ:小数に注意 小数には誤差があります。 0.1 + 0.2 == 0.3 は False です。 整数の計算では、できるだけ整数のまま処理します。 69
章末まとめ:大きな数 Pythonの整数は桁あふれしません。 ただし、 float が混ざると精度が落ちます。 整数の答えが欲しいなら、 // を使いましょう。 70
章末まとめ:切り上げ割り算 切り上げ割り算の定石は、 (N + K - 1) // K です。 箱詰め、ページ数、グループ分けなどで頻出です。 71
練習問題 2-1 あめの分配 個のあめを B 人で等しく分けます。 1人あたり何個もらえるかと、何個余るかを、この順に空白区切りで1行に出力してください。 A 72
練習問題 2-1:入力と出力 入力: A B 入力例: 17 5 出力例: 3 2 商は // 、余りは % で求めます。 73
answer_2_1.py # Read two integers separated by a space A, B = map(int, input().split()) # Print the quotient and the remainder print(A // B, A % B) / を使うと小数になるので、この問題では使いません。 74
練習問題 2-2 箱詰め 個の品物を箱に詰めます。 1つの箱には最大 K 個まで入ります。 すべての品物を詰めるために必要な箱の個数を出力してください。 N 75
練習問題 2-2:入力と出力 入力: N K 入力例: 10 3 出力例: 4 切り上げ割り算を使います。 76
answer_2_2.py # Read two integers separated by a space N, K = map(int, input().split()) # Ceiling division using integers only print((N + K - 1) // K) math.ceil(N / K) より安全です。 77
練習問題 2-3 巨大な積 3つの整数 A , B , C が与えられます。 A × B × C を出力してください。 非常に大きな答えになる可能性があります。 78
練習問題 2-3:入力と出力 入力: A B C 入力例: 1000000000000000000 1000000000000000000 2 出力例: 2000000000000000000000000000000000000 79
answer_2_3.py # Read three integers separated by a space A, B, C = map(int, input().split()) # Python integers have no upper limit print(A * B * C) Pythonの整数なら、そのまま掛け算できます。 80
次回予告 次の第3講では、 条件分岐 を扱います。 この講で先取りして使った if 文を、正面から学びます。 81