ฉันต้องการa
ที่จะปัดเศษ13.95
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
ฟังก์ชั่นไม่ได้ทำงานในแบบที่ผมคาดไว้
ฉันต้องการa
ที่จะปัดเศษ13.95
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
ฟังก์ชั่นไม่ได้ทำงานในแบบที่ผมคาดไว้
คำตอบ:
คุณกำลังประสบปัญหาเก่ากับตัวเลขจุดลอยตัวที่ไม่สามารถแสดงตัวเลขทั้งหมดได้อย่างแม่นยำ บรรทัดคำสั่งกำลังแสดงรูปแบบจุดลอยตัวเต็มรูปแบบจากหน่วยความจำ
ด้วยการเป็นตัวแทนจุดลอยรุ่นกลมของคุณเป็นจำนวนเดียวกัน เนื่องจากคอมพิวเตอร์เป็นเลขฐานสองพวกเขาจะเก็บตัวเลขทศนิยมเป็นจำนวนเต็มแล้วหารด้วยกำลังสองดังนั้น 13.95 จะแสดงในรูปแบบที่คล้ายกันกับ 125650429603636838 / (2 ** 53)
ตัวเลขความแม่นยำสองเท่ามีความแม่นยำ 53 บิต (16 หลัก) และลอยปกติมีความแม่นยำ 24 บิต (8 หลัก) ชนิดลอยจุดในหลามใช้ความแม่นยำสองในการจัดเก็บค่า
ตัวอย่างเช่น,
>>> 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
หากคุณอยู่หลังตำแหน่งทศนิยมเพียงสองตำแหน่งเท่านั้น (เพื่อแสดงค่าสกุลเงิน) คุณจะมีตัวเลือกที่ดีกว่า:
"%.2f" % round(a,2)
คุณสามารถใส่ไม่เพียง แต่ใน printf แต่ยังในสิ่งต่าง ๆ เช่นstr()
float
) เป็นเพียงการประมาณที่ใกล้ที่สุดของเลขทศนิยม (ที่คุณคุ้นเคยกับมนุษย์) ไม่มีค่าเลขฐานสองดังกล่าว (สามารถแสดงได้อย่างละเอียด) เป็น 0.245 มันก็ไม่อยู่และคณิตศาสตร์ไม่สามารถมีชีวิตอยู่ ค่าไบนารีที่ใกล้เคียงกับ 0.245 น้อยกว่า 0.245 เล็กน้อยดังนั้นโดยทั่วไปแล้วจะปัดเศษลง ในทำนองเดียวกันไม่มีสิ่งเช่น 0.225 ในไบนารี แต่ค่าไบนารีซึ่งใกล้เคียงกับ 0.225 มากกว่า 0.225 เล็กน้อยดังนั้นโดยธรรมชาติมันจะปัดขึ้น
Decimal
และนั่นก็เป็นหนึ่งในโซลูชั่นที่นำเสนอในคำตอบนี้ อีกอันคือการแปลงปริมาณของคุณเป็นจำนวนเต็มและใช้เลขคณิตเลขจำนวนเต็ม ทั้งสองวิธีนี้ยังปรากฏในคำตอบและความคิดเห็นอื่น ๆ
มีข้อกำหนดรูปแบบใหม่ข้อกำหนดรูปแบบสตริงเป็นภาษามินิ :
คุณสามารถทำเช่นเดียวกับ:
"{:.2f}".format(13.949999999999999)
หมายเหตุ 1:ข้างต้นส่งกลับสตริง หากต้องการลอยตัวให้ห่อด้วยfloat(...)
:
float("{:.2f}".format(13.949999999999999))
หมายเหตุ 2: การหุ้มด้วยfloat()
จะไม่เปลี่ยนแปลงอะไรเลย:
>>> 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)
พิมพ์'1,333.95'
ได้
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
built-in ใช้round()
งานได้ดีใน Python 2.7 หรือใหม่กว่า
ตัวอย่าง:
>>> round(14.22222223, 2)
14.22
round(2.16, 1)
ให้2.2
เหตุผลว่าทำไมไพ ธ อนจึงเสนอ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.
ฉันรู้สึกว่าวิธีที่ง่ายที่สุดคือการใช้format()
ฟังก์ชั่น
ตัวอย่างเช่น:
a = 13.949999999999999
format(a, '.2f')
13.95
สิ่งนี้สร้างจำนวนลอยเป็นสตริงที่ปัดเศษเป็นทศนิยมสองตำแหน่ง
ใช้
print"{:.2f}".format(a)
แทน
print"{0:.2f}".format(a)
เพราะหลังอาจนำไปสู่ข้อผิดพลาดการส่งออกเมื่อพยายามที่จะส่งออกหลายตัวแปร (ดูความคิดเห็น)
ตัวเลขส่วนใหญ่ไม่สามารถแสดงด้วยการลอยได้ ถ้าคุณต้องการปัดเศษตัวเลขเพราะนั่นคือสิ่งที่สูตรทางคณิตศาสตร์หรืออัลกอริทึมของคุณต้องการดังนั้นคุณต้องการใช้การปัดเศษ หากคุณต้องการ จำกัด การแสดงผลให้มีความแม่นยำแน่นอนอย่าใช้รอบและจัดรูปแบบเป็นสตริงนั้น (หากคุณต้องการแสดงด้วยวิธีการปัดเศษแบบอื่นและมีตันคุณต้องผสมสองวิธีเข้าด้วยกัน)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
และท้ายที่สุดแม้ว่าที่สำคัญที่สุดคือถ้าคุณต้องการคณิตศาสตร์ที่แน่นอนคุณก็ไม่ต้องการลอยเลย ตัวอย่างปกติคือการจัดการกับเงินและเพื่อเก็บ 'เซ็นต์' เป็นจำนวนเต็ม
ลองรหัสด้านล่าง:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
ฟังก์ชันในตอนแรก อีกวิธีหนึ่งเนื่องจากโซลูชันนี้ยังคงใช้จุดลอยตัวปัญหาเดิมของ OP ยังคงอยู่แม้ว่าจะเป็น "การแก้ไข" ของโซลูชัน "นี้"
round
ฟังก์ชันมาใช้ใหม่โดยไม่จำเป็น(ซึ่งถูกใช้ในคำถาม)
round()
ไม่ได้ตามที่ OP กล่าวถึง
ปัญหาการปัดเศษเข้า / ส่งออกได้รับการแก้ไขได้อย่างแน่นอนโดย Python 2.7.0และ3.1
ตัวเลขที่ถูกปัดเศษอย่างถูกต้องสามารถแปลงกลับไปกลับมา
str -> float() -> repr() -> float() ...
หรือDecimal -> float -> str -> Decimal
ประเภททศนิยมไม่จำเป็นสำหรับการจัดเก็บอีกต่อไป
(ธรรมชาติก็สามารถมีความจำเป็นที่จะรอบผลมาจากการเพิ่มหรือลบหมายเลขที่โค้งมนเพื่อขจัดข้อผิดพลาดบิตสุดท้ายสะสม. เลขคณิตสิบอย่างชัดเจนสามารถยังคงมีประโยชน์ แต่การแปลงสตริงโดยstr()
(นั่นคือมีการปัดเศษถึง 12 ตัวเลขที่ถูกต้อง ) ปกติแล้วจะดีพอหากไม่ต้องการความแม่นยำสูงหรือไม่ต้องใช้การคำนวณทางคณิตศาสตร์จำนวนมาก ๆ )
การทดสอบที่ไม่มีที่สิ้นสุด :
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+ :-)
ดูบันทึกประจำรุ่น Python 2.7 - ภาษาอื่นเปลี่ยนย่อหน้าที่สี่:
การแปลงระหว่างตัวเลขทศนิยมและสตริงนั้นถูกปัดเศษอย่างถูกต้องบนแพลตฟอร์มส่วนใหญ่ การแปลงเหล่านี้เกิดขึ้นในหลาย ๆ แห่ง: str () บนจำนวนลอยและจำนวนเชิงซ้อน ตัวสร้างลอยและซับซ้อน การจัดรูปแบบตัวเลข การทำให้เป็นอนุกรมและการทำให้เป็นอนุกรมลอยและหมายเลขที่ซับซ้อนโดยใช้
marshal
,pickle
และjson
โมดูล; การแยกลอยและตัวอักษรในจินตนาการในรหัสหลาม; และการแปลงทศนิยมเป็นทศนิยมเกี่ยวข้องกับสิ่งนี้การrepr ()ของตัวเลข floating-x จะส่งคืนผลลัพธ์โดยอิงจากสตริงทศนิยมที่สั้นที่สุดที่รับประกันว่าจะปัดกลับเป็น xภายใต้การปัดเศษที่ถูกต้อง (พร้อมโหมดการปัดเศษ ก่อนหน้านี้มันให้สตริงตามการปัดเศษ x ถึง 17 หลักทศนิยม
ข้อมูลเพิ่มเติม:จัดรูปแบบของfloat
ก่อนหลาม 2.7 numpy.float64
ใกล้เคียงกับปัจจุบัน ทั้งสองชนิดใช้ความแม่นยำสองเท่า64 บิตIEEE 754 ที่มี 52 mantissa ความแตกต่างใหญ่คือnp.float64.__repr__
มีการจัดรูปแบบบ่อยครั้งด้วยจำนวนทศนิยมที่มากเกินไปเพื่อไม่ให้บิตหายไปได้ แต่ไม่มีหมายเลข IEEE 754 ที่ถูกต้องอยู่ระหว่าง 13.94999999999999999 และ 13.950000000000001 ผลลัพธ์ไม่ดีและการแปลงrepr(float(number_as_string))
ไม่สามารถย้อนกลับได้ด้วย numpy ในทางกลับกัน:float.__repr__
มีการจัดรูปแบบเพื่อให้ทุกหลักมีความสำคัญ; ลำดับนั้นไม่มีช่องว่างและการแปลงกลับได้ ง่ายๆ: ถ้าคุณอาจมีหมายเลข numpy.float64 ให้แปลงเป็นทศนิยมปกติเพื่อจัดรูปแบบสำหรับมนุษย์ไม่ใช่สำหรับโปรเซสเซอร์ที่เป็นตัวเลขมิฉะนั้นไม่จำเป็นต้องใช้ Python 2.7+ อีกต่อไป
float
(ความแม่นยำสองเท่า) และปกติround
ไม่ใช่เกี่ยวกับ numpy.double และการแปลงเป็นสตริง การปัดเศษ Python ธรรมดาไม่สามารถทำได้ดีกว่าใน Python 2.7 คำตอบส่วนใหญ่เขียนไว้ก่อน 2.7 แต่พวกเขาล้าสมัยแม้ว่าพวกเขาจะดีมากในตอนแรก นี่คือเหตุผลของคำตอบของฉัน
1
ยกเว้นในระหว่าง "ค่อยเป็นค่อยไปอันเดอร์โฟลว์"
a*b
b*a
ขอบคุณสำหรับลิงค์ - Nostalgia
ด้วย Python <3 (เช่น 2.6 หรือ 2.7) มีสองวิธีในการทำเช่นนั้น
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
แต่ทราบว่าสำหรับงูหลามรุ่นข้างต้น 3 (เช่น 3.2 หรือ 3.3) ตัวเลือกที่สองคือการแนะนำ
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกที่สองผมขอแนะนำลิงค์นี้ในการจัดรูปแบบสตริงจากเอกสารหลาม
และสำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวเลือกหนึ่งที่ลิงค์นี้จะพอเพียงและมีข้อมูลเกี่ยวกับธงต่างๆ
การอ้างอิง: แปลงหมายเลขทศนิยมเป็นความแม่นยำแน่นอนแล้วคัดลอกไปยังสตริง
numvar=12.456
แล้ว"{:.2f}".format(numvar)
ผลตอบแทนถัวเฉลี่ย12.46
แต่ให้ข้อผิดพลาดและฉันคาดหวัง"{:2i}".format(numvar)
12
คุณสามารถปรับเปลี่ยนรูปแบบผลลัพธ์:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
ดูเหมือนจะไม่มีใครพูดถึงเลยดังนั้นขอยกตัวอย่างในรูปแบบ f-string / template-string ของ Python 3.6 ซึ่งฉันคิดว่าเรียบร้อยดี:
>>> f'{a:.2f}'
มันทำงานได้ดีกับตัวอย่างที่ยาวขึ้นด้วยตัวดำเนินการและไม่ต้องการ parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
คุณสามารถใช้ตัวดำเนินการรูปแบบสำหรับปัดเศษค่าทศนิยมสูงสุด 2 ตำแหน่งในไพ ธ อน:
print(format(14.4499923, '.2f')) // output is 14.45
ใน Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
มีเดียวกันแน่นอนคุ้มค่าเป็นa
ดังนั้นคุณอาจรวมทั้งได้เขียนprint a
แทนprint output
ในบรรทัดสุดท้าย
13.95
ออกมา แต่print a
สำหรับค่าเฉพาะนี้a
ใน Python 2.7 ดังนั้นจึงไม่ชัดเจนว่าจุดของขั้นตอนการจัดรูปแบบคืออะไร
a == output
รหัสที่คุณแสดงหรือไม่ มันให้True
สำหรับฉันและฉันสงสัยว่ามันจะทำเพื่อคุณเช่นกัน
งูหลามกวดวิชามีภาคผนวกที่เรียกว่าFloating Point เลขคณิต: ปัญหาและข้อ จำกัด อ่านมัน มันอธิบายสิ่งที่เกิดขึ้นและทำไม Python จึงพยายามทำให้ดีที่สุด มันยังมีตัวอย่างที่ตรงกับคุณ ให้ฉันพูดเล็กน้อย:
>>> 0.1 0.10000000000000001
คุณอาจถูกล่อลวงให้ใช้
round()
ฟังก์ชั่นเพื่อตัดกลับเป็นตัวเลขหลักเดียวที่คุณคาดหวัง แต่นั่นก็ไม่ได้ทำให้แตกต่าง:>>> round(0.1, 1) 0.10000000000000001
ปัญหาคือค่าเลขฐานสองแบบลอยตัวที่เก็บไว้
“0.1”
นั้นเป็นค่าเลขฐานสองที่ดีที่สุดเท่าที่จะเป็นไปได้1/10
ดังนั้นการพยายามปัดมันอีกครั้งไม่สามารถทำให้ดีขึ้นได้: มันดีพอ ๆ กับที่ได้รับผลที่ตามมาอีกประการหนึ่งคือเนื่องจาก
0.1
ไม่แน่นอนการ1/10
รวมสิบค่าของ0.1
อาจไม่ได้ผลอย่างแน่นอน1.0
เช่น:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
ทางเลือกหนึ่งและวิธีแก้ปัญหาของคุณคือการใช้decimal
โมดูล
ในฐานะที่เป็น @Matt ชี้ให้เห็นPython 3.6 ให้สตริง fและพวกเขายังสามารถใช้พารามิเตอร์ที่ซ้อนกัน :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
ซึ่งจะแสดง result: 2.35
มันทำสิ่งที่คุณบอกให้ทำและทำงานอย่างถูกต้อง อ่านเพิ่มเติมเกี่ยวกับความสับสนของทศนิยมและอาจลองใช้วัตถุทศนิยมแทน
ใช้การรวมกันของวัตถุทศนิยมและวิธีการกลม ()
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')
สำหรับการแก้ไขจุดลอยตัวในภาษาแบบไดนามิกเช่น Python และ JavaScript ฉันใช้เทคนิคนี้
# 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
คุณยังสามารถใช้ทศนิยมได้ดังต่อไปนี้:
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
ใช้ได้กับขอบเขตของฟังก์ชั่นหรือสถานที่ทั้งหมดหรือไม่
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)
ผล:
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'
orig_float = 232569 / 16000.0
14.5355625
short_float = float("{:.2f}".format(orig_float))
14.54
ฟังก์ชั่นแลมบ์ดาเป็นเช่นนี้:
arred = lambda x,n : x*(10**n)//1/(10**n)
วิธีนี้คุณสามารถทำได้:
arred(3.141591657,2)
และรับ
3.14
ง่ายเหมือน 1,2,3:
ใช้โมดูลทศนิยมสำหรับการคำนวณทศนิยมทศนิยมอย่างรวดเร็วอย่างถูกต้อง:
d = ทศนิยม (10000000.0000009)
เพื่อให้บรรลุการปัดเศษ:
d.quantize(Decimal('0.01'))
จะได้ผลลัพธ์ด้วย Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
หรือ
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: คำติชมของคนอื่น ๆ : การจัดรูปแบบไม่ได้ปัดเศษ
วิธีปัดเศษตัวเลขเป็นความละเอียดวิธีที่ดีที่สุดคือสิ่งต่อไปนี้ซึ่งสามารถทำงานได้กับความละเอียดใด ๆ (0.01 สำหรับสองทศนิยมหรือขั้นตอนอื่น ๆ ):
>>> 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
ความถูกต้อง / ความแม่นยำ ดังนั้นจึงจำเป็นต้องกำหนดว่าเป็น int ก่อนการคูณด้วยความละเอียด ฉันอัปเดตรหัสแล้ว ขอบคุณสำหรับสิ่งนั้น!
numpy.float64
ผลมาจากการ np.round หรือเพียงเพื่อการใช้งานfloat
round(value, 2)
ไม่มีหมายเลข IEEE 754 ที่ถูกต้องอยู่ระหว่าง 13.949999999999999 (= 1395 / 100. ) และ 3.950000000000001 (= 1395 * .01) ทำไมคุณคิดว่าวิธีการของคุณดีที่สุด ค่าดั้งเดิม 13.94999999999999999289 (= value = round (value, 2)) มีความแม่นยำมากกว่าของคุณ 13.95000000000000178 (พิมพ์โดย np.float96) ข้อมูลเพิ่มเติมสำหรับ numpy ตอนนี้เพิ่มลงในคำตอบของฉันที่คุณอาจ downvoted โดยไม่ได้ตั้งใจ เดิมทีมันไม่ได้เกี่ยวกับอะไร
int
ใช้float
สำหรับตัวอย่าง @szeitlin ขอบคุณสำหรับความคิดเห็นเพิ่มเติม (ขออภัย แต่ฉันไม่ได้ลงคะแนนให้คุณ)
lambda x, n: int (x * 10 n + .5) / 10 n ทำงานให้ฉันหลายปีในหลายภาษา
วิธีที่ฉันใช้คือการแบ่งสตริง มันค่อนข้างง่ายและรวดเร็ว
ก่อนอื่นให้แปลงทศนิยมเป็นสตริงเลือกความยาวที่คุณต้องการ
float = str(float)[:5]
ในบรรทัดเดียวด้านบนเราได้แปลงค่าเป็นสตริงจากนั้นเก็บสตริงเป็นตัวเลขหรือตัวอักษรสี่ตัวแรกเท่านั้น (รวมอยู่ด้วย)
หวังว่าจะช่วย!