1.3k

Tôi muốn ađược làm tròn đến 13,95 .

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

Các roundchức năng không hoạt động theo cách tôi mong đợi.

|
  • 2
  • 5

    Hmm ... Bạn đang cố gắng đại diện cho tiền tệ? Nếu vậy, bạn không nên sử dụng phao cho đô la. Bạn có thể có thể sử dụng phao cho đồng xu, hoặc bất kỳ đơn vị tiền tệ phổ biến nhỏ nhất mà bạn đang cố gắng tạo ra, nhưng cách tốt nhất là sử dụng biểu diễn thập phân, như HUAGHAGUAH đã đề xuất trong câu trả lời của anh ấy.

    – Ngô Cao Kỳ 03:39:21 13/04/2009
  • 50

    Điều quan trọng là không đại diện cho tiền tệ trong float. Phao không chính xác. Nhưng số tiền hoặc xu là số nguyên. Do đó, số nguyên là cách chính xác để đại diện cho tiền tệ.

    – Nguyễn Tùng Lâm 22:44:02 15/07/2012
  • 2

    @ DavoudTaghawi-Nejad hoặc hơn thế nữa ... Loại thập phân

    – Hoàng Mỹ Vân 11:01:40 08/04/2013
  • 13

    Có lẽ tôi đến quá muộn ở đây, nhưng tôi muốn hỏi, các nhà phát triển của Python đã giải quyết vấn đề này chưa? Bởi vì khi tôi làm tròn (13.949999999999999, 2), tôi chỉ đơn giản nhận được 13,95. Tôi đã thử nó trong Python 2.7.6, cũng như 3.4. Nó hoạt động. Không chắc chắn nếu 2.7 thậm chí đã có trong năm 2009. Có lẽ đó là một điều Python 2.5?

    – Lê Ðức Toản 05:51:49 22/09/2015
1.3k

Bạn đang gặp vấn đề cũ với các số dấu phẩy động mà tất cả các số không thể được biểu diễn. Dòng lệnh chỉ hiển thị cho bạn dạng dấu phẩy động đầy đủ từ bộ nhớ.

Trong dấu phẩy động, phiên bản tròn của bạn là cùng một số. Vì các máy tính là nhị phân, chúng lưu trữ các số dấu phẩy động dưới dạng một số nguyên và sau đó chia nó cho lũy thừa của hai nên 13,95 sẽ được biểu diễn theo kiểu tương tự như 125650429603636838 / (2 ** 53).

Số chính xác kép có độ chính xác 53 bit (16 chữ số) và phao thông thường có độ chính xác 24 bit (8 chữ số). Điểm nổi trong Python sử dụng độ chính xác kép để lưu trữ các giá trị.

Ví dụ,

  >>> 125650429603636838/(2**53)
  13.949999999999999

  >>> 234042163/(2**24)
  13.949999988079071

  >>> a=13.946
  >>> print(a)
  13.946
  >>> print("%.2f" % a)
  13.95
  >>> round(a,2)
  13.949999999999999
  >>> print("%.2f" % round(a,2))
  13.95
  >>> print("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Nếu bạn chỉ sau hai chữ số thập phân như bằng tiền thì bạn có một vài lựa chọn tốt hơn: 1) Sử dụng số nguyên và lưu trữ giá trị bằng xu, không phải đô la và sau đó chia cho 100 để chuyển đổi thành đô la. 2) Hoặc sử dụng số điểm cố định như số thập phân .

|
  • 1

    @Christian Có một sự khác biệt cơ bản giữa giá trị được lưu trữ và cách bạn hiển thị giá trị đó. Định dạng đầu ra sẽ cho phép bạn thêm phần đệm theo yêu cầu, cũng như thêm dấu tách dấu phẩy, v.v.

    – Vũ Như Thảo 11:03:35 08/04/2013
  • 1

    đáng nói là "%.2f" % round(a,2)bạn có thể đưa vào không chỉ trong printf, mà còn trong những thứ nhưstr()

    – Tạ Cao Phong 01:15:23 01/11/2013
  • 1

    Tại sao mọi người luôn giả định tiền tệ khi làm tròn điểm nổi? đôi khi bạn chỉ muốn làm việc với độ chính xác thấp hơn.

    – Ngô Thảo Vân 23:56:51 11/01/2014
  • 1

    @radtek: Bạn cần hiểu rằng giá trị nhị phân (loại float) chỉ là xấp xỉ gần nhất có sẵn của số thập phân (mà bạn quen thuộc với tư cách là một con người). Không có giá trị nhị phân (có thể biểu diễn chính xác) như 0,245. Nó chỉ đơn giản là không tồn tại, và về mặt toán học không thể tồn tại. Giá trị nhị phân gần nhất với 0,245 nhỏ hơn 0,245 một chút , do đó, tự nhiên nó làm tròn xuống. Tương tự như vậy, không có thứ gọi là 0,225 trong nhị phân, nhưng giá trị nhị phân gần nhất với 0,225 lớn hơn 0,225 một chút , do đó, tự nhiên nó làm tròn lên.

    – Dương Linh Hà 19:06:42 14/06/2016
  • 1

    @radtek: Bạn thực sự đã yêu cầu một lời giải thích. Giải pháp đơn giản nhất thực sự là sử dụng Decimal, và đó là một trong những giải pháp được trình bày trong câu trả lời này. Cách khác là chuyển đổi số lượng của bạn thành số nguyên và sử dụng số học số nguyên. Cả hai cách tiếp cận này cũng xuất hiện trong các câu trả lời và bình luận khác.

    – Bùi Minh Quang 19:45:26 15/06/2016
488

Có các đặc tả định dạng mới, Đặc tả định dạng chuỗi Mini-Language :

Bạn có thể làm tương tự như:

"{0:.2f}".format(13.949999999999999)

Lưu ý rằng ở trên trả về một chuỗi. Để có được như float, chỉ cần bọc với float(...):

float("{0:.2f}".format(13.949999999999999))

Lưu ý rằng gói float()không thay đổi bất cứ điều gì:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
|
211

Tích hợp round()hoạt động tốt trong Python 2.7 trở lên.

Thí dụ:

>>> round(14.22222223, 2)
14.22

Kiểm tra các tài liệu .

|
130

Tôi cảm thấy rằng cách tiếp cận đơn giản nhất là sử dụng format()chức năng.

Ví dụ:

a = 13.949999999999999
format(a, '.2f')

13.95

Điều này tạo ra một số float dưới dạng một chuỗi được làm tròn đến hai điểm thập phân.

|
89

Hầu hết các số không thể được biểu diễn chính xác trong phao. Nếu bạn muốn làm tròn số vì đó là những gì công thức toán học hoặc thuật toán của bạn yêu cầu, thì bạn muốn sử dụng vòng. Nếu bạn chỉ muốn giới hạn hiển thị ở một độ chính xác nhất định, thì thậm chí không sử dụng vòng và chỉ định dạng nó dưới dạng chuỗi đó. (Nếu bạn muốn hiển thị nó với một số phương pháp làm tròn thay thế và có hàng tấn, thì bạn cần kết hợp hai cách tiếp cận.)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

Và cuối cùng, mặc dù có lẽ quan trọng nhất, nếu bạn muốn toán chính xác thì bạn hoàn toàn không muốn nổi. Ví dụ thông thường là xử lý tiền và lưu trữ 'xu' dưới dạng số nguyên.

|
72

Sử dụng

print"{:.2f}".format(a)

thay vì

print"{0:.2f}".format(a)

Bởi vì cái sau có thể dẫn đến lỗi đầu ra khi cố gắng xuất nhiều biến (xem bình luận).

|
  • 1

    Thật vô nghĩa. Hai câu lệnh được đưa ra hoạt động giống hệt nhau trên Python 2.7 và chỉ có câu lệnh thứ hai là hợp lệ trên Python 2.6. (Cả hai câu lệnh đều không hợp lệ trong Python 3 hoặc Python <2.6.) Hình thức đầu tiên không có lợi thế ngoài sự ngắn gọn.

    – Tạ Ngọc Lai 17:56:25 28/01/2018
  • 1

    Ý tôi là, in "{0: .2f} {0: .2f}". Định dạng (a, b) sẽ dẫn đến nhầm lẫn trong đầu ra - nó sẽ xuất giá trị 'a' hai lần. Trong khi in định dạng "{:. 2f} {: .2f}". (A, b) sẽ tạo ra các giá trị 'a' và 'b'.

    – Trịnh Thiên Mai 17:30:34 01/02/2018
  • 1

    Đối với Python 3, bạn chỉ cần thêm dấu ngoặc in (...). Và trong tất cả những gì tôi viết là đúng.

    – Hồ Nguyên Nhân 17:31:47 01/02/2018
  • 1

    "Ý tôi là, in" {0: .2f} {0: .2f} ". Định dạng (a, b) sẽ dẫn đến nhầm lẫn trong đầu ra". À. Vâng, đó là một tuyên bố hoàn toàn khác! Có lẽ bạn nên chỉnh sửa câu trả lời của bạn? (Chẳng hạn "tăng lỗi" nghĩa là gì trong câu trả lời hiện tại? Bạn có thể đưa ra một ví dụ về trường hợp câu lệnh thứ hai đưa ra một ngoại lệ nhưng câu đầu tiên không?)

    – Tạ Nguyên Đức 18:34:04 01/02/2018
  • 1

    Bạn sẽ có sau khi in ("{0: .2f} {1: .2f}". Định dạng (a, b)) nếu bạn có hai biến

    – Hoàng Thành An 23:12:36 10/02/2018
69

Hãy thử mã dưới đây:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
|
  • 1

    Nhưng hãy cẩn thận, giá trị của a vẫn là một sự nổi không chính xác. Hãy xem tại đây - repl.it/LJs (Nhấp vào "Chạy phiên" ở đầu phần bên phải).

    – Tạ Ngọc Lai 19:23:42 02/10/2013
  • 1

    Nếu bạn đi theo cách tiếp cận này, bạn nên thêm 0,5 để thể hiện chính xác hơn. int (a * 100 + 0,5) / 100.0; Sử dụng math.ceil là một lựa chọn khác.

    – Trịnh Thiên Mai 00:11:20 08/11/2013
  • 1

    @ShashankSawant: Chà, vì một điều, câu trả lời như được trình bày không tròn, nó bị cắt cụt. Đề xuất thêm một nửa vào cuối sẽ làm tròn, nhưng sau đó không có lợi ích gì khi thực hiện việc này chỉ bằng cách sử dụng roundhàm ở vị trí đầu tiên. Đối với một điều khác, bởi vì giải pháp này vẫn sử dụng dấu phẩy động, vấn đề ban đầu của OP vẫn còn, ngay cả đối với phiên bản "đã sửa" của "giải pháp" này.

    – Hồ Nguyên Nhân 22:54:44 17/06/2014
  • 1

    -1, đây chỉ là một sự thực hiện lại không cần thiết của roundhàm (được sử dụng trong câu hỏi).

    – Tạ Nguyên Đức 22:55:54 12/09/2014
  • 1

    @interjay là cần thiết nếu round()không hoạt động như OP đã đề cập.

    – Hoàng Thành An 13:28:15 18/02/2015
51

Với Python <3 (ví dụ 2.6 hoặc 2.7), có hai cách để làm như vậy.

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

Nhưng lưu ý rằng đối với các phiên bản Python trên 3 (ví dụ: 3.2 hoặc 3.3), tùy chọn hai được ưu tiên .

Để biết thêm thông tin về tùy chọn hai, tôi đề nghị liên kết này về định dạng chuỗi từ tài liệu Python .

Và để biết thêm thông tin về tùy chọn một, liên kết này sẽ đủ và có thông tin về các cờ khác nhau .

Tham khảo: Chuyển đổi số dấu phẩy động thành độ chính xác nhất định, sau đó sao chép thành chuỗi

|
  • 1

    Làm thế nào để bạn đại diện cho một số nguyên? Nếu tôi sử dụng định dạng "{i3}". (Numvar), tôi sẽ gặp lỗi.

    – Đỗ Uy Phong 15:29:02 12/12/2013
  • 1

    Ý tôi là: Nếu numvar=12.456, sau đó "{:.2f}".format(numvar)mang lại 12.46nhưng "{:2i}".format(numvar)có lỗi và tôi đang mong đợi 12.

    – Bùi Thùy Uyên 15:47:04 12/12/2013
43

Bạn có thể sửa đổi định dạng đầu ra:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
|
36

TLDR;)

Vấn đề làm tròn số đầu vào / đầu ra đã được giải quyết dứt điểm bằng Python 2.7.03.1 .

Một số được làm tròn chính xác có thể được chuyển đổi qua lại một cách thuận nghịch:
str -> float() -> repr() -> float() ...hoặc Decimal -> float -> str -> Decimal
Loại thập phân không cần thiết cho việc lưu trữ nữa.

(Đương nhiên, có thể cần làm tròn kết quả của phép cộng hoặc trừ các số được làm tròn để loại bỏ các lỗi bit tích lũy cuối cùng. Một số học thập phân rõ ràng có thể vẫn tiện dụng, nhưng chuyển đổi thành chuỗi bằng str()(đó là làm tròn thành 12 chữ số hợp lệ ) là đủ tốt thường nếu không có độ chính xác cực cao hoặc không có số lượng cực lớn các phép toán số học liên tiếp được yêu cầu.)

Kiểm tra vô hạn:

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Tài liệu

Xem Ghi chú phát hành Python 2.7 - Ngôn ngữ khác Thay đổi đoạn thứ tư:

Chuyển đổi giữa các số dấu phẩy động và chuỗi hiện được làm tròn chính xác trên hầu hết các nền tảng. Các chuyển đổi này xảy ra ở nhiều nơi khác nhau: str () trên số float và số phức; các nhà xây dựng nổi và phức tạp; định dạng số; serializing và de-serializing phao nổi và các số phức bằng cách sử dụng marshal, picklejsonmodule; phân tích cú pháp float và chữ tưởng tượng trong mã Python; và chuyển đổi thập phân sang nổi.

Liên quan đến điều này, repr () của số dấu phẩy động x bây giờ trả về kết quả dựa trên chuỗi thập phân ngắn nhất được đảm bảo làm tròn trở lại x theo cách làm tròn chính xác (với chế độ làm tròn nửa tròn đến chẵn). Trước đây, nó đã đưa ra một chuỗi dựa trên làm tròn x đến 17 chữ số thập phân.

Vấn đề liên quan


Thông tin thêm: Định dạng floattrước Python 2.7 tương tự như hiện tại numpy.float64. Cả hai loại đều sử dụng cùng độ chính xác kép 64 bit của IEEE 754 với mantissa 52 bit. Một sự khác biệt lớn là np.float64.__repr__được định dạng thường xuyên với số thập phân quá mức để không mất bit nào, nhưng không tồn tại số IEEE 754 hợp lệ trong khoảng 13.949999999999999 và 13.950000000000001. Kết quả không đẹp và chuyển đổi repr(float(number_as_string))không thể đảo ngược với numpy. Mặt khác:float.__repr__được định dạng sao cho mọi chữ số đều quan trọng; trình tự là không có khoảng trống và chuyển đổi là đảo ngược. Đơn giản: Nếu bạn có thể có số numpy.float64, hãy chuyển đổi nó thành số float bình thường để được định dạng cho con người, không phải cho bộ xử lý số, nếu không thì không cần thêm gì với Python 2.7+.

|
  • 1

    Tại sao hạ cấp? Câu hỏi là về Python float(độ chính xác kép) và bình thường round, không phải về numpy.double và chuyển đổi thành chuỗi. Làm tròn Python đơn giản thực sự không thể được thực hiện tốt hơn trong Python 2.7. Hầu hết các câu trả lời đã được viết trước 2.7, nhưng chúng đã bị lỗi thời, mặc dù ban đầu chúng rất tốt. Đây là lý do của câu trả lời của tôi.

    – Đỗ Uy Phong 11:02:12 15/04/2016
  • 1

    53 bit khi bạn bao gồm "bit ẩn", ẩn 1, ngoại trừ trong "dòng chảy dần dần".

    – Bùi Thùy Uyên 04:16:45 17/05/2017
  • 1

    Đó không phải là lỗi của vòng, đó là lỗi hiển thị.

    – Dương Trí Hữu 04:22:36 17/05/2017
  • 1

    Vâng, nó được biết đến. Tuy nhiên, tôi bỏ lỡ một bối cảnh nếu bạn phản đối một cái gì đó trong Python 2.7 Phát hành ghi chú hoặc trong văn bản của tôi hoặc không có gì cả. Nó phức tạp hơn mục đích của câu hỏi này. Cũng cần nói thêm rằng cũng chuyển đổi từ chuỗi phao đã được cố định bằng Python 2.7 do làm tròn số lỗi trên chip nhất định 32-bit Intel và rằng "Vòng () chức năng cũng là tại làm tròn một cách chính xác." ( Ghi chú phát hành - 3.1 tính năng được nhập vào 2.7 ). Bạn có thể đồng ý không

    – Tạ Quốc Khánh 09:26:51 17/05/2017
  • 1

    Rất tiếc, đó là a*bvs b*a. Cảm ơn các liên kết - Nỗi nhớ.

    – Lý Thanh Trang 20:11:05 17/05/2017
28

Trong Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
|
  • 1

    Điều này không giúp được gì cả. outputcùng giá trị như a, vì vậy bạn cũng có thể đã viết print athay vì print outputở dòng cuối cùng.

    – Đỗ Uy Phong 06:12:57 26/05/2018
  • 1

    @MarkDickinson Bạn có thể vui lòng thử lại không. Bởi vì nó đang chạy như mong đợi trong trình biên dịch của tôi.

    – Bùi Thùy Uyên 08:07:52 23/09/2018
  • 1

    Bạn đang thiếu quan điểm của tôi. Có, mã của bạn in 13.95. Nhưng print avới giá trị cụ thể này a, trong Python 2.7, do đó, không thực sự rõ ràng điểm của bước định dạng là gì.

    – Dương Trí Hữu 11:13:12 23/09/2018
  • 1

    @MarkDickinson Tôi đã chỉnh sửa mã. Tôi đồng ý rằng 'in a' không in cùng giá trị với "đầu ra in". Nhưng nếu bạn so sánh "a == output", kết quả sẽ là "Sai" vì bước định dạng sẽ làm tròn giá trị nổi "a" thành hai điểm thập phân.

    – Tạ Quốc Khánh 11:45:02 23/09/2018
  • 1

    Bạn đã thực sự thử a == outputmã mà bạn hiển thị? Nó mang lại Truecho tôi, và tôi nghi ngờ nó cũng làm cho bạn.

    – Lý Thanh Trang 11:46:29 23/09/2018
20

Hướng dẫn Python có một phụ lục gọi là Số học dấu phẩy động: Các vấn đề và giới hạn . Đọc nó. Nó giải thích những gì đang xảy ra và tại sao Python lại làm tốt nhất. Nó thậm chí có một ví dụ phù hợp với bạn. Hãy để tôi trích dẫn một chút:

>>> 0.1
0.10000000000000001

bạn có thể bị cám dỗ sử dụng round() hàm để cắt nó trở lại một chữ số mà bạn mong đợi. Nhưng điều đó không tạo ra sự khác biệt:

>>> round(0.1, 1)
0.10000000000000001

Vấn đề là giá trị dấu phẩy động nhị phân được lưu trữ “0.1” đã là xấp xỉ nhị phân tốt nhất có thể có 1/10, do đó, cố gắng làm tròn lại một lần nữa không thể làm cho nó tốt hơn: nó đã tốt như nó đã đạt được.

Một hậu quả khác là vì 0.1 không chính xác 1/10, nên tổng cộng mười giá trị 0.1có thể không mang lại chính xác 1.0:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

Một giải pháp thay thế và giải pháp cho vấn đề của bạn sẽ là sử dụng decimalmô-đun.

|
19

Không ai ở đây dường như đã đề cập đến nó, vì vậy hãy để tôi đưa ra một ví dụ ở định dạng chuỗi f / chuỗi / mẫu của Python 3.6, mà tôi nghĩ là rất gọn gàng:

>>> f'{a:.2f}'

Nó cũng hoạt động tốt với các ví dụ dài hơn, với các toán tử và không cần parens:

>>> print(f'Completed in {time.time() - start:.2f}s')
|
12

Đó là làm chính xác những gì bạn bảo nó làm và đang hoạt động chính xác. Đọc thêm về nhầm lẫn dấu phẩy động và có thể thử các đối tượng thập phân thay thế.

|
11

Như @Matt đã chỉ ra, Python 3.6 cung cấp các chuỗi f và họ cũng có thể sử dụng các tham số lồng nhau :

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

cái nào sẽ hiển thị result: 2.35

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.