Tôi muốn a
được làm tròn đến 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Các round
chức năng không hoạt động theo cách tôi mong đợi.
Tôi muốn a
được làm tròn đến 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Các round
chức năng không hoạt động theo cách tôi mong đợi.
Câu trả lời:
Bạn đang gặp vấn đề cũ với các số dấu phẩy động mà không phải tất cả các số đều có thể được biểu diễn chính xác. Dòng lệnh chỉ hiển thị cho bạn dạng dấu phẩy động đầy đủ từ bộ nhớ.
Với biểu diễn 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ố). Kiểu dấu phẩy động 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("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Nếu bạn chỉ sau hai vị trí thập phân (để hiển thị giá trị tiền tệ chẳng hạn), thì bạn có một vài lựa chọn tốt hơn:
"%.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()
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.
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.
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ư:
"{:.2f}".format(13.949999999999999)
Lưu ý 1: ở trên trả về một chuỗi. Để có được như float, chỉ cần bọc với float(...)
:
float("{:.2f}".format(13.949999999999999))
Lưu ý 2: gói float()
không thay đổi bất cứ điều gì:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{0:,.2f}'.format(1333.949999999)
in '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
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 .
round(2.16, 1)
đưa ra 2.2
lý do tại sao trăn chỉ cung cấp một truncate
func
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
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.
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).
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.
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
round
hà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.
round
hàm (được sử dụng trong câu hỏi).
round()
không hoạt động như OP đã đề cập.
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.0 và 3.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, nó có thể là cần thiết để làm tròn kết quả của bổ sung, trừ các số tròn để loại bỏ các lỗi bit cuối cùng tích lũy được. Một số thập phân số học rõ ràng có thể vẫn tiện dụng, nhưng một chuyển đổi chuỗi bằng str()
(có nghĩa là với làm tròn đến 12 chữ số có giá trị ) 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+ :-)
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
,pickle
vàjson
module; 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.
Thông tin thêm: Định dạng float
trướ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+.
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.
1
, ngoại trừ trong "dòng chảy dần dần".
a*b
vs b*a
. Cảm ơn các liên kết - Nỗi nhớ.
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 một độ chính xác nhất định, sau đó sao chép thành chuỗi
numvar=12.456
, sau đó "{:.2f}".format(numvar)
mang lại 12.46
nhưng "{:2i}".format(numvar)
có lỗi và tôi đang mong đợi 12
.
Bạn có thể sửa đổi định dạng đầu ra:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
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')
Bạn có thể sử dụng toán tử định dạng để làm tròn giá trị lên tới 2 vị trí thập phân trong python:
print(format(14.4499923, '.2f')) // output is 14.45
Trong Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
có cùng giá trị như a
, vì vậy bạn cũng có thể đã viết print a
thay vì print output
ở dòng cuối cùng.
13.95
. Nhưng print a
vớ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ì.
a == output
mã mà bạn hiển thị? Nó mang lại True
cho tôi, và tôi nghi ngờ nó cũng làm cho bạn.
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ác1/10
, nên tổng cộng mười giá trị0.1
có thể không mang lại chính xác1.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 các vấn đề của bạn sẽ là sử dụng decimal
mô-đun.
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
Đó 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ế.
Sử dụng kết hợp đối tượng Decimal và phương thức round ().
Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
Để sửa điểm nổi trong các ngôn ngữ động kiểu như Python và JavaScript, tôi sử dụng kỹ thuật này
# For example:
a = 70000
b = 0.14
c = a * b
print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980
Bạn cũng có thể sử dụng Thập phân như sau:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')
getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
getcontext().prec = 6
chỉ hoạt động cho phạm vi của chức năng hoặc tất cả các nơi?
from decimal import Decimal
def round_float(v, ndigits=2, rt_str=False):
d = Decimal(v)
v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
if rt_str:
return v_str
return Decimal(v_str)
Các kết quả:
Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
Điều gì về một chức năng lambda như thế này:
arred = lambda x,n : x*(10**n)//1/(10**n)
Bằng cách này bạn có thể làm:
arred(3.141591657,2)
và lấy
3.14
Nó đơn giản như 1,2,3:
sử dụng mô-đun thập phân cho số học dấu phẩy động thập phân được làm tròn chính xác nhanh:
d = Số thập phân (10000000.0000009)
để đạt được làm tròn:
d.quantize(Decimal('0.01'))
sẽ có kết quả với Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
HOẶC LÀ
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: phê bình của người khác: định dạng không làm tròn.
Để làm tròn số thành độ phân giải, cách tốt nhất là cách sau, có thể hoạt động với bất kỳ độ phân giải nào (0,01 cho hai số thập phân hoặc thậm chí các bước khác):
>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95
>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
numpy.round
chính xác / chính xác. Vì vậy, nó đòi hỏi phải xác định nó là int trước khi nhân với độ phân giải. Tôi đã cập nhật mã. Cảm ơn vì điều đó!
numpy.float64
kết quả của np.round thành float
hoặc đơn giản là sử dụng round(value, 2)
. Không có số IEEE 754 hợp lệ tồn tại trong khoảng 13.949999999999999 (= 1395 / 100.) và 3.950000000000001 (= 1395 * .01). Tại sao bạn nghĩ rằng phương pháp của bạn là tốt nhất? Giá trị ban đầu 13.949999999999999289 (= value = round (value, 2)) thậm chí còn chính xác hơn 13.95000000000000178 của bạn (được in bởi np.float96). Thêm thông tin cho numpy bây giờ được thêm vào câu trả lời của tôi rằng bạn có thể bị hạ thấp do nhầm lẫn. Đó không phải là về numpy ban đầu.
int
bạn cũng có thể sử dụng float
cho ví dụ @szeitlin. Cảm ơn bạn đã bình luận thêm của bạn. (Xin lỗi nhưng tôi không
Phương pháp tôi sử dụng là cắt chuỗi. Nó tương đối nhanh chóng và đơn giản.
Đầu tiên, chuyển đổi float thành một chuỗi, chọn độ dài bạn muốn.
float = str(float)[:5]
Trong một dòng trên, chúng tôi đã chuyển đổi giá trị thành một chuỗi, sau đó chỉ giữ chuỗi đó thành bốn chữ số hoặc ký tự đầu tiên (bao gồm).
Mong rằng sẽ giúp!