2進数での丸め処理をする関数
Pythonで小数点の計算をするとおかしなことがおこります。
print(f'{0.1:.60f}')
#0.100000000000000005551115123125782702118158340454101562500000
0.1を単純に60桁まで表示させると、小数点第18位から555111・・・とごくわずかですが誤差が生じてしまいます。これは、Python、というよりコンピュータが2進数で数値を計算しており、そこでは浮動小数点方式という計算方法によっているためです。
また浮動小数点方式で目いっぱい大きな整数の計算をすると桁落ちを起こしますが、この落ち方が不思議です。
for i in range(11):
print(f'2^53-1+{i:>2}={f53+float(i):>20.1f}')
#2^53-1+ 0= 9007199254740991.0
#2^53-1+ 1= 9007199254740992.0
#2^53-1+ 2= 9007199254740992.0
#2^53-1+ 3= 9007199254740994.0
#2^53-1+ 4= 9007199254740996.0
#2^53-1+ 5= 9007199254740996.0
#2^53-1+ 6= 9007199254740996.0
#2^53-1+ 7= 9007199254740998.0
#2^53-1+ 8= 9007199254741000.0
#2^53-1+ 9= 9007199254741000.0
#2^53-1+10= 9007199254741000.0
整数部の1の桁の増え方が不思議です。
これらの原因は浮動小数点への変換のときの丸めの問題です。そこで、この計算の関数を作ってみました。
def round_bin(Bin,rb): #1桁で判断 決定版
ulp=Bin[-2] #unit in the last place
gb =Bin[-1] #Guard bit
sw_up= False
if gb=='1':
if rb==True: #Round bit
sw_up=True
else:
if ulp=='1':
sw_up=True
result=Bin[:-1]
if sw_up==True:
return bin(eval('0b'+result) +eval('0b'+(len(Bin)-2)*'0'+'1'))[2:]
else:
return result
結果は次の通りです。
print(round_bin('110',True))
print(round_bin('111',True))
print(round_bin('111',False))
print(round_bin('101',False))
print(round_bin('110',False))
print(round_bin('100',False))
11
100
100
10
11
10
詳しくは次のところをご参照ください。