Python で四捨五入をするときのまとめ

programming Python

Python での四捨五入のサンプルコードについてまとめておきます。
加えて、小数の表示など数値を文字列に変換するときによく使うサンプルコードについても集約しておきます。
欲しい出力に該当する箇所をコピー&ペーストすれば使えるよう意図しています。
四捨五入時の注意点などについても集約した形でまとめておきます。

以下の環境で動作確認をしています。
環境: Windows 10、Python 3.X

背景 なんでも取り込めて流儀が混とんとする!

Python は、いろいろなパッケージをすぐにインポートして使うことができる言語仕様になっており、柔軟性、拡張性の点で優れたプログラミング言語といえます。

ところがその反面、記載の流儀が統一されていない関数やメソッドが取り込まれ、混在する状況となっています。たとえば、四捨五入や繰り上げ、切り捨てといった簡単な計算を行う際も、プログラムの記載方法が複数あります。
この結果、各関数やメソッドを使おうとしたとき、細かな仕様を覚えておくことが難しくなります。バグを防止するためには、使うたびに書籍やネット検索で確認をする必要が生じます。使うたびに複数のサイトや書籍を探して確認していたのでは、プログラミングの効率を著しく落とす結果となります。

四捨五入のような誰でも使うような処理については、典型的なスクリプトと注意点が1か所にまとまっていることが望ましいです。加えて、サンプルコードをコピー&ペーストするとすぐに使えるとさらによいです。
そこでよく使うスクリプトについて1か所に集約し、公開しておくことにします。
以下の各ケースについてまとめておきます。

[1] 整数への四捨五入
[2] 小数での四捨五入、表示桁数の指定 (round( , ) を使った場合)
[3] 切り捨て、切り上げ
[4] 小数での四捨五入、表示桁数の指定 (format() を使った場合)
[5] 整数に丸める際の注意点 偶数への丸め
[6] 3桁ごとにカンマ区切り
[7] スペースパディング
[8] ゼロパディング(format() を使った場合)
[9] ゼロパディング(zfill() を使った場合)
[10] 日付でのゼロパディング

四捨五入、切り捨て、切り上げのまとめ

[1] オーソドックスな四捨五入  round( 3.14159 )

まずはオーソドックスな四捨五入です。以下で動きます。import なども不要です。
n1 = round( 3.14159 )    # 3

・ 整数への四捨五入をするだけであれば、round() 関数が便利です。
・ 関数 round() を使う前後で型のクラスを表示させると、3.14 …の class は ‘float’ 型、変換後は、’int’ 型(整数型)になっています。
・ サンプルコードを末尾にまとめています。適宜、参照してください。

[2] 四捨五入で、小数部分の桁数指定をするとき  round( 3.141, 2 )

四捨五入をするとき、小数部分の桁数指定をしたい場合は、引数を2つにします。
n1 = round( 3.14159, 2 )    # 3.14

・ 小数部分の桁数を変えた事例については、末尾のサンプルコードを参照してください。
・ 指定した桁数で表示され、かつ、末尾の桁が四捨五入されています。★
切り上げ、切り捨てとなる各場合について、正しく動いていることを確認できると思います。
・ なお、桁数指定を 0 とすると、整数になるのではなく、1 とした場合と同じ小数1桁での表示となる仕様になっていることがわかります。
・ また、round() 関数で、引数が1つのときの戻り値は整数型でしたが、引数を2つにすると、float 型に切り替わることがわかります。

[3] 切り捨て math.floor( v1 )、切り上げ math.ceil( v1 )

切り捨て、切り上げをしたい場合は、つぎのようになります。
プログラムの冒頭に import math を記載しておく必要があります。
n1 = math.floor( 3.14 )    # 3
n1 = math.ceil( 3.14 )      # 4

・ 四捨五入 round() だけは Python の標準関数になっているため、インポート等を考慮することなく、そのまま使用できます。
・ しかし、切り上げ、切り捨てをしたい場合は、import math として floor(), ceil() を呼び出して使う必要があります。
・ 切り捨てであれば、int() 関数に入れてしまう方法もあります。

[4] 小数の桁数指定 ”{:.2f}”.format( 3.1415926 )

小数の数値を桁数指定で文字列に変換する場合は、format() を使います。
str1 = “{:.2f}”.format( 3.1415926 )    # 3.14

・ {} 内を、ドット “.” 以下を2桁フロートで文字列表示、と読み取れば、理解しやすいと思います。
・ round() 関数は、引数の数に応じて、整数型、float 型への変換でしたが、format() は、文字列型への変換です。
・ format() を使わず、前述の round() 関数を使って計算し、計算後に文字列に変換しても、類似した表示は可能だと思います。
ところが、例えば、round() の小数の計算を行ったとき、計算結果の末尾がたまたまゼロ(例:0.0000)になると、文字列に変換した後の文字列の長さが特定できなくなる可能性があると思います。
そこで、format() で、文字列型として表示文字数を指定してしまったほうが、プログラムの動作を特定できるという点でメリットがあるといえます。
サンプルコードでは確認のため、変換後の型 type を表示しています。

[5] 注意点: round() で四捨五入をしたとき ~ 偶数側への丸め

以下、関数 round() の注意点です。
「整数への四捨五入」は、小数部分がちょうど 0.5 だったとき、偶数側に丸める(=切り捨てるか、あるいは、切り上げるかの扱いが整数部分の値に応じて異なる)ことになっています。
そのため、結果はすべて偶数になります。この点、小数の場合の★と挙動が異なっています。小数での四捨五入の場合、末尾の桁は、偶数となる場合と奇数となる場合の2つのパターンがあります。

この結果、数値計算、物理計算を行うような場合、同じ四捨五入であっても、整数演算と小数演算では四捨五入の動きが異なるケースが生じるため、注意が必要です。
例えば、浮動小数演算をするところで、計算速度を上げるために先に1000倍(係数倍)して整数演算を行い、表示のときに結果を1/1000倍するといった計算を行うと、計算結果が一致しないことが生じえます。

3桁ごとのカンマ区切り

[6] 3桁ごとにカンマで区切るとき ”{:,d}”.format( n1 )

お金の計算でよく使うカンマ区切りの文字列を作る事例です。
str1 = “{:,d}”.format( 12345678 )      # 12,345,678

・ カッコ{}内の後半で、「カンマ “,” を入れたデシマル(10進数)表示」と読み取れば、理解しやすいと思います。

スペースでのパディング、ゼロパディングをするとき

[7] 文字列の冒頭をスペースで埋めるとき ”{:10d}”.format( n1 )

スペースでのパティング(スペース埋め)のサンプルです。
str1 = “{:10d}”.format( 12345678 )     # ”  12345678″

・ カッコ{}内で、「(スペース)10文字でのデシマル表示」と読み取れば理解できると思います。

[8] 冒頭をゼロ埋めするとき ”{:010d}”.format() を使う例

文字列の冒頭をゼロで埋めて桁数を統一したいときは、以下のようにします。
str1 = “{:010d}”.format( 12345678 )     # “0012345678”

・ カッコ内で「ゼロでの10桁デシマル表示」と読み取れば、理解できると思います。

[9] 冒頭をゼロ埋めするとき str1.zfill() を使う例

文字列型に対して、 .zfill(10) メソッドを実行しても、ゼロ埋めができます。
str1 = str( 12345678 ).zfill( 10 )    # “0012345678”

日付の表示

[10] 日付でゼロ埋めをするとき:dt1.datetime.now().strftime( “%Y%m%d_%H%M%S” )

日付でゼロ埋めをする場合もよく出てきますので、まとめておきます。
import datetime as dt1
str1 = dt1.datetime.now().strftime( “%Y%m%d_%H%M%S” )

・ strftime() で文字列を指定すると、月、日等が1桁の場合に0で埋める動きとなります。
日付のフォーマットを統一できます。

まとめ

Python で四捨五入や表示桁数を指定する際の、典型的な処理、よく使うスクリプトをまとめました。

注意点も含め、まとまっているサイトが見つからなかったため、ポイントを集約しました。
通常出てくるものは、ほぼカバーしているかなと思います。

四捨五入の例だけを取っても、Python では複数のプログラミングの流儀が混在していることがよくわかると思います。なお、メソッドと関数の違いなどについて、以下の関連リンクでまとめています。もし興味があれば参照してみてください。

関連リンク
・ メソッドと関数のまとめ 【Python】
・ Python で円周率を求める

サンプルコード:数値を文字列に変換する際のまとめ

import math 
import datetime as dt1 

print( "\n--------------------------------\n" ) 

v1 = 3.1415926535

print( v1 ) 
print( type( v1 ) ) 

print( "\n--- [1] round( v1 ) ------------\n" ) 

n1 = round( v1 ) 
print( n1 )                      # 3 
print( type( n1 ) ) 

print( "\n--- [2] round( v1, n1 ) --------\n" ) 

v1 = 3.1415926535

v2 = round( v1, 0 ) 
print( v2 )                      # 3.0 
v2 = round( v1, 1 ) 
print( v2 )                      # 3.1 
v2 = round( v1, 2 ) 
print( v2 )                      # 3.14 
v2 = round( v1, 3 ) 
print( v2 )                      # 3.142 
v2 = round( v1, 4 ) 
print( v2 )                      # 3.1416 
v2 = round( v1, 5 ) 
print( v2 )                      # 3.14159 
v2 = round( v1, 6 ) 
print( v2 )                      # 3.141593 
v2 = round( v1, 7 ) 
print( v2 )                      # 3.1415927 

print( type( v2 ) )              # <class 'float'> 

print( "\n--- [3] math.floor(), ceil() ---\n" ) 

n1 = math.floor( v1 ) 
print( n1 )                      # 3 

n1 = math.ceil( v1 ) 
print( n1 )                      # 4 

print( type( n1 ) )              # <class 'int'> 

print( "\n--- [4] format() ---------------\n" ) 

v1 = 3.1415926535

str1 = "{:.0f}".format( v1 )     #  "{ index number: format }".format( ) 
print( str1 )                    # "3" 
str1 = "{:.1f}".format( v1 ) 
print( str1 )                    # "3.1" 
str1 = "{:.2f}".format( v1 ) 
print( str1 )                    # "3.14" 
str1 = "{:.3f}".format( v1 ) 
print( str1 )                    # "3.142" 
str1 = "{:.4f}".format( v1 ) 
print( str1 )                    # "3.1416" 
str1 = "{:.5f}".format( v1 ) 
print( str1 )                    # "3.14159" 
str1 = "{:.6f}".format( v1 ) 
print( str1 )                    # "3.141593" 
str1 = "{:.7f}".format( v1 ) 
print( str1 )                    # "3.1415927" 

v1 = 0 
str1 = "{:.7f}".format( v1 ) 
print( str1 )                    # "0.0000000" 

print( type( str1 ) )            # <class 'str'> 

print( "\n--- [5] note: round() ----------\n" ) 

v1 = -4.5 
n1 = round( v1 ) 
print( n1 )                      # -4 
v1 = -3.5 
n1 = round( v1 ) 
print( n1 )                      # -4 
v1 = -2.5 
n1 = round( v1 ) 
print( n1 )                      # -2 
v1 = -1.5 
n1 = round( v1 ) 
print( n1 )                      # -2 
v1 = -0.5 
n1 = round( v1 ) 
print( n1 )                      # 0 
v1 = 0.5 
n1 = round( v1 ) 
print( n1 )                      # 0 
v1 = 1.5 
n1 = round( v1 ) 
print( n1 )                      # 2 
v1 = 2.5 
n1 = round( v1 ) 
print( n1 )                      # 2 
v1 = 3.5 
n1 = round( v1 ) 
print( n1 )                      # 4 
v1 = 4.5 
n1 = round( v1 ) 
print( n1 )                      # 4 

print( type( n1 ) )              # <class 'int'> 

print( '\n--- [6] "{:,d}".format( n1 ) ---\n' ) 

n1 = 12345678

str1 = "{:,d}".format( n1 )
print( str1 )                    # "12,345,678"  thousands separator 

print( type( str1 ) )            # <class 'str'> 

print( '\n--- [7] space padding ----------\n' ) 

n1 = 12345678 

str1 = "{:10d}".format( n1 )     # "  12345678"   ' ' padding 
print( str1 ) 
str1 = "{:9d}".format( n1 )      # " 12345678" 
print( str1 ) 
str1 = "{:8d}".format( n1 )      # "12345678" 
print( str1 ) 

print( '\n--- [8] zero padding format() --\n' ) 

str1 = "{:010d}".format( n1 )    # "0012345678"   '0' padding 
print( str1 ) 
str1 = "{:09d}".format( n1 )     # "012345678" 
print( str1 ) 
str1 = "{:08d}".format( n1 )     # "12345678" 
print( str1 ) 

print( type( str1 ) )            # <class 'str'> 

print( '\n--- [9] zero padding zfill() ---\n' ) 

str1 = str( n1 ).zfill( 10 )     # "0012345678"   '0' padding 
print( str1 ) 
str1 = str( n1 ).zfill(  9 )     # "012345678" 
print( str1 ) 
str1 = str( n1 ).zfill(  8 )     # "12345678" 
print( str1 ) 

print( type( str1 ) )            # <class 'str'> 

print( '\n--- [10] date & time -----------\n' ) 

str1 = dt1.datetime.now().strftime( "%Y%m%d_%H%M%S" )  # date format  YYYYmmdd
print( str1 )                    # "20210101_000000" 

str1 = dt1.datetime.now().strftime( "%y%m%d_%H%M%S" )  # date format  yymmdd
print( str1 )                    # "210101_000000" 

print( type( str1 ) )            # <class 'str'> 

print( "\n--------------------------------\n" ) 

出力結果

--------------------------------

3.1415926535
<class 'float'>

--- [1] round( v1 ) ------------

3
<class 'int'>

--- [2] round( v1, n1 ) --------

3.0
3.1
3.14
3.142
3.1416
3.14159
3.141593
3.1415927
<class 'float'>

--- [3] math.floor(), ceil() ---

3
4
<class 'int'>

--- [4] format() ---------------

3
3.1
3.14
3.142
3.1416
3.14159
3.141593
3.1415927
0.0000000
<class 'str'>

--- [5] note: round() ----------

-4
-4
-2
-2
0
0
2
2
4
4
<class 'int'>

--- [6] "{:,d}".format( n1 ) ---

12,345,678
<class 'str'>

--- [7] space padding ----------

  12345678
 12345678
12345678

--- [8] zero padding format() --

0012345678
012345678
12345678
<class 'str'>

--- [9] zero padding zfill() ---

0012345678
012345678
12345678
<class 'str'>

--- [10] date & time -----------

20210101_000000
210101_000000
<class 'str'>

--------------------------------



外部リンク

リーダブルコード ?より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

新品価格
¥2,640から
(2021/10/25 15:59時点)

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