2012-09-07 45 views
9

我想用python打印一個工程格式的數字,但我似乎無法讓它工作。語法SEEMS很簡單,但它不起作用。工程格式的打印號碼

>>> import decimal 
>>> x = decimal.Decimal(1000000) 
>>> print x 
1000000 
>>>> print x.to_eng_string() 
1000000 

我想不通這是爲什麼。這兩個值不相等(一個是字符串,另一個是int)。在decimal中設置各種上下文似乎也沒有幫助。任何線索或想法?

+0

我發現這裏的解決方案「%0.4克」%× – lehalle

回答

17

爲了得到這個工作的編輯,你必須先規範十進制:

>>> x = decimal.Decimal ('10000000') 

>>> x.normalize() 
Decimal('1E+7') 

>>> x.normalize().to_eng_string() 
'10E+6' 

其原因可以通過鑽研到源被發現碼。

如果檢查(從gzip壓縮的源焦油球hereLib/decimal.py)在Python 2.7.3源代碼樹to_eng_string(),它只是簡單地調用__str__eng設置爲true。

然後你可以看到,它決定有多少數字去到小數點左邊最初:

leftdigits = self._exp + len(self._int) 

下表顯示了該值是這兩件事情:

      ._exp  ._int   len leftdigits 
         -----  ---------  --- ---------- 
Decimal (1000000)   0  '1000000'  7   7 
Decimal ('1E+6')    6  '1'    1   7 

後一直延續的代碼是:

if self._exp <= 0 and leftdigits > -6: 
    # no exponent required 
    dotplace = leftdigits 
elif not eng: 
    # usual scientific notation: 1 digit on left of the point 
    dotplace = 1 
elif self._int == '0': 
    # engineering notation, zero 
    dotplace = (leftdigits + 1) % 3 - 1 
else: 
    # engineering notation, nonzero 
    dotplace = (leftdigits - 1) % 3 + 1 

,你可以看到,unle它已經在指數在一定範圍內(self._exp > 0 or leftdigits <= -6),在字符串表示中不會給它任何指數。


進一步的調查顯示了這種行爲的原因。查看代碼本身,您會發現它基於General Decimal Arithmetic Specification(PDF here)。

的「以科學串」操作轉換:

如果你搜索to-scientific-string(上to-engineering-string在很大程度上依賴)該文件,它在部分(轉述,並與我大膽位)規定一個數字到一個字符串,使用科學記數法如果需要指數。該操作不受上下文影響。

如果該數量爲有限數,則:

使用字符0至9的係數首先被轉換爲一個字符串在基座10與無前導零(除非它的值是零,在這種情況下單個0字符被使用)。

接下來,計算調整後的指數;這是指數,加上轉換系數中的字符數,少一個。也就是說,指數+(clength-1),其中clength是係數的長度,以十進制數字表示。

如果指數小於或等於零,並且調整後的指數大於或等於-6,則該數字將被轉換爲不使用指數表示法的字符形式。在這種情況下,如果指數爲零,則不會添加小數點。否則(指數將爲負數),將插入一個小數點,指數的絕對值將指定小數點右側的字符數。根據需要將「0」字符添加到轉換系數的左側。如果在插入後沒有字符先於小數點,那麼傳統的「0」字符是前綴。

換句話說,它正在做它做的事情,因爲這是標準要求它做的事情。

+0

爲什麼要麻煩檢查一下?我問了一些具體的問題。然後它決定我不想要那個,只想要我給它的東西?有時候Python會讓我困惑...... – jmurrayufo

+2

@jmurrayufo,檢查更新。基本上,這是因爲這是標準要求它做的。 – paxdiablo

4

在我看來,你將不得不推出自己的:

from math import log10 
def eng_str(x): 
    y = abs(x) 
    exponent = int(log10(y)) 
    engr_exponent = exponent - exponent%3 
    z = y/10**engr_exponent 
    sign = '-' if x < 0 else '' 
    return sign+str(z)+'e'+str(engr_exponent) 

雖然你可能要採取多一點關懷在z部分的格式...

沒有很好的測試。隨意如果您發現錯誤

+0

雖然我不介意的想法,我更好奇爲什麼'decimal'類並沒有做什麼,似乎它應該,或我怎麼用錯了 – jmurrayufo

+0

@jmurrayufo - 對不起,我想我誤解了這個問題:)。 – mgilson

-1

此前我試着回答,但發現它只是科學記數法。 未來版本的Python格式說明符(3.2?)將支持工程表示法,但不支持Python 2.7。

看待這個問題http://bugs.python.org/issue8060

+1

其實,這是相關的,但它是EFloat類型而不是十進制類型。 – paxdiablo

+0

paxdiablo的解釋看起來不對,EFloat提到的似乎只是想要的行爲的示範類。但從2010年起這個問題最近已被封閉/拒絕。 – handle

2

我意識到這是一個古老的線程,但它確實來了附近的一個python engineering notation搜索的頂部。

我是一個喜歡「工程101」工程單位的工程師。我甚至不喜歡名稱如0.1uF,我希望讀100nF。我玩Decimal類,並沒有真正喜歡它在可能值範圍內的行爲,所以我推出了一個名爲engineering_notation的包,它可以通過pip安裝。

pip install engineering_notation 

通過Python內:

>>> from engineering_notation import EngNumber 
>>> EngNumber('1000000') 
1M 
>>> EngNumber(1000000) 
1M 
>>> EngNumber(1000000.0) 
1M 
>>> EngNumber('0.1u') 
100n 
>>> EngNumber('1000m') 
1 

此包還支持比較和其他簡單的數值的操作。

https://github.com/slightlynybbled/engineering_notation