28

私はxlrd、Excelスプレッドシートから値を取得し、それらを使用してさまざまなことを行うために使用するPythonスクリプトを維持しています。スプレッドシートの一部のセルは高精度の数値であり、そのままにしておく必要があります。これらのセルの1つの値を取得すると、xlrd0.38288746115497402floatなどが表示されます。

ただし、コードの後半でこの値を文字列に取り込む必要があります。str(value)またはを実行すると、「 0.382887461155 unicode(value)」のようなものが返されます。要件は、これは受け入れられないと言っています。精度を維持する必要があります。

私はこれまでにいくつかのことを試しましたが、成功しませんでした。1つ目は、文字列の書式設定を使用することでした。

data = "%.40s" % (value) 
data2 = "%.40r" % (value) 

ただし、どちらも同じ丸められた数値「0.382887461155」を生成します。

SOやインターネット上の他の場所で同様の問題を抱えている人々を探し回ったとき、一般的な提案はDecimalクラスを使用することでした。しかし、データが私に与えられる方法を変更することはできません(誰かがxlrd小数を返す秘密の方法を知っていない限り)。そして、私がこれをやろうとすると:

data = Decimal(value)

しかし、TypeError: Cannot convert float to Decimal. First convert the float to a string.明らかに文字列に変換できません。そうしないと、精度が低下します。

そうそう、私はどんな提案にもオープンです-必要ならば本当にひどい/ハッキーなものでさえ。私はPython(私自身はJava / C#の人の方が多い)の経験があまりないので、ここで何らかの根本的な誤解がある場合は、遠慮なく訂正してください。

編集:Python2.6.4を使用していることを追加しようと思っただけです。バージョンの変更を妨げる正式な要件はないと思います。他のコードを台無しにする必要はありません。

4

5 に答える 5

54

私はxlrdの作者です。他の回答やコメントには多くの混乱があり、コメントで反論するので、私は回答でそれを行っています。

@katriealex:"""xlrdの内臓で精度が失われている"""---完全に根拠がなく真実ではありません。xlrdは、XLSファイルに格納されている64ビット浮動小数点数を正確に再現します。

@katriealex:"""ローカルのxlrdインストールを変更してフロートキャストを変更できる可能性があります"""---なぜこれを実行するのかわかりません。16ビット整数を浮動させても精度が失われることはありません!!! いずれの場合も、そのコードは、Excel 2.Xファイル(INTEGERタイプのセルレコードが含まれている)を読み取る場合にのみ使用されます。OPは、彼がそのような古代のファイルを読んでいることを示していません。

@jloubert:あなたは間違っているに違いありません。"%.40r" % a_floatと同じ答えを得るバロック的な方法ですrepr(a_float)

@EVERYBODY:精度を維持するために、浮動小数点数を小数に変換する必要はありません。この関数の要点はrepr()、次のことが保証されていることです。

float(repr(a_float)) == a_float

Python 2.X(X <= 6)reprは、元の値を再現することが保証されているため、定数の10進数の17桁の精度を提供します。それ以降のPython(2.7、3.1)は、元の値を再現する最小の小数点以下の桁数を提供します。

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.38288746115497402'
>>> float(repr(f)) == f
True

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.382887461154974'
>>> float(repr(f)) == f
True

つまり、floatオブジェクトのすべての精度を保持する文字列が必要な場合は、preserved = repr(the_float_object)...を使用して後で値を復元しますfloat(preserved)とても簡単です。decimalモジュールは必要ありません。

于 2010-08-14T01:09:12.863 に答える
3

repr()精度を失うことなく文字列に変換してから、Decimalに変換するために使用できます。

>>> from decimal import Decimal
>>> f = 0.38288746115497402
>>> d = Decimal(repr(f))
>>> print d
0.38288746115497402
于 2010-08-13T23:42:55.583 に答える
1

編集:私は間違っています。スレッドの残りの部分が理にかなっているように、この答えをここに残しておきますが、それは真実ではありません。上記のジョン・マチンの答えをご覧ください。ありがとうみんな=)。

上記の答えがうまくいけば、それは素晴らしいことです-それはあなたに多くの厄介なハッキングを救うでしょう。ただし、少なくとも私のシステムでは、そうではありません。あなたは例えばでこれをチェックすることができます

import sys
print( "%.30f" % sys.float_info.epsilon )

その数は、システムがゼロと区別できる最小のフロートです。それよりも小さいものは、操作を実行するときにフロートからランダムに加算または減算される場合があります。これは、少なくとも私のPythonセットアップでは、の内臓の精度が失われ、xlrdそれを変更せずにできることは何もないように思われることを意味します。これは奇妙です。私はこの事件が以前に起こったと思っていたが、明らかにそうではなかった!

xlrdローカルインストールを変更してfloatキャストを変更できる場合があります。開いてsite-packages\xlrd\sheet.py1099行目に移動します。

...
elif rc == XL_INTEGER:
                    rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
                    self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
...

floatキャストに注意してください。これをaに変更して、decimal.Decimal何が起こるかを確認できます。

于 2010-08-13T23:50:27.733 に答える
0

編集:それが正しく機能しなかったb/c私の前の答えをクリアしました。

私はPython2.6.5を使用していますが、これでうまくいきます。

a = 0.38288746115497402
print repr(a)
type(repr(a))    #Says it's a string

注:これは文字列に変換されるだけです。Decimal必要に応じて、後で自分自身に変換する必要があります。

于 2010-08-13T23:45:20.710 に答える
0

すでに述べたように、フロートはまったく正確ではありません。そのため、精度を維持することは多少誤解を招く可能性があります。

floatオブジェクトから最後のすべての情報を取得する方法は次のとおりです。

>>> from decimal import Decimal
>>> str(Decimal.from_float(0.1))
'0.1000000000000000055511151231257827021181583404541015625'

別の方法はそうなるでしょう。

>>> 0.1.hex()
'0x1.999999999999ap-4'

両方の文字列は、フロートの正確な内容を表します。他のほとんどすべては、Pythonがおそらく意図されたと考えているようにfloatを解釈します(ほとんどの場合正しいです)。

于 2010-08-14T15:41:47.367 に答える