pythonの割り算は大きく2種類存在する。"/“と”//“である。 違いについて、混乱し、検索しても納得がいかなかったので実機で動作を確認した。

定義

/演算子

こちらが通常の割り算。結果はfloat型(不動小数点型)。pythonの不動小数点型も他の言語と同様に2の補数表現として表されている。

//演算子

こちらは商を求める演算。結果はint型(整数型)。あくまで、整数の範囲で割り算を行い、商を返す。

int()によるキャスト

int()はfloat型→int型への型キャスト演算である。 int()は少数部の切り捨て演算にあたる。 int(3.5)→3

考察

ここで気になるのがint()と/演算子との組み合わせである。 数学的には、a//bとint(a/b)は同一の結果となる。

しかし実装上は異なる。 具体例を見てみる。

a = int(input())
# 987654321


sum_a1 = int(a * (a + 1) / 2) % 998244353
sum_a2 = int(a * (a + 1) // 2) % 998244353
print("sum_a1 : {}".format(sum_a1))
print("sum_a2 : {}".format(sum_a2))
#sum_a1 : 3544418
#sum_a2 : 3544427


sum_b1 = a * (a + 1) / 2
sum_b2 = a * (a + 1) // 2
print("sum_b1 : {}".format(sum_b1))
print("sum_b2 : {}".format(sum_b2))
#sum_b1 : 4.877305293888127e+17
#sum_b2 : 487730529388812681

理由は、一度float型で読み取ると誤差が生じるためである。 誤差のある数字どうしを掛け算して桁の大きな数字にすると、誤差が大きくなり、切り捨て演算の結果が変わることになる。

まとめ

不必要にfloatが発生しないようにするべし。 Decimal型を使っても安全かも。