どうもこんにちは!
round()関数を使って四捨五入して整数に、本当にそれでよかったのでしょうか、という話です。
タイトルで察した方もいらっしゃると思いますしWebで検索したらもろもろ出てくる話ですが、自分はAtcoderではまだ小数を使ってないこともあり把握していませんでした。
自分が忘れないように整理します。
起きたことと調べてわかったこと
某所のスキルチェック問題で、round関数を使って小数第一位を四捨五入して整数にしたところ誤答が発生。テストケースの詳細は不明ですが、例えば2.5をround関数で丸めると2となることがわかりました。
(ちなみに3.5をround関数で丸めると4となるため、x+0.5の丸めが必ずx(つまり切り捨て)になるわけでもありません)
四捨五入するには
計算でおこなう
小数第一位が0.5以上なら2倍したら整数の1桁目が+1されるので、以下の式で四捨五入できます。ただ、後述の関数を使う方が無難とのこと。丸めとかで0.5以上でも1桁目が+1されないケースもあるんでしょうか。あと負の数には使えません。
int((x*2+1) // 2)
Decimal関数を使う
decimalモジュールに含まれるDecimal関数を使うと10進数の浮動小数点の演算ができます。(モジュール名はdecimal、関数はDecimalです)
以下が変数xを四捨五入して整数にする例。主なポイントはコメントで入れました。
from decimal import *
Decimal(str(x)).quantize(Decimal('0'), ROUND_HALF_UP)
# Decimal(str(x)) で変数をstr型にしてDecimal型に変換
# Decimal().quantize()でDecimal()の値を四捨五入。
# 整数で四捨五入の場合はquantize(Decimal('0'),ROUND_HALF_UP)
# quantizeの引数のうち、Decimal('0')で出力する値の桁数。例えば'0.1'だと小数第一位で出力。
# ROUND_HALF_UPは丸め方の指定。この場合は一般的な四捨五入。
# ROUND_HALF_DOWNにすると、0.5以下が切り捨てになる(0.51とかは切り上げ)
ではでは。
参考にしたサイトなど