การจัดรูปแบบลอยโดยไม่มีศูนย์ต่อท้าย


181

ฉันจะจัดรูปแบบการลอยเพื่อไม่ให้มีศูนย์ต่อท้ายได้อย่างไร กล่าวอีกนัยหนึ่งฉันต้องการให้สตริงผลลัพธ์สั้นที่สุดเท่าที่จะทำได้

ตัวอย่างเช่น:

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

ตัวอย่างนั้นไม่สมเหตุสมผลเลย 3.14 == 3.140- พวกมันเป็นเลขทศนิยมเหมือนกัน สำหรับเรื่องนั้น 3.140000 นั้นเป็นเลขทศนิยมเหมือนกัน ไม่มีศูนย์ในตอนแรก
S.Lott

33
@ S.Lott - ฉันคิดว่าปัญหาคือการพิมพ์เลขทศนิยมโดยไม่ต้องมีศูนย์ต่อท้ายไม่เทียบเท่าสองตัวเลขจริง
pokstad

1
@pokstad: ในกรณีนี้ไม่มีศูนย์ "ฟุ่มเฟือย" %0.2fและ%0.3fเป็นสองรูปแบบที่จำเป็นในการสร้างตัวเลขสุดท้ายทางด้านซ้าย ใช้%0.2fสำหรับสร้างตัวเลขสองตัวสุดท้ายทางด้านขวา
S.Lott

6
3.0 -> "3"ยังคงเป็นกรณีการใช้งานที่ถูกต้อง print( '{:,g}'.format( X )ทำงานให้ฉันเพื่อส่งออก3ที่ไหนX = 6 / 2และเมื่อไหร่ที่X = 5 / 2ฉันได้ผลลัพธ์2.5ที่คาดหวัง
ShoeMaker

1
คำถามเก่า แต่ .. print("%s"%3.140)ให้สิ่งที่คุณต้องการ (ฉันเพิ่มคำตอบลงด้านล่าง ... )
drevicko

คำตอบ:


178

ฉันฉันจะทำ('%f' % x).rstrip('0').rstrip('.')- รับประกันการจัดรูปแบบจุดคงที่มากกว่าสัญกรณ์ทางวิทยาศาสตร์ ฯลฯ ฯลฯ ใช่ไม่ลื่นและสง่างามเหมือน%gแต่มันใช้งานได้ (และฉันไม่รู้ว่าจะบังคับ%gให้ใช้สัญลักษณ์ทางวิทยาศาสตร์ไม่ได้หรือไม่ -)


6
ปัญหาเดียวกับที่เป็น'%.2f' % -0.0001จะทำให้คุณมีและท้ายที่สุด-0.00 -0
Kos

3
@ alexanderlukanin13 เนื่องจากความแม่นยำเริ่มต้นคือ 6 ดูdocs.python.org/2/library/string.html : 'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6.คุณจะต้องใช้ '% 0.7f' ในโซลูชันด้านบน
Derenio

3
@derenio จุดที่ดี :-) ฉันสามารถเพิ่มความแม่นยำที่เพิ่มขึ้นข้างต้น'%0.15f'เป็นความคิดที่ไม่ดีเพราะสิ่งแปลก ๆเริ่มเกิดขึ้น
alexanderlukanin13 13

1
ในกรณีที่คุณอยู่ในช่วงกลางของสตริงอื่น ๆ : print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
ทนความผิดพลาด

1
@ Alex Martelli กำจัดrstripคำสั่งdouble ใช้เพียงแค่นี้แทนแถบจุด ( .) และศูนย์ต่อท้ายทั้งหมดในการดำเนินการ:('%f' % x).rstrip('.0')
Gabriel Staples

143

คุณสามารถใช้%gเพื่อให้บรรลุสิ่งนี้:

'%g'%(3.140)

หรือสำหรับ Python 2.6 หรือดีกว่า:

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

จากเอกสารสำหรับformat : gสาเหตุ (เหนือสิ่งอื่นใด)

ศูนย์ที่ไม่มีนัยสำคัญต่อท้าย [จะ] ถูกลบออกจากซิกนิฟิแคนด์และจุดทศนิยมจะถูกลบออกหากไม่มีตัวเลขที่เหลืออยู่ตามหลัง


28
โอ้เกือบ! บางครั้งมันจะจัดรูปแบบลอยในสัญกรณ์ทางวิทยาศาสตร์ ("2.342E + 09") - มันเป็นไปได้ที่จะปิดมันคือแสดงตัวเลขที่สำคัญทั้งหมดหรือไม่
TarGz

5
ทำไมต้องใช้'{0:...}'.format(value)เมื่อคุณสามารถใช้format(value, '...')? ที่หลีกเลี่ยงการแยกวิเคราะห์ตัวระบุรูปแบบจากสตริงแม่แบบที่ว่างเปล่า
Martijn Pieters

2
@MartijnPieters: ค่าใช้จ่ายต่ำสุดในการแยกวิเคราะห์ตัวระบุรูปแบบนั้นล้นมือด้วยค่าใช้จ่าย AFAICT อื่น ในทางปฏิบัติมาตรฐานในท้องถิ่นของฉันใน 3.6 (โดยมีการกำหนดขอบเขตการทำงานของ microbenchmark เพื่อรหัสจริงรูปแบบได้อย่างถูกต้อง) ได้format(v, '2.5f')ใช้เวลา ~ 10% '{:2.5f}'.format(v)นานกว่า แม้ว่ามันจะไม่เป็นเช่นนั้นฉันก็มักจะใช้strแบบฟอร์มวิธีการเพราะเมื่อฉันจำเป็นต้องปรับแต่งมันเพิ่มค่าเพิ่มเติมให้กับมัน ฯลฯ มีการเปลี่ยนแปลงน้อยลง แน่นอนว่า ณ 3.6 เรามี f-strings สำหรับวัตถุประสงค์ส่วนใหญ่ :-)
ShadowRanger

5
ใน Python 3.6 สิ่งนี้สามารถทำให้สั้นลงได้f"{var:g}"ว่าvarมีตัวแปรลอยอยู่ที่ไหน
TheGreatCabbage

12

ลองใช้วิธีที่ง่ายและมีประสิทธิภาพมากที่สุด วิธีการทำให้ปกติ ()ลบศูนย์ท้ายสุดทั้งหมดออก

from decimal import Decimal

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

ทำงานในหลาม 2และงูหลาม 3

- อัปเดต -

ปัญหาเดียวที่ @ BobStein-VisiBone ชี้ให้เห็นคือตัวเลขเช่น 10, 100, 1,000 ... จะแสดงเป็นเลขชี้กำลังแทน สามารถแก้ไขได้อย่างง่ายดายโดยใช้ฟังก์ชั่นต่อไปนี้แทน:

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
ยกเว้นDecimal('10.0').normalize()จะกลายเป็น'1E+1'
Bob Stein

11

หลังจากดูคำตอบของคำถามที่คล้ายกันหลายข้อดูเหมือนว่าจะเป็นทางออกที่ดีที่สุดสำหรับฉัน:

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

เหตุผลของฉัน:

%g ไม่กำจัดสัญกรณ์วิทยาศาสตร์

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

15 ตำแหน่งทศนิยมดูเหมือนจะหลีกเลี่ยงพฤติกรรมที่แปลกและมีความแม่นยำมากมายสำหรับความต้องการของฉัน

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

ฉันสามารถใช้format(inputValue, '.15f').แทนได้'%.15f' % inputValueแต่มันช้าลงเล็กน้อย (~ 30%)

ฉันสามารถใช้งานได้Decimal(inputValue).normalize()แต่ก็มีปัญหาเล็กน้อยเช่นกัน สำหรับหนึ่งมันช้ากว่ามาก (~ 11x) normalize()ฉันยังพบว่าแม้ว่ามันจะมีความแม่นยำมากสวยก็ยังคงได้รับความทุกข์จากการสูญเสียความแม่นยำเมื่อใช้

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

สิ่งสำคัญที่สุดคือฉันจะยังคงเปลี่ยนDecimalจากสิ่งfloatที่สามารถทำให้คุณจบลงด้วยสิ่งอื่นนอกเหนือจากหมายเลขที่คุณใส่ไว้ ฉันคิดว่าDecimalทำงานได้ดีที่สุดเมื่อเลขคณิตอยู่ในDecimalและDecimalเริ่มต้นได้ด้วยสตริง

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

ฉันแน่ใจว่าDecimal.normalize()สามารถแก้ไขปัญหาความแม่นยำของสิ่งที่จำเป็นโดยใช้การตั้งค่าบริบท แต่เมื่อพิจารณาความเร็วที่ช้าอยู่แล้วและไม่ต้องการความแม่นยำที่ไร้สาระและความจริงที่ว่าฉันยังคงแปลงจากการลอยและการสูญเสียความแม่นยำอยู่ดี ไม่คิดว่ามันคุ้มค่าที่จะติดตาม

ฉันไม่กังวลกับผลลัพธ์ "-0" ที่เป็นไปได้เนื่องจาก -0.0 เป็นเลขทศนิยมที่ถูกต้องและอาจเป็นเหตุการณ์ที่เกิดขึ้นได้ยาก แต่เนื่องจากคุณพูดถึงว่าคุณต้องการให้ผลลัพธ์สตริงสั้นที่สุดเท่าที่จะทำได้ สามารถใช้เงื่อนไขเพิ่มเติมได้เสมอด้วยค่าใช้จ่ายที่เพิ่มขึ้นเล็กน้อย

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

1
น่าเสียดายทำงานได้เฉพาะกับตัวเลขที่มีตัวเลขน้อยกว่าประมาณห้าหลักขึ้นไปทางซ้ายของจุดทศนิยม floatToString(12345.6)ผลตอบแทน'12345.600000000000364'เช่น การลด 15 ใน%.15fจำนวนที่น้อยลงจะแก้ได้ในตัวอย่างนี้ แต่ค่านั้นต้องลดลงมากขึ้นเรื่อย ๆ เมื่อจำนวนมีขนาดใหญ่ขึ้น มันสามารถคำนวณแบบไดนามิกโดยยึดตาม log-base-10 ของจำนวน แต่มันกลายเป็นสิ่งที่ซับซ้อนอย่างรวดเร็ว
JohnSpeeks

1
วิธีหนึ่งในการแก้ปัญหานั้นอาจเป็นการจำกัดความยาวของจำนวนเต็ม (แทนที่จะเป็นเพียงแค่ตัวเลขหลังจุดทศนิยม):result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
Timothy Smith

@ JohnSpeeks ฉันไม่แน่ใจว่าจะหลีกเลี่ยงได้ เป็นผลข้างเคียงของตัวเลขลอยตัวที่ไม่สามารถแสดงความถูกต้องได้หากต้องการตัวเลขเพิ่มเติมทางด้านซ้าย จากสิ่งที่ฉันสามารถบอกได้ว่าตัวเลขที่ออกมาเป็นสตริงนั้นเป็นตัวเลขเดียวกันกับที่เป็นทศนิยมหรืออย่างน้อยที่สุดก็เป็นตัวแทนที่ใกล้เคียงที่สุด >>>12345.600000000000364 == 12345.6 True
PolyMesh

ผมเขียนอีกวิธีการแก้ปัญหา
niitsuma

8

นี่เป็นวิธีแก้ปัญหาที่เหมาะกับฉัน มันเป็นความผสมผสานของการแก้ปัญหาโดยPolymeshและการใช้งานของใหม่ไวยากรณ์.format()

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

ผลผลิต :

3
3
3
3.1
3.14
3.14

สิ่งเดียวที่ผิดกับสิ่งนี้คือคุณต้องตั้งค่าตัวเลขทศนิยมที่สมเหตุสมผล ยิ่งคุณตั้งค่าไว้สูงเท่าใดคุณก็จะได้ตัวเลขที่แม่นยำยิ่งขึ้น แต่ถ้าคุณทำสิ่งนี้มากก็จะทำให้ประสิทธิภาพลดลง
beruic

1
การเพิ่มความคิดเห็นของ beruic สิ่งนี้ไม่ได้ผลสำหรับการลอยที่แม่นยำยิ่งขึ้น (เช่น3.141) เนื่องจาก.2fฮาร์ดโค้ด
TrebledJ

3

คุณสามารถใช้รูปแบบ () เพื่อทำสิ่งนี้:

format(3.140, '.10g') โดยที่ 10 คือความแม่นยำที่คุณต้องการ


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

คุณไม่หมายถึงint(a) if a % 1 else aเหรอ
beruic

เรียน Beruic คำตอบของคุณคือคำตอบที่เป็นลบ a if a % 1 else int(a)ถูกต้อง. คำถามต้องการผลลัพธ์เป็นสตริงดังนั้นฉันเพิ่งเพิ่มstr
Shameem

อ่าฉันเข้าใจแล้ว a % 1เป็นจริงเพราะมันไม่ใช่ศูนย์ a % 1 == 0ฉันโดยปริยายและการรับรู้ผิดว่ามันเป็น
beruic

2

ในขณะที่การจัดรูปแบบเป็นไปได้ว่าวิธี Pythonic ส่วนใหญ่นี่เป็นวิธีการแก้ปัญหาอื่นโดยใช้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"

จำนวนจะถูกแปลงเป็นสตริงซึ่งมีอักขระต่อท้ายที่ตรงกับเพรดิเคต fmtไม่จำเป็นต้องใช้คำจำกัดความของฟังก์ชั่นแต่จะใช้ที่นี่เพื่อทดสอบการยืนยันซึ่งทั้งหมดผ่าน หมายเหตุ: ใช้งานได้กับอินพุตสตริงและยอมรับเพรดิเคตเพิ่มเติม

ดูรายละเอียดเพิ่มเติมในห้องสมุดบุคคลที่สามmore_itertoolsนี้


1

หากคุณสามารถใช้ชีวิตด้วย 3 และ 3.0 ปรากฏเป็น "3.0" วิธีการง่ายๆที่ศูนย์ทางขวาจากการเป็นตัวแทนลอย:

print("%s"%3.140)

(ขอบคุณ @ellimilial สำหรับการชี้ข้อยกเว้น)


1
แต่print("%s"%3.0)ไม่
ellimilial

1

การใช้แพ็คเกจ QuantiPhy เป็นตัวเลือก QuantiPhy ปกติจะใช้เมื่อทำงานกับตัวเลขกับหน่วยและตัวคูณ SI SI แต่มีตัวเลือกการจัดรูปแบบตัวเลขที่หลากหลาย

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

และจะไม่ใช้สัญลักษณ์อิเล็กทรอนิกส์ในสถานการณ์นี้:

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

อีกทางเลือกหนึ่งที่คุณอาจชอบคือการใช้ตัวคูณสเกล SI กับหน่วย

    >>> 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 ต้องการลบศูนย์ superflouous และสร้างสตริงผลลัพธ์ให้สั้นที่สุด

ฉันพบว่าการจัดรูปแบบเลขชี้กำลัง% g ทำให้สตริงผลลัพธ์สั้นลงสำหรับค่าที่มากและน้อย ปัญหามาสำหรับค่าที่ไม่จำเป็นต้องมีเครื่องหมายเอ็กซ์โพเนนเชียลเช่น 128.0 ซึ่งไม่ใหญ่มากหรือเล็กมาก

ต่อไปนี้เป็นวิธีหนึ่งในการจัดรูปแบบตัวเลขเป็นสตริงแบบสั้นที่ใช้เครื่องหมายเอ็กซ์โพเนนเชียล% g เฉพาะเมื่อ Decimal.normalize สร้างสตริงที่ยาวเกินไป นี่อาจไม่ใช่วิธีที่เร็วที่สุด (เนื่องจากใช้ Decimal.n ปกติize)

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

สำหรับโฟลทคุณสามารถใช้สิ่งนี้:

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

ทดสอบมัน

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

สำหรับทศนิยมดูวิธีแก้ปัญหาที่นี่: https://stackoverflow.com/a/42668598/5917543



0

นี่คือคำตอบ:

import numpy

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

เอาท์พุท "3.14" และ "3"

trim='-' ลบทั้งศูนย์ต่อท้ายและทศนิยม


-1

ใช้% g ที่มีความกว้างเพียงพอที่ใหญ่เช่น '% .99g' มันจะพิมพ์ด้วยเครื่องหมายจุดคงที่สำหรับจำนวนมากพอสมควร

แก้ไข: มันไม่ทำงาน

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

1
.99คือความแม่นยำไม่ใช่ความกว้าง ค่อนข้างมีประโยชน์ แต่คุณไม่ต้องตั้งค่าความแม่นยำที่แท้จริงด้วยวิธีนี้ (นอกเหนือจากการตัดทอนด้วยตัวคุณเอง)
Kos

-1

คุณสามารถใช้max()สิ่งนี้:

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


1
คุณต้องพิจารณากรณีที่xเป็นลบ if x < 0: print(min(x), x) else : print(max(x), x)
ThunderPhoenix

วิธีที่มีประโยชน์เมื่อฉันต้องการทำ json stringify float 1.0 เปลี่ยนเป็น int 1 ดังนั้นมันจะทำงานเหมือนกับใน javascript
pingze

-3

คุณสามารถทำสิ่งนั้นได้ในแบบ pythonic ส่วนใหญ่เช่นนั้น:

python3:

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

คุณถูก. วิธีที่ง่ายที่สุดคือใช้ "{: g}". รูปแบบ (จำนวน)
Pyglouthon

-4

จัดการ% f และคุณควรใส่

% .2f

ที่: .2f == .00 ลอยตัว

ตัวอย่าง:

พิมพ์ "ราคา:% .2f"% prices [ผลิตภัณฑ์]

เอาท์พุท:

ราคา: 1.50


1
ชัดเจนว่านี่ไม่ใช่สิ่งที่คำถามต้องการ ต้องลงคะแนน
episodeyang
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.