2012-09-07 40 views
9

Tôi đang cố gắng in một số thành định dạng kỹ thuật bằng python, nhưng tôi dường như không thể làm cho nó hoạt động được. Cú pháp SEEMS đủ đơn giản, nhưng nó không hoạt động.Số in theo định dạng kỹ thuật

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

Tôi không thể hiểu tại sao điều này xảy ra. Hai giá trị không bằng nhau (một là một chuỗi, giá trị kia là một int). Việc thiết lập các ngữ cảnh khác nhau trong decimal cũng không giúp được gì. Bất kỳ manh mối hay ý tưởng nào?

+0

tôi tìm thấy giải pháp ở đây "% .4g" % x – lehalle

Trả lời

17

Để có được điều này để làm việc, bạn cần phải chuẩn hóa số thập phân thứ nhất:

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

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

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

Lý do cho điều này có thể được phát hiện bởi delving vào nguồn mã.

Nếu bạn kiểm tra to_eng_string() trong Python 2.7.3 cây nguồn (Lib/decimal.py từ tar bóng nguồn gzipped here), nó chỉ đơn giản gọi __str__ với eng set là true.

Sau đó bạn có thể thấy rằng nó quyết định có bao nhiêu chữ số đi đến bên trái của số thập phân ban đầu với:

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

Bảng dưới đây cho thấy những gì các giá trị dành cho những hai điều:

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

Các mã tiếp tục sau đó là:

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 

và bạn có thể thấy rằng, unle ss nó đã có số mũ trong một phạm vi nhất định (self._exp > 0 or leftdigits <= -6), sẽ không có số mũ nào được hiển thị trong biểu diễn chuỗi.


Điều tra thêm cho thấy lý do cho hành vi này. Nhìn vào mã, bạn sẽ thấy mã này dựa trên số General Decimal Arithmetic Specification (PDF here).

Nếu bạn tìm kiếm rằng tài liệu cho to-scientific-string (mà trên đó to-engineering-string được chủ yếu dựa), nó khẳng định một phần (diễn giải, và với bit đậm của tôi):

Các "to-khoa học-string" cải đạo hoạt động một số vào một chuỗi, sử dụng ký pháp khoa học nếu số mũ là cần thiết. Thao tác không bị ảnh hưởng bởi ngữ cảnh.

Nếu số là một số hữu hạn thì:

Hệ số là lần đầu tiên chuyển đổi sang một chuỗi trong cơ sở mười bằng cách sử dụng ký tự từ 0 đến 9 không có số không hàng đầu (trừ khi giá trị của nó là số không, trong trường hợp một duy nhất 0 ký tự được sử dụng).

Tiếp theo, số mũ được điều chỉnh được tính; đây là số mũ, cộng với số ký tự trong hệ số được chuyển đổi, ít hơn một. Tức là, số mũ + (độ dài-1), trong đó độ dài là chiều dài của hệ số theo các chữ số thập phân.

Nếu số mũ nhỏ hơn hoặc bằng 0 và số mũ được điều chỉnh lớn hơn hoặc bằng -6, số sẽ được chuyển thành dạng ký tự mà không sử dụng ký hiệu lũy thừa. Trong trường hợp này, nếu số mũ bằng 0 thì không thêm dấu thập phân. Nếu không (số mũ sẽ là số âm), một điểm thập phân sẽ được chèn vào với giá trị tuyệt đối của số mũ xác định số ký tự ở bên phải dấu thập phân. Các ký tự “0” được thêm vào bên trái của hệ số được chuyển đổi nếu cần. Nếu không có ký tự nào đứng trước dấu thập phân sau khi chèn, thì ký tự “0” thông thường được đặt trước.

Nói cách khác, nó đang làm những gì nó đang làm bởi vì đó là những gì tiêu chuẩn bảo nó làm.

+0

Tại sao phải kiểm tra điều đó? Tôi hỏi nó cho một cái gì đó cụ thể. Sau đó nó quyết định rằng tôi không muốn điều đó và chỉ muốn những gì tôi đã cho nó? Python lẫn lộn tôi vào những lúc ... – jmurrayufo

+2

@jmurrayufo, kiểm tra cập nhật. Về cơ bản, nó làm điều đó bởi vì đó là những gì tiêu chuẩn bảo nó làm. – paxdiablo

4

Dường như với tôi rằng bạn sẽ phải cuộn của riêng bạn:

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) 

Mặc dù bạn có thể muốn chăm sóc nhiều hơn một chút trong định dạng của phần z ...

không được kiểm tra tốt. Cảm thấy tự do để chỉnh sửa nếu bạn tìm thấy lỗi

+0

Trong khi tôi không nhớ ý tưởng, tôi tò mò hơn vì sao 'decimal' lớp không làm những gì có vẻ như nó nên, hoặc làm thế nào tôi đang sử dụng nó sai – jmurrayufo

+0

@ jmurrayufo - Xin lỗi, tôi cho rằng tôi hiểu sai câu hỏi :). – mgilson

-1

Trước đây tôi đã cố gắng trả lời, nhưng phát hiện ra nó chỉ là ký pháp khoa học. Ký pháp kỹ thuật sẽ được hỗ trợ trong các phiên bản tương lai của trình định dạng định dạng Python (3.2?), Nhưng không được hỗ trợ trong Python 2.7.

Nhìn vào vấn đề này http://bugs.python.org/issue8060

+1

Thực ra, điều đó có liên quan nhưng nó dành cho các loại EFloat hơn là loại thập phân. – paxdiablo

+0

giải thích của paxdiablo có vẻ sai, EFloat được đề cập dường như chỉ là một lớp trình diễn cho hành vi mong muốn. Nhưng vấn đề này từ năm 2010 gần đây đã bị đóng/bị từ chối. – handle

2

Tôi nhận ra rằng đây là một chủ đề cũ, nhưng nó đến gần đầu một tìm kiếm cho python engineering notation.

Tôi là kỹ sư thích các đơn vị kỹ thuật "kỹ thuật 101". Tôi thậm chí không thích các chỉ định như 0.1uF, tôi muốn đọc 100nF. Tôi đã chơi với lớp Decimal và không thực sự thích hành vi của nó trong phạm vi giá trị có thể, vì vậy tôi đã cuộn một gói có tên là engineering_notation có thể cài đặt được pip.

pip install engineering_notation 

Từ bên trong Python:

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

Gói này cũng hỗ trợ so sánh và hoạt động số đơn giản khác.

https://github.com/slightlynybbled/engineering_notation

Các vấn đề liên quan