2010-06-10 70 views
4

我有在Python含有浮點數(例如num = 24654.123)的變量,並且我想確定的數量的精度和標度值(在Oracle感),所以123.45678應該給我(8,5),12.76應該給我(4,2)等。確定精度和特定數目的比例在Python

我首先想到使用字符串表示法(通過strrepr),但那些失敗的大數字(雖然我現在瞭解浮點數表示法的侷限性是這裏的問題):

>>> num = 1234567890.0987654321 
>>> str(num) = 1234567890.1 
>>> repr(num) = 1234567890.0987654 

編輯:

好以下要點。我應該澄清。這個數字已經是一個浮點數,正在通過cx_Oracle被推送到數據庫。我試圖盡我所能在Python中處理對於相應的數據庫類型來說太大的浮點數,因爲執行INSERT和處理Oracle錯誤的數據庫類型太大(因爲我想處理數字字段而不是記錄,一次)。我猜map(len, repr(num).split('.'))是最接近浮點的精度和比例嗎?

回答

13

獲取的數字小數點左邊的數字是很容易:

int(log10(x))+1 

的數字小數點右邊的數字是因爲浮點值的固有不準確的麻煩。我需要再花幾分鐘時間來弄清楚。

編輯:基於這一原則,這裏展示的代碼。

import math 

def precision_and_scale(x): 
    max_digits = 14 
    int_part = int(abs(x)) 
    magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1 
    if magnitude >= max_digits: 
     return (magnitude, 0) 
    frac_part = abs(x) - int_part 
    multiplier = 10 ** (max_digits - magnitude) 
    frac_digits = multiplier + int(multiplier * frac_part + 0.5) 
    while frac_digits % 10 == 0: 
     frac_digits /= 10 
    scale = int(math.log10(frac_digits)) 
    return (magnitude + scale, scale) 
+0

哇,謝謝!看起來應該這樣做。 – jrdioko 2010-06-11 17:02:05

+0

出於好奇,數字14從哪裏來?它與平臺無關嗎? – jrdioko 2010-06-11 18:09:53

+0

它依賴於平臺,但大多數平臺將使用IEEE-754。 http://en.wikipedia.org/wiki/Double_precision_floating-point_format#Double_precision_binary_floating-point_format我大概可以做到15,但我想保守一點,並確保我的四捨五入正常工作。 – 2010-06-11 18:21:48

3

我想你應該考慮使用decimal類型,而不是一個float的。 float類型將給出舍入誤差,因爲數字以二進制內部表示,但許多十進制數字沒有精確的二進制表示。

2

(0)請確認或否認:您將得到彩車使用,這是不可避免的,你不能爲小數,則Oracle數據類型包括基於十進制類型讓您的數據,這根本不匹配不可避免的。請解釋任何完全或部分拒絕。 (1)你的「大數失敗」的評論是誤導性的/無關的/錯誤的 - 你說你的出發點是一個浮點數,但是1234567890.0987654321不能表示爲一個浮點數,如下面的結果所示:再版()。

(2)也許你可以使用新的再版(Python的2.7和3.1),其提供再版的最小可能精度(x)中仍然滿足float(repr(x)) == x

例如舊的repr(1.1)產生「1.1000000000000001」,新的repr(1.1)產生「1.1」

關於「我猜map(len,repr(num).split('。'))是最接近的我會得到到浮點的精度和規模?「:您需要一個策略來處理(a)負數和零數字(b)數字,如1.1e20

在對象中挖掘/ floatobject.c應該爲float對象的新repr()調出C代碼,應該你需要使用Python 2.6或更早版本。

(3)或許,如果你告訴我們有關Oracle數據類型的規格,我們可以幫助你設計用於選擇檢查哪一款都包含給定float值。

+0

0.確認,本質上。一切都設置爲使用浮動,我不相信cx_Oracle會處理十進制類型,至少在我設置它的時候。 1.編輯更正。 2.有趣的是,不幸的是我落後於2.7。 3.我試圖編寫能夠動態工作的代碼,即使Oracle列類型的精確度或縮放比例發生變化。 (哎喲,抱歉格式不對) – jrdioko 2010-06-11 17:07:29

3

不可能使用浮點變量。例如,鍵入

>>> 10.2345 

給出:

10.234500000000001 

因此,要6,4出這一點,你必須找到一種方式進入10.234510.234500000000001用戶,這是不可能的使用浮點數來區分。這與浮點數的存儲方式有關。使用decimal

import decimal 
a = decimal.Decimal('10.234539048538495') 
>>> str(a) 
'10.234539048538495' 
>>> (len(str(a))-1, len(str(a).split('.')[1])) 
(17,15) 
+1

是可能的浮動;看到我的答案。 – 2010-06-10 23:20:03

+1

我的答案也可以。關鍵是將數字的數量限制爲浮點類型的已知精度並對結果進行四捨五入。 – 2010-06-11 15:36:34

1

好像str是更好的選擇比repr

>>> r=10.2345678 
>>> r 
10.234567800000001 
>>> repr(r) 
'10.234567800000001' 
>>> str(r) 
'10.2345678' 
相關問題