Pythonの四捨五入を本当に理解しましたか?1.45小数点以下の1位を保留して、四捨五入はいくらですか?


まずPythonに内蔵されている四捨五入関数を見てみましょう.
round(x, n)
  • この関数は、入力されたx数値(浮動小数点型または整数型)の四捨五入値を返す.
  • パラメータnは、xを四捨五入する際の保持/参照のビット精度を表す.
  • パラメータnは、入力されなくてもよい.この場合、デフォルト値は0であるが、入力された場合、整数でなければならない.
  • nが0の場合、返される結果が整数、nが負の整数または正の整数の場合、返される値の数値タイプは、入力されるx数値のタイプと同じ(整数または浮動小数点タイプ)である.
  • nが正の整数であれば、四捨五入時に保持/参照される小数点以下の桁数を表す.
  • nが負の整数であれば、−1は10ビット四捨五入(捨てビット)に基づいて、−2は100ビット四捨五入(捨てビットと10ビット)に基づいて、順次類推される.
  • roundは数値(整数型または浮動小数点型)を返し、数値については正確性に注目する.数値は算術演算に用いられるため、例えばround(31415.0,2)であり、得られた結果は「31415.0」であり、要求に完全に合致し、浮動小数点型(伝達パラメータも浮動点型であるため)を約束通りに返した.小数点以下2桁の桁数精度(または有効桁数)も完全に満たす.数値にとって「31415.0」と「31415.00」は完全に等しいからである.
  • しかし注意しなければならないのは、上述した「数値」の有効ビットまたは精度は、私たちが普段言及している「どれだけの有効ビットを保持するか」という概念とは異なり、あるいは少なくともプログラミングの面では、両者は異なるレベルのことであり、前者は「数値」の精度に注目し、後者は表示または出力に使用される.注目するのは数値の文字列のフォーマットです.
  • したがって、数値を四捨五入した後、算術式計算に用いる場合、round関数を用いて数値を四捨五入処理し、必要に応じて有効ビット表示出力を保持するためにのみ用いる場合、文字列フォーマット出力を直接用いることができ、例えば、f’{31415:.2f}’を用いて、出力を「31415.00」とする.

  • 次のコードに示すように、それぞれ2つの数が印刷され、前者はround呼び出しで返された真の数値で出力され、後者は文字列でフォーマットされて出力されます.
    print(' 3.14159265      3 、       :',round(3.14159265, 3), f'{3.14159265:0.3f}')
    print(' 31415.9265       、       :',round(31415.9265), f'{31415.9265:.0f}')
    print(' 31415.9265             :',round(31415.9265, -2), f'{round(31415.9265, -2):.0f}')
    print(' 31415             :',round(31415, -2), f'{round(31415, -2):.0f}')
    print(' 31415      2 、       :',round(31415, 2), f'{31415:.2f}')
    print(' 31415.0      2 、       :',round(31415.0, 2), f'{31415.0:.2f}')
    
     3.14159265      3 、       : 3.142 3.142
     31415.9265       、       : 31416 31416
     31415.9265             : 31400.0 31400
     31415             : 31400 31400
     31415      2 、       : 31415 31415.00
     31415.0      2 、       : 31415.0 31415.00
    

    さらに重要なのは、Pythonのこのround内蔵関数について、次の2点に注意することです.
  • 四捨五入演算は必然的に進位または不進位に関わる.例えば、数値x(例えば1.45)に対して四捨五入演算を行い、進位でA(例えば1.5、小数点を保持した後1位)、進位でB(例えば1.4、小数点を保持した後1位)を得ると仮定すると、xはちょうどAとBの中間、すなわちAとBからの距離が同じである場合、この場合は「5」に遭遇するのが一般的ですが、この場合、AとBのどちらを取るのでしょうか.Pythonの処理は「偶数」(1.4の最後の4が偶数)を取ることで、私たちの伝統的な「五入」のやり方とは違います.
  • print('      ,  “  ”:',round(0.5),round(-0.5),round(2.5),round(125,-1),round(1.45,1))
    print('      ,  “  ”:',round(1.5),round(-1.5),round(1.5),round(135,-1),round(1.35,1))
    
          ,  “  ”: 0 0 2 120 1.4
          ,  “  ”: 2 -2 2 140 1.4
    
  • さらに、上記ルールには別の課題があり、「5」に遭遇し、特別な浮動小数点数に遭遇すると、状況はより複雑になり、例えば、round(6.675,2)が与えた結果は6.67であり、上記ルールに従って得られるべき6.68ではなく、Python言語のBugや問題ではなく、なぜなら、コンピュータ自体が浮動小数点数を10進数から2進数に変換する場合、いくつかの10進数を2進数で正確に表すことができない(除法中に絶えない場合に相当する)が存在し、コンピュータが数字を記憶するための2進数は限られており、必然的に後の数位が捨てられるため、x(例えば、現在の6.675)は、我々の10進数で見たものではなく、A(すなわち6.68)とB(すなわち6.67)との距離が完全に等しいのではなく、小さくなり、Bに近づいたので、round関数によって6.67が選択された.
  • print('             :',round(6.675,2),round(1.355,2))
    
                 : 6.67 1.35
    

    なお、上記2点の特殊な状況は、数値の文字列フォーマットに対して同様の影響を及ぼし、上記の規則と原因を知った後、類似の特殊な状況に遭遇した場合、私たちはこれ以上理解したり迷ったりすることはありません.さらに、特殊な厳格な場合、私たちは特殊な処理を行い、上記の状況の発生を回避する必要があるかもしれません.以下に示すように、文字列フォーマットによる上記の特殊な数値の出力状況を見てみましょう.
    print('        :')
    print('%.0f %.1f %.2f' % (-0.5,1.45,6.675))
    print('%.0f %.1f' % (-1.5,1.35))
    
    print('
    str.format() :'
    ) print('{:.0f} {:.1f} {:.2f}'.format(-0.5,1.45,6.675)) print('{:.0f} {:.1f}'.format(-1.5,1.35)) print('
    f-string :'
    ) print(f'{-0.5:.0f} {1.45:.1f} {6.675:.2f}') print(f'{-1.5:.0f} {1.35:.1f}')
            :
    -0 1.4 6.67
    -2 1.4
    
    str.format()    :
    -0 1.4 6.67
    -2 1.4
    
    f-string   :
    -0 1.4 6.67
    -2 1.4