Python の数値と四捨五入

数値

Python における数値型には 3 種類あります。整数 (int)、 浮動小数点数 (float)、 複素数 (complex)です。また、ブール型 (bool) は、整数のサブタイプです。

整数
5100 など、小数点以下を含まない数値です。
浮動小数点数
3.141.86e4 など、小数点以下を含む数値や、指数表記を含む数値です。
複素数
5j などの虚数単位 (j) を含む数値です。虚数単位は i ではないため注意が必要です。また、虚部が 1 の場合でも省略すると NameError が発生するため 1j と明示的に記述する必要があります。
type(1)
# <class 'int'>

type(3.14)
# <class 'float'>

type(5j)
# <class 'complex'>
数値の種類

これらの数値型は、以下の算術演算子を使うことで計算することができます。

Python の算術演算子一覧
演算説明結果
x + y加算5 + 813
x - y減算90 + 1080
x * y乗算4 * 728
x / y浮動小数点数の除算7 / 23.5
x // y整数の除算 (切り捨て)7 // 23
x % y剰余7 % 31
x ** y指数3 ** 481
-x負数-135-135
+x正数+135135
abs(x)絶対値abs(-271.1)271.1
int(x)整数へ変換 (切り捨て)int(10.5)10
float(x)浮動小数点数へ変換float(10)10.0
divmod(x)商と剰余をまとめて取得divmod(9, 5)(1, 4)
complex(re, im)実部 (re)、虚部 (im) の複素数へ変換complex(3, 4)(3+4j)
c.conjugate()複素数 c を共役複素数へ変換(3+4j).conjugate()(3-4j)

Python の数字の並びは、リテラルの整数と見なされます。ゼロも使用することもできますが、他の数字の前にゼロを置くことはできません。もしもゼロを置いた場合、SyntaxError が発生します。

>>> 5
5

>>> 0
0

>>> 05
  File "<stdin>", line 1
    05
     ^
SyntaxError: invalid token
数値の扱い

Python では、他の言語と同様に以下のような簡略版の記述ができます。

# a = a + 8 と同じ意味
a += 8

# a = a - 8 と同じ意味
a -= 8

# a = a * 8 と同じ意味
a *= 8

# a = a / 8 と同じ意味
a /= 8

# a = a // 8 と同じ意味
a //= 8
簡略版の記述

n進数などの基数の記述方法は以下のとおりです。

>>> 10
10

>>> 0b10
2

>>> 0o10
8

>>> 0x10
16
基数の記述

数値への変換

データ型を変換するには、int() 関数、または float() 関数を使います。

>>> int(10)
10

>>> float(10)
10.0
整数の変換

小数点を含む変換の場合、int() 関数は小数点以下を切り捨てます。

>>> int(10.5)
10

>>> float(10.5)
10.5
小数点を含む数値の変換

文字列から数値に変換する場合、int() 関数は小数点を含む文字列を変換できません。

>>> int("10")
10

>>> int("10.5")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.5'

>>> float("10")
10.0

>>> float("10.5")
10.5
文字列の変換

また、数値に変換できない文字列を変換しようとした場合、例外が発生します。

>>> int("abc")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'abc'

>>> int("")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: ''
文字列の変換 (例外発生)

異なる数値型を混ぜて計算すると、Python は片方を自動的に変換する場合があります。

>>> 4 + 7.0
11.0
自動的な変換

bool 値の False は、整数、浮動小数点数と混ぜて計算するときには、0 または 0.0 として扱われます。True の場合は 1 または 1.0 として扱われます。

>>> True + 2
3

>>> False + 5.0
5.0
自動的な変換

一般的に文字列が数値に変換可能かどうか調べるためのアプローチは、以下の3つがあります。

  • try-except を使用する
  • .isdigit() 関数を使用する
  • regex を使用する

以下のコードでは、try-except を用いて float に変換可能な場合は、True を返す関数を実装しています。ただし、指数表記、NanInfTrue を返すため、注意が必要です。

def is_float_expression(s):
    try:
        val = float(s)
        return True
    except ValueError:
        return False

print(is_float_expression(100))    # True
print(is_float_expression("100"))  # True
print(is_float_expression("10.5")) # True
print(is_float_expression(".5"))   # True
print(is_float_expression("10."))  # True
print(is_float_expression("10e2")) # True
print(is_float_expression("NaN"))  # True
print(is_float_expression("Inf"))  # True
print(is_float_expression("a"))    # False
try-except による変換可否の判定

以下のコードでは、isdigit() 関数を用いて数字であれば True を返しています。ただし、isdigit() 関数では小数点は判定できないため、注意が必要です。

"10".isdigit()   # True
"10.5".isdigit() # False
isdigit() 関数による変換可否の判定

以下のコードでは、正規表現を用いて変換可否を判定しています。

import re

def is_float_expression(s):
    if re.match("^-?\d+?\.\d+?$", s) is None:
        return False
    else:
        return True

is_float_expression("10.1")  # True
is_float_expression("-10.1") # True
正規表現による変換可否の判定

int 型の大きさ

Python2 では、int のサイズは 32 ビットに制限されていました。これは -2,147,483,648 から 2,147,483,647 までの整数を表現できます。long は 64 ビットなのでもっと大きな範囲の数値を表現できます。具体的には -9,223,372,036,854,775,808 から 9,223,372,036,854,775,807 までです。

Python3 では long がなくなり int任意のサイズになりました。つまり 64 ビットよりもはるかに大きな数値を表現できるようになりました。

googol = 10**100
# 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

googol * googol
# 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
int 型の大きさ

多くの言語では上記のコードを試そうとすると、整数オーバーフローと呼ばれるエラーが発生します。これは、コンピュータが認めている以上のサイズを数値が求めているために発生するエラーです。しかし、Python は途方もなく大きな整数を問題なく処理できます。

四捨五入する: round, Decimal.quantize

Python で四捨五入する場合、以下の方法があります。

  • 組み込み関数の round() 関数を使う
  • 標準ライブラリの decimal.quantize() 関数を使う
  • 新しい関数を定義する

四捨五入する: round() 関数

Python には組み込み関数として round() 関数が用意されています。

round(number[, ndigits])
round() 関数の構文

round() 関数では、第一引数 (number) に四捨五入したい数値を指定し、オプショナルの第二引数には何桁にするか指定します。第二引数が省略された場合、入力値にもっとも近い整数 (int) を返します。第二引数が指定された場合、浮動小数点数 (float) を返します。ただし、round() 関数は厳密な四捨五入ではなく、偶数への丸めである点に注意してください。偶数への丸めについては後述します。

f = 123.456

print(round(f))
# 123

print(type(round(f)))
# <class 'int'>

print(round(f, 1))
# 123.5

print(round(f, 2))
# 123.46

print(round(f, 0))
# 123.0

print(type(round(f, 0)))
# <class 'float'>
round() 関数の四捨五入

第二引数に負の整数を指定した場合、対応する桁に丸めることができます。

i = 123

print(round(i, -1))
# 120

print(round(i, -2))
# 100

f = 123.456

print(round(f, -1))
# 120.0

print(round(f, -2))
# 100.0
round() 関数の四捨五入

偶数への丸めとは、端数が 0.5 より小さいなら切り捨て、端数が 0.5 より大きいならは切り上げ、端数がちょうど 0.5 なら切り捨てと切り上げのうち結果が偶数となる方へ丸める方法です。つまり端数がちょうど 0.5 の場合、以下のように結果はすべて偶数となります。

print(round(0.5)) # 0
print(round(1.5)) # 2
print(round(2.5)) # 2
print(round(3.5)) # 4
print(round(4.5)) # 4
偶数への丸め

ただし、2進数では小数点以下を浮動小数点数では正確に表現できないため、小数点以下2桁以降の処理では偶数への丸めの定義に当てはまらない場合があるので注意が必要です。

print(round(0.05, 1)) # 0.1
print(round(0.15, 1)) # 0.1
print(round(0.25, 1)) # 0.2
print(round(0.35, 1)) # 0.3
print(round(0.45, 1)) # 0.5
偶数への丸め

正確な偶数への丸めを実現したい場合は、次の decimal.quantize() 関数か、新しい関数を定義する方法を使います。また、Python2 の round() は偶数の丸めではなく四捨五入の処理となるため、注意してください。

四捨五入する: decimal.quantize() 関数

標準ライブラリの decimal モジュールを使うと、正確な十進浮動小数点数を扱うことができます。

decimal モジュールの quantize() 関数を使うと、丸めモードを指定して数値を丸めることができます。

quantize(exp, rounding=None, context=None)
quantize() 関数の構文

quantize() 関数の rounding 引数に、ROUND_HALF_UP を指定すると一般的な四捨五入になります。

from decimal import Decimal, ROUND_HALF_UP

print(Decimal('1.5').quantize(Decimal('1'), ROUND_HALF_UP))
# 2
quantize() 関数での四捨五入

Decimal()Decimal 型のオブジェクトを生成できます。引数に float 型を指定すると、実際に扱われる数値について確認することができます。

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>
Decimal 型のオブジェクト

上記のように、0.05 は2進数で正確には表現できないため、近似値となります。上述した round 関数で 0.05 を含む数値が正しく丸められなかったのは、これが原因になります。

引数に float 型ではなく str 型を指定すると、正確にその値の Decimal 型として扱われます。

print(Decimal('0.05'))
# 0.05
Decimal 型のオブジェクト

quantize() の第一引数に求めたい桁数と同じ桁数の数値を '0.1''0.01' のように文字列で指定します。引数 rounding には、丸めモードを指定します。例えば、ROUND_HALF_UP を丸めモードとして指定すると、一般的な四捨五入となります。

from decimal import Decimal, ROUND_HALF_UP

f = 123.456

print(Decimal(str(f)).quantize(Decimal('0'),    rounding=ROUND_HALF_UP)) # 123
print(Decimal(str(f)).quantize(Decimal('0.1'),  rounding=ROUND_HALF_UP)) # 123.5
print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 123.46
quantize() 関数での四捨五入

組み込み関数 round() と異なり、0.51 に丸められています。

from decimal import Decimal, ROUND_HALF_UP

print(Decimal('0.4').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 0
print(Decimal('0.5').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 1
print(Decimal('0.6').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 1
quantize() 関数での四捨五入

四捨五入する: decimal.as_tuple() 関数

整数を任意の桁数で四捨五入する場合、as_tuple() 関数を使います。また、整数 (Decimal('10')) の場合、E を使った指数表記になります。四捨五入を行う場合は、引数の roundingROUND_HALF_UP を指定します。ただし、そのままでは結果も指数表記になるため、整数として演算したい場合、int() で変換する必要があります。

i = 12345

print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))
# 1.235E+4

print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 12350

print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP)))
# 12300

print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP)))
# 12000
as_tuple() 関数での四捨五入

整数の場合、浮動小数点数とは異なり指数表記になる理由は、整数 (Decimal('10')) では Decimal オブジェクトの指数 (exponent) が 1 ではなく 0 になるためです。

print(Decimal('10').as_tuple())
# DecimalTuple(sign=0, digits=(1, 0), exponent=0)

print(Decimal('1E1').as_tuple())
# DecimalTuple(sign=0, digits=(1,), exponent=1)
as_tuple() 関数での四捨五入

Python 全体の仕様を体系的にまとめたページは、Python 入門を参照してください。

Category:
プログラミング
公開日:
更新日:
Pageviews:
11
Shares:
1
Tag:
Python
hatebu icon
hatebu