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

詳しくは次のところをご参照ください。

2進数での丸め処理をする関数

いいなと思ったら応援しよう!