2010-03-14 18 views
100

Làm thế nào để định dạng một phao để nó không làm mờ các số 0? Nói cách khác, tôi muốn chuỗi kết quả càng ngắn càng tốt ..?Định dạng phao nổi trong Python mà không cần các số thừa thừa

Giống như:

3 -> "3" 
3. -> "3" 
3.0 -> "3" 
3.1 -> "3.1" 
3.14 -> "3.14" 
3.140 -> "3.14" 
+0

Đó dụ không thực hiện bất kỳ ý nghĩa gì cả. '3.14 == 3.140' - Chúng là số * dấu chấm động * cùng. Đối với vấn đề đó, 3.140000 là cùng một số dấu phẩy động. Số không không tồn tại ở nơi đầu tiên. –

+15

@ S.Lott - Tôi nghĩ rằng vấn đề là IN số float mà không có dấu 0, không phải là sự tương đương thực tế của hai số. – pokstad

+1

@pokstad: Trong trường hợp đó, không có "thừa" không. '% 0.2f' và'% 0.3f' là hai định dạng cần thiết để tạo ra các số cuối cùng bên trái. Sử dụng '% 0.2f' để tạo hai số cuối cùng bên phải. –

Trả lời

116

nhớ, tôi muốn làm ('%f' % x).rstrip('0').rstrip('.') - đảm bảo điểm cố định định dạng chứ không phải là ký hiệu khoa học, vv vv Vâng, không phải là trơn và thanh lịch như %g, nhưng, nó hoạt động (và tôi không biết làm thế nào để buộc %g không bao giờ sử dụng ký pháp khoa học ;-).

+0

Cảm ơn nó hoạt động chính xác như tôi muốn! Chỉ cần một chút không may là không có loại trình bày cho loại hành vi .... – TarGz

+0

@TarGz, đồng ý, nó chắc chắn sẽ thanh lịch hơn để có một số% -flags cho điều đó. Đối với phương pháp Python hiện đại, hãy xem http://docs.python.org/library/string.html?highlight = string # string-format - nhưng nó có vẻ hành xử, liên quan đến vấn đề cụ thể của bạn, giống như ''% g'% x' được sử dụng, nó chỉ có cú pháp đẹp hơn. Ngoài ra, bây giờ bạn có thể phân lớp 'string.Formatter' để thực hiện các tùy chỉnh của riêng bạn. –

+4

Vấn đề duy nhất với đó là ''% .2f'% -0.0001' sẽ để bạn với' -0.00' và cuối cùng là '-0'. – Kos

107

Bạn có thể sử dụng %g để đạt được điều này:

'%g'%(3.140) 

hoặc, đối với Python 2.6 hoặc tốt hơn:

'{0:g}'.format(3.140) 

Từ docs for format: g nguyên nhân (trong số những thứ khác)

số 0 không đáng kể [được] bị xóa khỏi tên miền và dấu thập phân cũng bị xóa nếu có không còn chữ số nào theo sau.

+18

Ồ, gần như! Đôi khi nó định dạng float trong ký pháp khoa học (" 2.342E + 09 ") - có thể biến nó thành off, tức là luôn luôn hiển thị tất cả các chữ số có nghĩa? – TarGz

+2

Tại sao sử dụng ''{0: ...}' định dạng (giá trị)' khi bạn có thể sử dụng 'định dạng (giá trị, '...')'? Điều đó tránh phải phân tích cú pháp ra các định dạng specifier từ một chuỗi mẫu mà là nếu không có sản phẩm nào. –

0

Sử dụng% g có chiều rộng đủ lớn, ví dụ '% .99g'. Nó sẽ in bằng ký hiệu điểm cố định cho bất kỳ số lượng lớn nào hợp lý.

EDIT: nó không hoạt động

>>> '%.99g' % 0.0000001 
'9.99999999999999954748111825886258685613938723690807819366455078125e-08' 
+1

' .99' là chính xác, không phải chiều rộng; kinda hữu ích nhưng bạn không nhận được để thiết lập độ chính xác thực tế theo cách này (khác hơn là cắt nó cho mình). – Kos

+0

Điều này cũng rất sai, chỉ cần thử in 0,51 với điều đó. –

0

Có thể sử dụng chức năng format:

{}.format(float) 
9

gì về việc cố gắng tiếp cận dễ dàng nhất và có lẽ hiệu quả nhất? Phương pháp bình thường hóa() xóa tất cả các số 0 ở cuối cùng bên phải.

from decimal import Decimal 

print (Decimal('0.001000').normalize()) 
# Result: 0.001 

trình trong Python 2Python 3.

- Cập nhật -

Vấn đề duy nhất là @ BobStein-VisiBone chỉ ra, đó là con số như 10, 100, 1000 ... sẽ được hiển thị trong trình bày mũ. Điều này có thể dễ dàng cố định bằng cách sử dụng chức năng sau thay vì:

from decimal import Decimal 


def format_float(f): 
    d = Decimal(str(f)); 
    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize() 
+0

Trừ 'Decimal ('10 .0 '). Normalize()' trở thành '' 1E + 1'' –

6

Sau khi nhìn qua câu trả lời cho một số câu hỏi tương tự, điều này có vẻ là giải pháp tốt nhất đối với tôi:

def floatToString(inputValue): 
    return ('%.15f' % inputValue).rstrip('0').rstrip('.') 

lập luận của tôi:

%g không loại bỏ ký pháp khoa học.

>>> '%g' % 0.000035 
'3.5e-05' 

15 chữ số thập phân dường như tránh hành vi lạ và có nhiều chính xác cho nhu cầu của tôi.

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.') 
'1.35' 
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.') 
'1.3500000000000001' 

Tôi có thể đã sử dụng format(inputValue, '.15f'). thay vì '%.15f' % inputValue, nhưng đó là một chút chậm hơn (~ 30%).

Tôi có thể đã sử dụng Decimal(inputValue).normalize(), nhưng điều này cũng có một số vấn đề. Đối với một, nó là A LOT chậm hơn (~ 11x). Tôi cũng thấy rằng mặc dù nó có độ chính xác khá lớn, nó vẫn bị mất chính xác khi sử dụng normalize().

>>> Decimal('0.21000000000000000000000000006').normalize() 
Decimal('0.2100000000000000000000000001') 
>>> Decimal('0.21000000000000000000000000006') 
Decimal('0.21000000000000000000000000006') 

Quan trọng nhất, tôi sẽ vẫn được chuyển đổi để Decimal từ một float có thể làm cho bạn kết thúc với một cái gì đó khác hơn số bạn đặt vào đó. Tôi nghĩ rằng Decimal hoạt động tốt nhất khi số học nằm trong DecimalDecimal được khởi tạo bằng một chuỗi.

>>> Decimal(1.35) 
Decimal('1.350000000000000088817841970012523233890533447265625') 
>>> Decimal('1.35') 
Decimal('1.35') 

tôi chắc chắn rằng vấn đề chính xác của Decimal.normalize() có thể được điều chỉnh để những gì cần thiết sử dụng cài đặt bối cảnh, nhưng xem xét tốc độ đã chậm và không cần độ chính xác vô lý và thực tế là tôi vẫn muốn được chuyển đổi từ một nổi và mất chính xác anyway, tôi không nghĩ rằng nó là giá trị theo đuổi.

Tôi không quan tâm đến kết quả "-0" có thể do -0.0 là số dấu phẩy động hợp lệ và có thể hiếm khi xảy ra, nhưng vì bạn đã đề cập bạn muốn giữ kết quả chuỗi ngắn càng tốt, bạn luôn có thể sử dụng thêm một điều kiện với chi phí tăng thêm rất ít.

def floatToString(inputValue): 
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.') 
    return '0' if result == '-0' else result 
+0

Thật không may chỉ hoạt động với số có ít hơn khoảng) năm hoặc nhiều chữ số ở bên trái của chữ số thập phân. 'floatToString (12345.6)' trả về ''12345.600000000000364'' chẳng hạn. Giảm 15 trong '% .15f' xuống một số thấp hơn giải quyết nó trong ví dụ này, nhưng giá trị đó cần phải được giảm nhiều hơn và nhiều hơn khi số lượng lớn hơn. Nó có thể được tính toán động dựa trên log-base-10 của số, nhưng điều đó nhanh chóng trở nên rất phức tạp. – JohnSpeeks

0

Tôi nghĩ có cách dễ dàng hơn để thực hiện việc này với chức năng str.format mới. Nếu bạn chỉ chuyển đổi nó với str (ví dụ: str(.0300) ->0.3), nó thực hiện những gì mong muốn, chủ yếu. Nếu số lượng nhỏ hoặc đủ lớn, nó sẽ sử dụng ký hiệu số mũ, nhưng hầu hết nó sẽ chỉ in một số dấu phẩy động mà không có dấu 0 (hoặc hàng đầu). Nếu chuỗi định dạng là trống rỗng, sau đó nó về cơ bản phải viện đến đầu ra của str(), vì vậy đây sẽ làm việc nếu đó là chức năng mong muốn:

'{0}'.format(fp_num) 

Thậm chí điều này sẽ có tác dụng nếu đó là điều duy nhất được formated:

'{}'.format(fp_num) 
+0

'>>>" {} ". Định dạng (4.)' cho '' 4.0'' và giống: '>>>" {0} ".định dạng (4.)' cho '' 4.0'' – sebhaase

0

OP muốn loại bỏ các số không siêu và làm cho chuỗi kết quả càng ngắn càng tốt.

Tôi tìm thấy định dạng số mũ% g rút ngắn chuỗi kết quả cho các giá trị rất lớn và rất nhỏ. Vấn đề xảy ra đối với các giá trị không cần ký hiệu mũ, như 128.0, không phải là rất lớn hoặc rất nhỏ.

Dưới đây là một cách để định dạng số dưới dạng chuỗi ngắn chỉ sử dụng ký hiệu số mũ% g khi Decimal.normalize tạo chuỗi quá dài. Đây có thể không phải là giải pháp nhanh nhất (vì nó sử dụng Thập phân.bình thường)

def floatToString (inputValue, precision = 3): 
    rc = str(Decimal(inputValue).normalize()) 
    if 'E' in rc or len(rc) > 5: 
     rc = '{0:.{1}g}'.format(inputValue, precision)   
    return rc 

inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0] 

outputs = [floatToString(i) for i in inputs] 

print(outputs) 

# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10'] 
0

Bạn chỉ có thể sử dụng định dạng() để đạt được điều này:

format(3.140, '.10g') nơi 10 là chính xác mà bạn muốn.

0

Đối với float bạn có thể sử dụng này:

def format_float(num): 
    return ('%i' if num == int(num) else '%s') % num 

thử nghiệm nó:

>>> format_float(1.00000) 
'1' 
>>> format_float(1.1234567890000000000) 
'1.123456789' 

Đối Decimal thấy giải pháp ở đây: https://stackoverflow.com/a/42668598/5917543

1
>>> str(a if a % 1 else int(a)) 
+0

Bạn không có nghĩa là 'int (a) nếu một% 1 else a'? – beruic

+0

Kính gửi Beruic, câu trả lời của bạn cho kết quả trả lời tiêu cực. 'a nếu a% 1 else int (a)' là chính xác. Câu hỏi cần đầu ra trong chuỗi, Vì vậy, tôi chỉ cần thêm 'str' – Shameem

+0

Ah, tôi nhận được nó ngay bây giờ. 'a% 1' là trung thực bởi vì nó không khác. Tôi ngầm hiểu và hiểu nhầm nó là 'a% 1 == 0'. – beruic

2

Dưới đây là một giải pháp mà làm việc cho tôi. Đó là sự pha trộn của solution bởi PolyMesh và sử dụng .format()syntax mới.

for num in 3, 3., 3.0, 3.1, 3.14, 3.140: 
    print('{0:.2f}'.format(num).rstrip('0').rstrip('.')) 

Output:

3 
3 
3 
3.1 
3.14 
3.14 
+0

Chỉ có điều sai với điều này là bạn phải đặt số chữ số thập phân hợp lý. Bạn càng đặt nó càng cao, con số chính xác hơn bạn có thể đại diện, nhưng nếu bạn làm điều này rất nhiều, nó có thể làm giảm hiệu suất. – beruic

1

Trong khi định dạng là khả năng mà hầu hết các cách Pythonic, đây là một giải pháp thay thế bằng công cụ more_itertools.rstrip.

import more_itertools as mit 


def fmt(num, pred=None): 
    iterable = str(num) 
    predicate = pred if pred is not None else lambda x: x in {".", "0"} 
    return "".join(mit.rstrip(iterable, predicate)) 

assert fmt(3) == "3" 
assert fmt(3.) == "3" 
assert fmt(3.0) == "3" 
assert fmt(3.1) == "3.1" 
assert fmt(3.14) == "3.14" 
assert fmt(3.140) == "3.14" 
assert fmt(3.14000) == "3.14" 
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3" 

Số được chuyển thành một chuỗi, được tước các ký tự theo sau thỏa mãn vị từ. Định nghĩa hàm fmt là không bắt buộc, nhưng nó được sử dụng ở đây để kiểm tra các xác nhận, tất cả đều vượt qua. Lưu ý: nó hoạt động trên đầu vào chuỗi và chấp nhận các biến vị ngữ tùy chọn.

Xem thêm chi tiết về thư viện bên thứ ba này, more_itertools.

1

Bạn có thể đạt được điều đó theo cách pythonic nhất như thế:

python3:

"{:0.0f}".format(num) 
Các vấn đề liên quan