Định dạng phao mà không có số 0


181

Làm cách nào tôi có thể định dạng một float để nó không chứa các số 0 ở cuối? Nói cách khác, tôi muốn chuỗi kết quả càng ngắn càng tốt.

Ví dụ:

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

Ví dụ đó không có ý nghĩa gì cả. 3.14 == 3.140- Chúng là cùng một số dấu phẩy độ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.
S.Lott

33
@ S.Lott - Tôi nghĩ rằng vấn đề là IN số float mà không có các số 0 ở cuối, 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ó số "thừa" nào. %0.2f%0.3flà 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để sản xuất hai số cuối cùng bên phải.
S.Lott

6
3.0 -> "3"vẫn là một trường hợp sử dụng hợp lệ. print( '{:,g}'.format( X )làm việc cho tôi để đầu ra 3ở đâu X = 6 / 2và khi X = 5 / 2tôi có một đầu ra 2.5như mong đợi.
Thợ làm giày 27/2/2016

1
câu hỏi cũ, nhưng .. print("%s"%3.140)cung cấp cho bạn những gì bạn muốn. (Tôi đã thêm một câu trả lời xuống bên dưới ...)
drevicko

Câu trả lời:


178

Tôi, tôi sẽ làm ('%f' % x).rstrip('0').rstrip('.')- đảm bảo định dạng điểm cố định thay vì ký hiệu khoa học, v.v ... Vâng, không bóng bẩy và thanh lịch như%g , nhưng, nó hoạt động (và tôi không biết cách ép buộc %gkhông bao giờ sử dụng ký hiệu khoa học; -).


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

3
@ alexanderlukanin13 vì độ chính xác mặc định là 6, xem docs.python.org/2/library/string.html : 'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6.Bạn sẽ phải sử dụng '% 0.7f' trong dung dịch trên.
derenio

3
@derenio Điểm hay :-) Tôi chỉ có thể thêm rằng nâng cao độ chính xác ở trên '%0.15f'là một ý tưởng tồi, bởi vì những điều kỳ lạ bắt đầu xảy ra.
alexanderlukanin13

1
Trong trường hợp bạn đang ở giữa một chuỗi khác: print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
chịu lỗi

1
@Alex Martelli, thoát khỏi rstriplệnh kép . Thay vào đó, chỉ sử dụng cách này để loại bỏ cả dấu chấm ( .) và tất cả các số 0 ở sau trong một thao tác:('%f' % x).rstrip('.0')
Gabriel Staples

143

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 trở lên:

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

Từ các tài liệu choformat : gnguyên nhân (trong số những thứ khác)

các số 0 ở cuối không đáng kể [được] xóa khỏi ý nghĩa và dấu thập phân cũng bị xóa nếu không có chữ số nào còn lại theo sau nó.


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

5
Tại sao sử dụng '{0:...}'.format(value)khi bạn có thể sử dụng format(value, '...')? Điều đó tránh việc phải phân tích trình xác định định dạng từ một chuỗi mẫu trống.
Martijn Pieters

2
@MartijnPieters: Chi phí rất nhỏ để phân tích cú pháp định dạng định dạng bị ngập bởi các AFAICT trên cao khác; trong thực tế, điểm chuẩn cục bộ của tôi trên 3.6 (với phạm vi chức năng của microbenchmark để mô hình chính xác mã thực) đã format(v, '2.5f')mất ~ 10% lâu hơn '{:2.5f}'.format(v). Ngay cả khi nó không, tôi có xu hướng sử dụng strbiểu mẫu phương thức bởi vì khi tôi cần điều chỉnh nó, thêm các giá trị bổ sung cho nó, v.v., sẽ có ít thay đổi hơn. Tất nhiên, kể từ 3.6, chúng tôi có chuỗi f cho hầu hết các mục đích. :-)
ShadowRanger

5
Trong Python 3.6, điều này có thể được rút ngắn về f"{var:g}"nơi varlà một biến float.
TheGreatCabbage

12

Còn về cách thử phương pháp dễ nhất và có lẽ hiệu quả nhất? Phương thức normalize () loại bỏ tất cả các số 0 ở cuối bên phải.

from decimal import Decimal

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

Hoạt động trong Python 2Python 3 .

- Cập nhật -

Vấn đề duy nhất như @ BobStein-VisiBone đã chỉ ra, đó là các số như 10, 100, 1000 ... sẽ được hiển thị dưới dạng đại diện theo cấp số nhân. Điều này có thể dễ dàng được sửa chữa bằng cách sử dụng chức năng sau đây:

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()

2
Ngoại trừ Decimal('10.0').normalize()trở thành'1E+1'
Bob Stein

11

Sau khi xem qua câu trả lời cho một số câu hỏi tương tự, đây dường như là giải pháp tốt nhất cho tôi:

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

Lý luận của tôi:

%g không thoát khỏi ký hiệu khoa học.

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

15 vị trí 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 chậm hơn một chút (~ 30%).

Tôi có thể đã sử dụng Decimal(inputValue).normalize(), nhưng điều này cũng có một vài vấn đề. Đối với một, nó chậm hơn rất nhiều (~ 11x). Tôi cũng thấy rằng mặc dù nó có độ chính xác khá lớn, nhưng 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 vẫn sẽ chuyển đổi Decimaltừ một floatthứ có thể khiến bạn kết thúc bằng thứ gì đó không phải là số bạn đặt trong đó. Tôi nghĩ rằng Decimalhoạt động tốt nhất khi số học ở lại DecimalDecimalđược khởi tạo với 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 Decimal.normalize()có thể được điều chỉnh theo những gì cần thiết khi sử dụng cài đặt ngữ cảnh, nhưng xem xét tốc độ đã chậm và không cần độ chính xác lố bịch và thực tế là tôi vẫn chuyển đổi từ phao và mất độ chính xác, tôi đã không Tôi không nghĩ rằng nó đáng để theo đuổi.

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

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

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

1
Một cách để giải quyết vấn đề đó có thể là giới hạn độ dài của toàn bộ số (thay vì chỉ các chữ số sau số thập phân):result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
Timothy Smith

@JohnSpeek Tôi không chắc điều này có thể tránh được. Đó là một tác dụng phụ của các số trôi nổi không thể biểu thị độ chính xác nếu cần nhiều chữ số hơn ở phía bên trái. Từ những gì tôi có thể nói, số xuất hiện dưới dạng một chuỗi là cùng một số xuất hiện dưới dạng nổi hoặc ít nhất là đại diện gần nhất của chuỗi. >>>12345.600000000000364 == 12345.6 True
PolyMesh

Tôi đã viết một giải pháp khác .
niitsuma

8

Đây là một giải pháp hiệu quả với tôi. Đó là sự pha trộn của giải pháp của PolyMesh và sử dụng .format() cú pháp mới .

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

Đầu ra :

3
3
3
3.1
3.14
3.14

Điều duy nhất sai với điều này là bạn phải đặt một số chữ số thập phân hợp lý. Bạn đặ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 nhiều, nó có thể làm giảm hiệu suất.
beruic

1
Thêm vào nhận xét của beruic, điều này không hoạt động đối với các số float có độ chính xác cao hơn (ví dụ 3.141) vì .2fđược mã hóa cứng.
TrebledJ

3

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

format(3.140, '.10g') trong đó 10 là độ chính xác bạn muốn


2
>>> str(a if a % 1 else int(a))

Ý bạn là int(a) if a % 1 else asao?
beruic

Beruic thân mến, câu trả lời của bạn cho kết quả tiêu cực. a if a % 1 else int(a)đúng. Câu hỏi cần đầu ra trong chuỗi, vì vậy tôi vừa thêmstr
Shameem

Ah, tôi hiểu rồi a % 1là sự thật bởi vì nó khác không. Tôi mặc nhiên và hiểu sai nó là a % 1 == 0.
beruic

2

Mặc dù định dạng có khả năng là cách Pythonic nhất, đây là một giải pháp thay thế bằng cách sử dụng more_itertools.rstripcông cụ.

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 đổi thành một chuỗi, được loại bỏ các ký tự dấu thỏa mãn một vị ngữ. Định nghĩa hàmfmt 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 vị từ tùy chọn.

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


1

Nếu bạn có thể sống với 3. và 3.0 xuất hiện dưới dạng "3.0", một cách tiếp cận rất đơn giản là các dải số 0 bên phải từ các biểu diễn float:

print("%s"%3.140)

(cảm ơn @ellimilial vì đã chỉ ra các ngoại lệ)


1
Nhưng print("%s"%3.0)không.
ellimilial

1

Sử dụng gói QuantiPhy là một tùy chọn. Thông thường QuantiPhy được sử dụng khi làm việc với các số có đơn vị và hệ số tỷ lệ SI, nhưng nó có nhiều tùy chọn định dạng số đẹp.

    >>> from quantiphy import Quantity

    >>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:p}')
          3 -> 3
         3. -> 3
        3.0 -> 3
        3.1 -> 3.1
       3.14 -> 3.14
      3.140 -> 3.14
    3.14000 -> 3.14

Và nó sẽ không sử dụng ký hiệu điện tử trong tình huống này:

    >>> cases = '3.14e-9 3.14 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:,p}')
    3.14e-9 -> 0
       3.14 -> 3.14
     3.14e9 -> 3,140,000,000

Một cách khác bạn có thể thích là sử dụng các yếu tố tỷ lệ SI, có thể với các đơn vị.

    >>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case, 'm')
    ...    print(f'{case:>7} -> {q}')
       3e-9 -> 3 nm
    3.14e-9 -> 3.14 nm
          3 -> 3 m
       3.14 -> 3.14 m
        3e9 -> 3 Gm
     3.14e9 -> 3.14 Gm

0

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

Tôi thấy định dạng hàm 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 theo cấp số nhân, như 128.0, không quá lớn hoặc rất nhỏ.

Dưới đây là một cách để định dạng số dưới dạng các chuỗi ngắn sử dụng ký hiệu số mũ% g chỉ khi Decimal.n normalize tạo các 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 Decimal.n normalize)

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

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

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

Kiểm tra nó:

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

Để biết số thập phân, hãy xem giải pháp tại đây: https://stackoverflow.com/a/42668598/5917543



0

Đây là câu trả lời:

import numpy

num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')

đầu ra "3.14" và "3"

trim='-' loại bỏ cả dấu 0 và dấu thập phân.


-1

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

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

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

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

-1

Bạn có thể sử dụng max()như thế này:

print(max(int(x), x))


1
bạn phải xem xét trường hợp xtiêu cực. if x < 0: print(min(x), x) else : print(max(x), x)
ThunderPhoenix

Một phương pháp hữu ích khi tôi muốn làm json Stringify. float 1.0 thay đổi thành int 1, vì vậy nó hoạt động giống như trong javascript.
pingze

-3

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

trăn3:

"{:0.0f}".format(num)

Bạn đúng. Cách dễ nhất là sử dụng định dạng "{: g}". (
Num

-4

Xử lý% f và bạn nên đặt

% .2f

, trong đó: .2f == .00 phao.

Thí dụ:

in "Giá:% .2f"% giá [sản phẩm]

đầu ra:

Giá: 1,50


1
Điều này được nêu rõ ràng không phải những gì câu hỏi muốn. Cần downvote.
tập
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.