Skip to content
This page has been auto-translated and may contain errors.View in English

数値と算術演算

数値はほとんどすべてのプログラムに登場します。ショッピングカートで価格を合計する。ゲームでスコアを更新する。スクリプトで何かが発生した回数を数える。Python は紙で行う計算と同じように動作する算術演算子に加えて、最初から知っておく価値のあるものをいくつか提供しています。

Python の算術演算子は、標準的なものに加え、整数除算、剰余、べき乗をカバーします。実用上重要な、他言語と異なる挙動がいくつかあります。/ は常に float を返し、切り捨て除算は負の無限大方向に丸められ、剰余は真の剰余(modulo)のセマンティクスに従います。

Python の数値階層: int(任意精度)、float(IEEE 754 binary64)、complex(ここでは扱いません)。算術演算子は C 言語の慣例ではなく数学的な定義に従います。// は切り捨て除算(負の無限大方向)、% は除数の符号を引き継ぎ、両者を組み合わせるとすべての整数入力について恒等式 a == (a // b) * b + (a % b) を満たします。

演算子

算数の四則演算子(+, -, *, /)は期待どおりに動作します。Python はそれに加えて、よく使う 3 つの演算子を提供します: 整数除算、剰余、べき乗です。

標準的な 4 つの演算子は期待どおりの挙動ですが、一つ重要な規則があります: / は結果が整数値であっても常に float を返します。追加の 3 つの演算子は、余計な手間をかけずに表現できる範囲を広げてくれます。

7 つの演算子はすべて dunder メソッドに対応します: +__add__//__floordiv__%__mod__**__pow__ といった具合です。int/float が混在する演算は float に拡張されます。/ はオペランドの型に関係なく常に float を返します。

python
price    = 12.99
quantity = 3

print(price * quantity)   # 38.97
print(price + 2)          # 14.99
print(price - 1.00)       # 11.99
演算子名称結果
+加算5 + 38
-減算5 - 32
*乗算5 * 315
/除算5 / 31.6666...
//整数除算5 // 31
%剰余5 % 32
**べき乗5 ** 3125

除算: ///

/ は、答えが整数になる場合でも常に正確な小数の結果を返します。// は整数部分のみを返し、小数点以下をすべて切り捨てます。四捨五入ではなく、切り捨てです:

/ は、入力が整数かどうかにかかわらず常に float を返します。// は結果の床(floor)を返します: 真の結果以下の最大の整数です。正の数では切り捨て(truncation)と同じですが、負の数では異なります:

/ は真の除算で、常に float を返します。// は切り捨て除算(floor division): 真の商に math.floor() を適用し、ゼロ方向ではなく常に負の無限大方向に丸めます。これは整数除算が切り捨てとなる C や Java とは異なります。数学的な利点として、Python の //% はすべての整数入力(負の値を含む)について恒等式 a == (a // b) * b + (a % b) を満たします。C のゼロ方向への切り捨て除算は負の値に対してこの恒等式を満たしません。

python
10 / 2     # 5.0   (常に float、割り切れる場合でも)
10 / 3     # 3.3333333333333335

10 // 3    # 3
7  // 2    # 3
-7 // 2    # -4    (ゼロ方向ではなく負の無限大方向に丸める)

-7 // 2 の結果は意外に思われます。// は主に正の数で使うことが多く、その場合はこの問題は発生しません。負の数が登場したときのために、頭の片隅に置いておいてください。

Python はこれを**切り捨て除算(floor division)**と呼びます。数学的な床関数を適用するからです。他の言語ではゼロ方向に切り捨て、負の数に対して異なる結果になります。// という記法はヒントです: 割って、床関数を適用する、と覚えてください。

// は切り捨てではなく floor(a / b) を実装します。恒等式 a == (a // b) * b + (a % b) は Python ではすべての整数入力で成立します。C や Java では / はゼロ方向に切り捨てるため、この恒等式は負の値で破綻し、% は真の剰余(除数の符号を取る)ではなく余り演算子(被除数の符号を取る)として動作します。

剰余演算子 %

% は整数除算後の余りを返します。10 // 33 であるなら(3 は 10 に 3 回入るから)、10 % 31 です(3 × 3 = 9、10 - 9 = 1 だから)。最も一般的な用途は、ある数が偶数か奇数かを判定することです。

% は剰余演算子です。偶数/奇数の判定は分かりやすい用途ですが、循環や折り返しの問題全般に一般化できます: カウンタを範囲内に保つ、アイテムをグループに分配する、シーケンスを繰り返す、など。パターンは常に value % limit で、結果は 0 から limit - 1 の間に収まります。

Python の % は真の剰余(modulo)で、結果は常に除数の符号を引き継ぎます。これは % が余り演算子で被除数の符号を取る C や Java と異なります。Python では -7 % 3-1 ではなく 2 です。剰余は a - (a // b) * b と定義され、// が負の無限大方向に丸められるためです。この一貫した符号の挙動こそが、負の入力を含む循環や折り返しで % を信頼できるものにしています。

python
10 % 3    # 1
10 % 2    # 0  (割り切れる)
10 % 7    # 3

6 % 2     # 0  (偶数)
7 % 2     # 1  (奇数)

べき乗 **

** は数値をべき乗します。アスタリスクを 2 つ使い、^ 記号ではない点に注意してください(Python では ^ は別の意味を持ちます):

** はべき乗です。float でも動作するため、別の関数呼び出しを使わずに小数のべき乗として平方根などを表現できます:

**__pow__ を呼び出します。2 つの int オペランドでは int を返し、float オペランドが含まれていれば float を返します。一つ優先順位の罠があります: -2 ** 2-(2 ** 2) として解釈されます。** が単項マイナスよりも結合が強いため、結果は 4 ではなく -4 です。括弧を使ってください: (-2) ** 2

python
2 ** 10    # 1024
3 ** 3     # 27
9 ** 0.5   # 3.0  (平方根: 0.5 乗する)

演算子の優先順位

Python は標準的な算数の順序に従います: 最初にべき乗、次に乗算と除算、最後に加算と減算です。確信が持てない場合は括弧を使ってください。意図が明確になり、コストもかかりません:

Python は標準的な PEMDAS/BODMAS の順序に従います。よく引っかかるのは、///% がすべて同じ優先順位レベルで、混在すると左から右に評価される点です。括弧は無料です。順序が一目で明らかでない場合は常に使いましょう:

算術演算子の優先順位(高い順): **、次に単項 -、次に * / // %(同じ優先順位では左から右)、最後に + -。単項マイナスと ** の相互作用は微妙な罠です: -2 ** 2-(2 ** 2) = -4 です。単項マイナスは ** よりも結合が弱いためです。否定とべき乗を組み合わせるときは常に括弧をつけてください。

python
2 + 3 * 4      # 20 ではなく 14
2 ** 3 + 1     # 512 ではなく 9
10 - 4 / 2     # 3.0 ではなく 8.0

(2 + 3) * 4    # 20
10 / (2 + 3)   # 2.0

intfloat の相互作用

Python は一貫したルールを持っています: / は常に小数を返します(4 / 2 でも 2.0 です)。また、整数と小数を混ぜた演算は小数を返します。整数が必要な場合は // を使うか、int() で変換してください。

型のルールは予測可能です: / は常に float を返します。//% は 2 つの整数では int を返します。intfloat を混ぜたあらゆる演算は float を返します。これは 4 / 22 ではなく 2.0 になることを意味し、整数が必要な場面(たとえばインデックスとして使う場合)では重要です。

型の昇格は固定された階層に従います: 混合演算で intfloat に拡張されます。/__truediv__ に対応し、常に float を返します。//__floordiv__ に対応し、2 つの int オペランドでは int を返し、float オペランドが含まれていれば float を返します。これらのルールは一貫しており予測可能です。唯一の意外な点は、4 / 2 のような場合でも / が決して int を返さないことです。

python
4 / 2      # 2.0   (常に float)
4 // 2     # 2     (int)
4 + 2      # 6     (int)
4 + 2.0    # 6.0   (float)
4 * 0.5    # 2.0   (float)

浮動小数点数の精度

ほとんど誰もが一度はびっくりする落とし穴があります:

python
0.1 + 0.2   # 0.30000000000000004

この小さな誤差は Python のバグではありません。コンピュータは小数を 2 進数で保存しますが、0.1 のような値は正確に表現できません。10 進数で 1/3 を正確に書けないのと似ています。日常的な計算のほとんどでは問題になりません。お金を表示するなら、round():.2f フォーマット指定子を使えば出力をきれいに保てます。

Python の float は IEEE 754 binary64 です: 64 ビットで、おおよそ 10 進 15-16 桁の有効精度を持ちます。一部の分数は 2 進数で正確に表現できないため、不正確さが表面化します。0.1 + 0.20.30000000000000004 を生成します。ずれは生の値を確認するときだけ現れ、:.2fround() でフォーマットすれば出力上は隠せます。

セント単位以下が累積する金融処理では、Python の標準ライブラリに decimal.Decimal があり、正確な 10 進数演算ができます。これはモジュールの章で取り上げます。

float は IEEE 754 binary64 です: sign × mantissa × 2^exponent で仮数部が 53 ビット、相対精度は 2^-52 ≈ 2.2e-16 です。分母が 2 以外の素因数を持つ分数(たとえば 1/10 = 1/(2×5))は、循環する 2 進小数となり、正確に格納できません。誤差は小さいですが、繰り返し演算で累積します。

正確な 10 進数演算には、Python の decimal.Decimal が内部で任意精度の 10 進数を使用します。丸めのない正確な有理数演算には、fractions.Fraction が分子/分母のペアを格納します。両方とも標準ライブラリにあり、モジュールの章で扱います。

読みやすい数値リテラル

Python では大きな数を読みやすくするため、数値リテラルにアンダースコアを入れられます。Python はそれらを完全に無視します。あくまであなたのためのものです:

アンダースコアは数値リテラルのどこにでも使え、パース時に取り除かれて値に影響を与えません。定数の桁区切りや、2 進数・16 進数リテラルの桁グループ化に便利です:

数値リテラル中のアンダースコアはトークナイザの機能です: 字句解析時に取り除かれ、結果の値には影響しません。整数、浮動小数点数、基数指定リテラル(0xFF_FF0b1010_00011_234.567_890)で使えます。唯一の制約: 先頭、末尾、小数点や指数記号の隣には置けません。

python
population  = 8_100_000_000
distance_km = 384_400
pi_approx   = 3.141_592_653

便利な組み込み関数

abs()

abs() は絶対値を返します: 入力の符号にかかわらず常に正です。ある数値が 0 からどれだけ離れているかを知りたいとき(方向は問わないとき)に使います。

abs() は数値の大きさ(magnitude)を返します。整数でも float でも動作します。距離計算、誤差マージン、方向は無関係で大きさだけが必要な状況に便利です。

abs() はオペランドの __abs__ を呼び出します。intfloat では同じ型を返します。complex では大きさ(原点からのユークリッド距離)を float として返します。実数では入力の型と同じ型を返します。

python
abs(-5)     # 5
abs(3.7)    # 3.7
abs(-0.5)   # 0.5

round()

round() はデフォルトで最も近い整数に丸めます。第 2 引数を渡せば、指定した小数点以下の桁数まで保持します:

python
round(3.7)          # 4
round(3.2)          # 3
round(3.14159, 2)   # 3.14

知っておくべき点: round(2.5)3 ではなく 2 を返します。Python は、値が 2 つの選択肢のちょうど中間にあるとき、最も近い偶数に丸めます。

round() は**銀行家の丸め(banker's rounding)**を使います: 値がちょうど中間のとき、常に切り上げるのではなく最も近い偶数に丸めます。これにより統計処理での誤差の累積を最小化できますが、0.5 が常に切り上げられると期待していると驚くかもしれません:

python
round(2.5)   # 2  (最も近い偶数に丸める)
round(3.5)   # 4
round(4.5)   # 4  (5 ではない)
round(3.14159, 2)   # 3.14

round() は IEEE 754 の round-half-to-even(銀行家の丸め)を実装しています: 中間値は最も近い偶数の整数に丸められます。これは「中間値を切り上げる」慣例とは異なります。ndigits 引数があると、round() はオブジェクトの __round__ を呼び出します。カスタム型は丸めの挙動をオーバーライドできます。注意: float は正確ではないため、round(2.5) のような「中間値」が 2 進数では正確に 0.5 に位置しないことがあり、一見一貫しない結果になることがあります。

python
round(2.5)   # 2
round(3.5)   # 4
round(4.5)   # 4

divmod()

divmod() は商と余りを一度の呼び出しでまとめて返します。一対の値が返されるので、それを 2 つの名前にまとめて代入できます:

divmod(a, b)(a // b, a % b) と同等ですが、一度の計算で求められます。どのみち両方の値が必要な場面で使います: ページネーション、時刻変換、アイテムのグループ分配など。

divmod() は左オペランドの __divmod__ を呼び出します。除算を一度だけ実行して切り捨て商と剰余の両方を返すので、//% を別々に呼び出す冗長な計算を避けられます。結果は Python の切り捨て除算のセマンティクスのもと、すべての整数入力に対して a == divmod(a, b)[0] * b + divmod(a, b)[1] を満たします。

python
divmod(10, 3)   # (3, 1): 商 3、余り 1
divmod(7, 2)    # (3, 1)
divmod(9, 3)    # (3, 0)

quotient, remainder = divmod(10, 3)
print(quotient)    # 3
print(remainder)   # 1

(3, 1) って何?

これはタプルです: まとめて返される、固定された値のペアです。タプルには専用の章があります。今のところは、上の例のように 2 つの名前にまとめて代入することで、2 つの値を取り出せます。

実践例

チップ計算機:

python
bill     = 45.50
tip_rate = 0.18
tip      = round(bill * tip_rate, 2)
total    = round(bill + tip, 2)

print(f"Bill:  ${bill}")
print(f"Tip:   ${tip}")
print(f"Total: ${total}")

round() のおかげで、出力が長々と続く小数ではなく金額らしく見えます。

ページネーション用のページ数の計算と、パーセンテージとして進捗を追跡する例:

python
total_items    = 153
items_per_page = 10

full_pages, leftover = divmod(total_items, items_per_page)
total_pages = (total_items + items_per_page - 1) // items_per_page

print(f"Full pages: {full_pages}, leftover: {leftover}")
print(f"Total pages needed: {total_pages}")   # 16
python
total_files     = 847
processed_files = 312

percent = round(processed_files / total_files * 100, 1)
print(f"Progress: {processed_files}/{total_files} ({percent}%)")

切り上げ除算の式 (n + d - 1) // d は、float に変換せずに切り上げを行うための標準的な整数演算のテクニックです。

最小-最大正規化とパーセンテージ変化: データ処理で頻繁に現れる 2 つのパターン:

python
# 最小-最大正規化: 値を 0.0 から 1.0 の範囲にスケールする
value   = 75
minimum = 0
maximum = 100

normalised = (value - minimum) / (maximum - minimum)
print(f"Normalised: {normalised:.2f}")   # 0.75

# 2 つの測定値間のパーセンテージ変化
before = 1_200
after  = 1_380

change = (after - before) / before * 100
print(f"Change: {change:.1f}%")          # 15.0%

両方のパターンは比率に帰着します: 参照範囲または参照大きさに対する相対値です。float の精度はほとんどの分析作業に十分です。累積誤差が問題になるのは、計算が数十の演算を連鎖する場合や、桁が大きく異なる値を扱う場合に限られます。