2016-11-09 7 views
0

人間が表示する浮動小数点数の書式を扱うインプレースコードを扱っています。Python書式の文字列と浮動小数点表現

現在の実装では、この処理を行います。

理にかなっていると、ほとんどの部分だけで正常に動作し
"{0:.24f}".format(some_floating_point).rstrip('0') 

。しかし、0.0003のような値に直面したときには、うまくいっていません。

>>> "{0:.24f}".format(0.0003).rstrip('0') 
'0.000299999999999999973719' 

さらに調査したところ、Pythonは要求された桁数に基づいて基礎となる表現を変更しているようです。

>>> "{0:.15f}".format(0.0003) 
'0.000300000000000' 
>>> "{0:.20f}".format(0.0003) 
'0.00029999999999999997' 

私の前提は単精度対doubleです。

ユーザーは、データベースに格納されている場所でこれらの値をdoubleとして入力し、後でフォームを再度レンダリングするときに、フィールドに同じ値が事前入力されます。したがって、これらの表現の1:1マッピングが必要です。

私の質問は次のようなものです:この行動に対処するための、よりエレガントで安全な方法は何ですか?これまでの私の最善の努力はlog10に関わってきており、それをきちんと置くのに理想的ではありません。

編集:プルーンは値が実際には変化していないと指摘していますが、フォーマットで行われた丸めは9のセットを0にします。その行動は意味をなさないが、解決策はまだ私を逃げている。

+0

は、このエレガントな解決策はありません、それは私が答えを提供できるベース2とベース10との違いに固有のだが、それはあまりにもlog10のを必要とする - あなたはの桁数を制限する必要があります形式は、倍精度浮動小数点(Double)に格納されている有効桁数より1少ない数になります。 –

答えて

1

保存されている番号が届きます。 0.0003はバイナリ分数として正確に格納することはできません。例:

>>> 0.00029999999999999997 == 0.0003 
True 

印刷書式設定では、最下位桁の数値を丸めます。倍精度は、問題をさらに右に押すだけです。問題を基数10の目に完全に "解決"するには、小数点以下の算術に切り替えるか、またはより単純な値に十分近い数の文字列ハンドラを作成する必要があります(小数部の9または0の疑わしい文字列)。


ここでは、関数の開始点を示します。私はそれを0.0004でテストしました。これは0.0004以上の毛髪として保存されています。 9の場合は練習として残されます:-)。

def str_round(x): 
    size = 6 
    nines = '9'*size 
    zeros = '0'*size 

    str = "{0:.24f}".format(x).rstrip('0') 
    str_len = len(str) 
    print str, str_len 

    if nines in str: 
     # replace leading digit with one more 
     pos = str.index(nines) 
     # ADD CODE HERE 
     # Turn the leading portion into an integer; 
     # increment and convert back to zero-leading string. 
     # Fill out the rest with zeros. 

    elif zeros in str: 
     # Change all trailing digits to 0 
     pos = str.index(zeros) 
     str = str[:pos] + '0'*(str_len - pos) 

    return str 

print str_round(0.0004) 
+0

ああ、私は何とかそれを理解できませんでした。 29999は最大30000に切り上げられます。したがって、この場合は9ではない数字でフォーマットすることを要求するときに「中断」します。何らかの理由で私はもっと複雑なことをしていると思った。しかし、まだ解決策の多くを提供していません。 – Zigsaz

関連する問題