PR

python~decimalで数値を丸める~【pythonマスターへの道#010】

decimalで数値を丸める

 以前の記事で、decimalを使用した正確な計算を学びましたが、
decimalにはまだ数値の丸めという便利な機能があります。

 今回はその数値の丸めについて一緒に学んでいきましょう。
「数値の丸め」と一言に言っても実はたくさんの種類があります。
一つ一つ理解してマスターしましょう!

自己紹介

東証一部上場企業でサラリーマンしてます。

主に工場(生産現場)で使用する検査装置のアプリケーション開発してます。

ヒトの作業を自動化して簡略化するアプリケーションを日々開発中。

今までのPythonに関する記事はこちら

pythonの数値の丸めの種類

decimalを使用して実際にできる数値の丸めの種類は、

数値の丸めに使える関数
  • ROUND_CEILING
  • ROUND_FLOOR
  • ROUND_UP
  • ROUND_DOWN
  • ROUND_HALF_DOWN
  • ROUND_HALF_EVEN
  • ROUND_HALF_UP

これだけ豊富に存在します。

それぞれの使い方と具体例を学びましょう。

ROUND_CEILING

ROUND_CEILINGの使い道

ROUND_CEILINGは、「プラス方向への切り上げ」です。

decimalの使い方でやった、contextプロパティの指定で

「プラス方向への切り上げ」ができるようになります。

ROUND_CEILINGの具体例

それでは、10/3の答え、3.33333を例にして

ROUND_CEILINGを使用してみましょう。

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_CEILING #有効桁数の所でプラス方向に切り上げ
x=decimal.Decimal('10')/decimal.Decimal('3')
print(x)

decimalを使用するときはimport decimalを忘れないように気を付けてください。

出力結果は、3.334になりましたね?

有効桁数4で、4桁目を「プラス方向へ切り上げ」しているので

3.333333…. ⇒ 3.334となっています。

ちなみに、負の数字にROUND_CEILINGを使用したばあいは、

「切り捨て」のような扱いになります。

具体的には、

-3.33333333… ⇒ -3.333(有効桁数4で指定)

となります。

ROUND_FLOOR

ROUND_FLOORの使い道

次にROUND_FLOORです。

こちらは、「マイナス方向への丸め」になります。

ROUND_CEILINGのちょうど逆といったところですね。

ROUND_FLOORの具体例

同様の例に使用してみると、

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_FLOOR #有効桁数の所でマイナス方向に丸め
x=decimal.Decimal('-10')/decimal.Decimal('3')
print(x)

出力結果は、-3.334となります。

正の数字にROUND_FLOORを使用すると、

ちょうどROUND_CEILINGの負の数字と同じように、

「切り捨て」のような処理が行われます。

具体的には、

3.333333…. ⇒ 3.333(有効桁数4)

となります。

ROUND_UP

ROUND_UPの使い道

ROUND_UPは正の数字でも、負の数字でも、

切り上げ処理が行われます。

3.3333…⇒3.334

-3.33333…⇒-3.334

ROUND_CEILINGとROUND_FLOORでは、

正か負かによって「切り捨て」が行われていましたが、

それが無いパターンですね。

ROUND_UPの具体例

なんとなく予想はつくと思いますが、

コードを書いておきます。出力結果は3.334です。

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_UP #有効桁数の所でプラス方向に切り上げ
x=decimal.Decimal('10')/decimal.Decimal('3')
print(x)

ROUND_DOWN

ROUND_DOWNの使い道

ROUND_DOWNは、ROUND_UPの逆です。

つまり、正負にかかわらず、有効桁数で切り捨てします。

ROUND_DOWNの具体例

負の数をROUND_DOWNした場合、

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_DOWN #有効桁数の所でプラス方向に切り上げ
x=decimal.Decimal('-10')/decimal.Decimal('3')
print(x)

-3.333が出力結果となります。

-10を10として、正の数にしたばあいでも

「切り捨て」の処理をされるので、

3.333が出力されます。

ROUND_HALF_DOWN

ROUND_HALF_DOWNの使い道

ROUND_HALF_DOWNは、有効桁数の末尾が0~5と6~9で

処理が変わります。

具体例を見たほうが早いので、具体例をご覧ください。

ROUND_HALF_DOWNの具体例

ここでは、10から小さい値を引いて切り上げされるのか、

切り捨てされるのか確認します。

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_DOWN #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0006')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_DOWN #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0005')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_DOWN #有効桁数の所が6~9なら切り上げ
x=decimal.Decimal('10')-decimal.Decimal('0.0004')
print(x)

出力結果は、順に

9.999

9.999

10.00となります。

ですから、有効桁数4とした場合には、

9.9994⇒9.999

9.9995⇒9.999

9.9996⇒10.00

という出力結果となります。

イメージとしては、四捨五入ではなく、五捨六入というイメージでしょうか。

ROUND_HALF_EVEN

ROUND_HALF_EVENの使い道

ROUND_HARLF_EVENは、

先ほどのROUND_HALF_DOWNとは、

有効桁数の末尾が5の時の扱いのみ異なります。

ROUND_HALF_EVENの具体例

先ほどのROUND_HALF_DOWNと同様の具体例で

どうなるか確認してみましょう。

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_EVEN #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0006')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_EVEN #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0005')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_EVEN #有効桁数の所が6~9なら切り上げ
x=decimal.Decimal('10')-decimal.Decimal('0.0004')
print(x)

出力結果は、順に

9.999

10.00

10.00

なので、ROUND_HALF_DOWNとは、末尾が5の場合のみ異なりました。

ただじつは、このHALF_UPとHALF_DOWN

CEILINGとFLOORの関係のように、

正の数を丸めるか、負の数を丸めるかで挙動が変わりますので、

完全な四捨五入とはいきません。

正の数であれば、ROUND_HALF_EVENが四捨五入になっているのは

確認できましたが…

ROUND_HALF_UP(四捨五入)

ROUND_HALF_UPの使い道

ROUND_HALF_UPは、

ROUND_HALF_DOWNとEVENの四捨五入のみできるようにしたものです。

先ほど、正の数であれば、ROUND_HALF_EVENが

四捨五入になるお話はしましたが、

負の数でも四捨五入になるようにしてあるのが、

このROUND_HALF_UPです。

ROUND_HALF_UPの具体例

例としては、「10から小さい値を引くパターン」と、

「-10から小さい値を足すパターン」の2種類で見ていきましょう。

import decimal
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0006')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('10')-decimal.Decimal('0.0005')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が6~9なら切り上げ
x=decimal.Decimal('10')-decimal.Decimal('0.0004')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('-10')+decimal.Decimal('0.0006')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が0~5なら切り捨て
x=decimal.Decimal('-10')+decimal.Decimal('0.0005')
print(x)
cont=decimal.getcontext() #decimalのContextプロパティを取得
cont.prec=4 #有効桁数を指定
cont.rounding=decimal.ROUND_HALF_UP #有効桁数の所が6~9なら切り上げ
x=decimal.Decimal('-10')+decimal.Decimal('0.0004')
print(x)

出力結果は、順に

9.999

10.00

10.00

-9.999

-10.00

-10.00

となったので、正の数でも、負の数でも四捨五入されているのがわかります。

まとめ

今回は、decimalを使用した数値の丸めについて学びました。

四捨五入以外にも、切り捨てや切り上げなどの処理が必要になることは

多々あると思います。

そのときに向けてしっかりと違いについて理解しておきましょう。

コメント

タイトルとURLをコピーしました