การตัดทอนลอยใน Python


110

ฉันต้องการลบตัวเลขออกจากทศนิยมเพื่อให้มีจำนวนหลักคงที่หลังจุดเช่น:

1.923328437452 -> 1.923

ฉันต้องการส่งออกเป็นสตริงไปยังฟังก์ชันอื่นไม่ใช่พิมพ์

นอกจากนี้ฉันต้องการละเว้นตัวเลขที่หายไปไม่ใช่ปัดเศษ


4
-1.233 ควรถูกตัดให้เหลือ -1.23 หรือ -1.24?
Antony Hatchkins

คำตอบ:


117

ขั้นแรกฟังก์ชั่นสำหรับผู้ที่ต้องการเพียงแค่คัดลอกและวางโค้ด:

def truncate(f, n):
    '''Truncates/pads a float f to n decimal places without rounding'''
    s = '{}'.format(f)
    if 'e' in s or 'E' in s:
        return '{0:.{1}f}'.format(f, n)
    i, p, d = s.partition('.')
    return '.'.join([i, (d+'0'*n)[:n]])

ใช้ได้ใน Python 2.7 และ 3.1+ สำหรับเวอร์ชันเก่าจะไม่สามารถรับเอฟเฟกต์ "การปัดเศษอัจฉริยะ" แบบเดียวกันได้ (อย่างน้อยก็ไม่ใช่โดยไม่มีรหัสที่ซับซ้อนมากนัก) แต่การปัดเศษเป็นทศนิยม 12 ตำแหน่งก่อนการตัดทอนจะใช้เวลาส่วนใหญ่:

def truncate(f, n):
    '''Truncates/pads a float f to n decimal places without rounding'''
    s = '%.12f' % f
    i, p, d = s.partition('.')
    return '.'.join([i, (d+'0'*n)[:n]])

คำอธิบาย

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

i, p, d = s.partition('.')
'.'.join([i, (d+'0'*n)[:n]])

หรือdecimalโมดูล

str(Decimal(s).quantize(Decimal((0, (1,), -n)), rounding=ROUND_DOWN))

ขั้นตอนแรกการแปลงเป็นสตริงนั้นค่อนข้างยากเนื่องจากมีลิเทอรัลจุดลอยตัวบางคู่ (เช่นสิ่งที่คุณเขียนในซอร์สโค้ด) ซึ่งทั้งคู่ให้การแทนค่าไบนารีเหมือนกัน แต่ก็ควรจะถูกตัดทอนให้แตกต่างกัน ตัวอย่างเช่นพิจารณา 0.3 และ 0.29999999999999998 หากคุณเขียน0.3ในโปรแกรม Python คอมไพลเลอร์จะเข้ารหัสโดยใช้รูปแบบทศนิยมของ IEEE ในลำดับของบิต (สมมติว่าเป็นทศนิยม 64 บิต)

0011111111010011001100110011001100110011001100110011001100110011

นี่คือค่าที่ใกล้เคียงที่สุดกับ 0.3 ที่สามารถแสดงเป็นค่าลอยของ IEEE ได้อย่างแม่นยำ แต่ถ้าคุณเขียน0.29999999999999998ด้วยโปรแกรม Python คอมไพลเลอร์จะแปลเป็นค่าเดียวกันทั้งหมด ในกรณีหนึ่งคุณตั้งใจให้มันถูกตัดทอน (เป็นหนึ่งหลัก) ใน0.3ขณะที่อีกกรณีหนึ่งคุณหมายถึงมันถูกตัดให้สั้นลง0.2แต่ Python สามารถให้คำตอบได้เพียงคำตอบเดียว นี่เป็นข้อ จำกัด พื้นฐานของ Python หรือภาษาโปรแกรมใด ๆ โดยไม่ต้องใช้การประเมิน ฟังก์ชันการตัดทอนจะเข้าถึงเฉพาะค่าไบนารีที่จัดเก็บไว้ในหน่วยความจำของคอมพิวเตอร์ไม่ใช่สตริงที่คุณพิมพ์ลงในซอร์สโค้ดจริงๆ 1

หากคุณถอดรหัสลำดับของบิตกลับเป็นเลขฐานสิบอีกครั้งโดยใช้รูปแบบทศนิยม 64 บิตของ IEEE คุณจะได้รับ

0.2999999999999999888977697537484345957637...

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

เป็นเรื่องยากมากที่จะทำงานกับค่าทศนิยมที่ใกล้เคียงกับตัวเลขกลมๆ แต่ตั้งใจจะไม่เท่ากับจำนวนรอบนั้น ดังนั้นเมื่อตัดทอนจึงเป็นเรื่องที่สมเหตุสมผลที่จะเลือกการแทนค่าทศนิยม "ที่ดีที่สุด" จากทั้งหมดที่สามารถสอดคล้องกับค่าในหน่วยความจำ Python 2.7 ขึ้นไป (แต่ไม่ใช่ 3.0) มีอัลกอริทึมที่ซับซ้อนเพื่อทำสิ่งนั้นซึ่งเราสามารถเข้าถึงได้ผ่านการดำเนินการจัดรูปแบบสตริงเริ่มต้น

'{}'.format(f)

ข้อแม้เดียวคือสิ่งนี้ทำหน้าที่เหมือนgข้อกำหนดรูปแบบในแง่ที่ใช้สัญกรณ์เอกซ์โพเนนเชียล ( 1.23e+4) ถ้าตัวเลขมีขนาดใหญ่หรือเล็กพอ ดังนั้นวิธีการต้องจับกรณีนี้และจัดการมันแตกต่างกัน มีบางกรณีที่การใช้fข้อกำหนดรูปแบบแทนทำให้เกิดปัญหาเช่นการพยายามตัดทอน3e-10ความแม่นยำให้เหลือ 28 หลัก (ซึ่งเกิดขึ้น0.0000000002999999999999999980) และฉันยังไม่แน่ใจว่าจะจัดการกับสิ่งเหล่านั้นได้ดีที่สุดอย่างไร

หากคุณกำลังทำงานกับfloats ที่มีค่าใกล้เคียงกับตัวเลขกลมๆมาก แต่ไม่ได้ตั้งใจให้เท่ากับจำนวนนั้น (เช่น 0.29999999999999998 หรือ 99.959999999999994) สิ่งนี้จะทำให้เกิดผลบวกลวงกล่าวคือจะปัดเศษตัวเลขที่คุณไม่ต้องการให้ปัดเศษ ในกรณีนี้วิธีแก้ปัญหาคือการระบุความแม่นยำคงที่

'{0:.{1}f}'.format(f, sys.float_info.dig + n + 2)

จำนวนหลักของความแม่นยำที่จะใช้ในที่นี้ไม่สำคัญนักเพียง แต่ต้องมีขนาดใหญ่พอที่จะทำให้แน่ใจได้ว่าการปัดเศษใด ๆ ที่ดำเนินการในการแปลงสตริงจะไม่ "ชน" ค่าเป็นการแทนทศนิยมที่ดี ฉันคิดว่าsys.float_info.dig + n + 2อาจจะเพียงพอในทุกกรณี แต่ถ้าไม่เช่นนั้น2อาจจะต้องเพิ่มขึ้นและไม่เจ็บที่จะทำเช่นนั้น

ใน Python เวอร์ชันก่อนหน้า (มากถึง 2.6 หรือ 3.0) การจัดรูปแบบตัวเลขทศนิยมนั้นค่อนข้างหยาบกว่ามากและมักจะสร้างสิ่งต่างๆเช่น

>>> 1.1
1.1000000000000001

หากนี่คือสถานการณ์ของคุณหากคุณไม่ต้องการใช้การแทนค่าทศนิยม "nice" สำหรับการตัดทอนสิ่งที่คุณทำได้ (เท่าที่ฉันรู้) คือเลือกตัวเลขจำนวนหนึ่งน้อยกว่าความแม่นยำเต็มที่แทนค่าได้ด้วย a floatและปัดเศษ ให้เป็นตัวเลขจำนวนมากก่อนที่จะตัดทอน ตัวเลือกทั่วไปคือ 12

'%.12f' % f

แต่คุณสามารถปรับให้เหมาะกับตัวเลขที่คุณใช้


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

def trunc_introspect(f, n):
    '''Truncates/pads the float f to n decimal places by looking at the caller's source code'''
    current_frame = None
    caller_frame = None
    s = inspect.stack()
    try:
        current_frame = s[0]
        caller_frame = s[1]
        gen = tokenize.tokenize(io.BytesIO(caller_frame[4][caller_frame[5]].encode('utf-8')).readline)
        for token_type, token_string, _, _, _ in gen:
            if token_type == tokenize.NAME and token_string == current_frame[3]:
                next(gen) # left parenthesis
                token_type, token_string, _, _, _ = next(gen) # float literal
                if token_type == tokenize.NUMBER:
                    try:
                        cut_point = token_string.index('.') + n + 1
                    except ValueError: # no decimal in string
                        return token_string + '.' + '0' * n
                    else:
                        if len(token_string) < cut_point:
                            token_string += '0' * (cut_point - len(token_string))
                        return token_string[:cut_point]
                else:
                    raise ValueError('Unable to find floating-point literal (this probably means you called {} with a variable)'.format(current_frame[3]))
                break
    finally:
        del s, current_frame, caller_frame

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


เราจะใช้ฟังก์ชันนี้กับดาต้าเฟรมได้อย่างไร?
เจ้าของรหัส

@RohithRNair ปิดด้านบนของหัวของฉันแบบเดียวกับที่คุณใช้ฟังก์ชันอื่น ๆ ที่ทำงานกับแต่ละองค์ประกอบ (เช่นapplymap()) อาจมีวิธีที่จะทำให้การดำเนินการทั้งหมดมีประสิทธิภาพมากขึ้น แต่นั่นก็เป็นเรื่องสำหรับคำถามแยกต่างหาก
David Z

applymap () ใช้เวลามากเนื่องจากดาต้าเฟรมของฉันมีขนาดใหญ่มาก ฉันกำลังพยายามเปรียบเทียบสองดาต้าเฟรมสำหรับความแตกต่าง แต่ความแม่นยำของจุดลอยตัวทำให้ผลลัพธ์ของฉันเบี้ยวจากที่ต้องการ อย่างที่คุณบอกฉันจะถามคำถามเดียวกัน ขอบคุณ.
เจ้าของรหัส

@RohithRNair อ่าถ้าคุณกำลังพยายามเปรียบเทียบสองดาต้าเฟรมสำหรับความแตกต่างให้ถามเกี่ยวกับเรื่องนั้นแทน การตัดทอนค่า (ซึ่งเป็นคำถามนี้เกี่ยวกับ) ไม่ใช่วิธีที่ดีที่สุดที่จะทำ
David Z

โปรดทราบว่ารหัสของคุณดูเหมือนจะสับตัวเลขเชิงลบให้เป็นศูนย์ลบซึ่งอาจทำให้สับสนได้ ...
user541686

152
round(1.923328437452, 3)

ดูเอกสารงูใหญ่เกี่ยวกับประเภทมาตรฐาน คุณจะต้องเลื่อนลงเล็กน้อยเพื่อไปที่ฟังก์ชัน round โดยพื้นฐานแล้วตัวเลขที่สองจะบอกจำนวนทศนิยมที่ต้องปัดเศษ


49
ฉันหมายความว่าการปัดเศษไม่ใช่สิ่งที่ฉันต้องการ ฉันต้องการการตัดทอนซึ่งแตกต่างออกไป
Joan Venge

1
Ahhh ยุติธรรมพอ ความผิดพลาดของฉันขอโทษ
Teifion

22
นั่นเป็นการโหวตจำนวนมากสำหรับวิธีแก้ปัญหาที่ไม่ถูกต้อง! หนึ่งในสิ่งที่หายากของ Stackoverflow ที่แปลกประหลาดเหล่านั้น ฉันสงสัยว่ามีตราสำหรับมันหรือ
เปล่า

5
เป็นที่น่าตกใจว่ามีคำตอบผิดกี่ข้อ (และโหวตให้คำตอบที่ผิด) สำหรับคำถามนี้
nullstellensatz

6
ผู้คนจำนวนมากจะมาที่หน้านี้เพื่อหาการปัดเศษ;)
janjackson

33

ผลลัพธ์ของroundการลอยตัวดังนั้นโปรดระวัง (ตัวอย่างมาจาก Python 2.6):

>>> round(1.923328437452, 3)
1.923
>>> round(1.23456, 3)
1.2350000000000001

คุณจะดีขึ้นเมื่อใช้สตริงที่จัดรูปแบบ:

>>> "%.3f" % 1.923328437452
'1.923'
>>> "%.3f" % 1.23456
'1.235'

8
ใน Python ของฉันรอบนั้น: '% .3f'% 1.23456 == '1.235'
David Z

นี่เป็นวิธีที่หรูหรากว่าการจัดรูปแบบสตริงด้วยตนเองไร้สาระโพสต์ที่ดี!
rsethc

round(1.23456, 3)is 1.235and not1.2350000000000001
Ahmad

1
@ Ahmad ไม่จำเป็น ตัวอย่างนี้มาจาก Python 2.6 (สังเกตวันที่ของคำตอบ) การจัดรูปแบบสตริงได้รับการปรับปรุงใน Python 2.7 / 3.1 นั่นอาจเป็นสาเหตุที่คุณได้ผลลัพธ์ที่แตกต่างกัน อย่างไรก็ตามตัวเลขทศนิยมมักจะมีการแสดงสตริงที่ไม่คาดคิดโปรดดู: docs.python.org/3.6/tutorial/floatingpoint.html
Ferdinand Beyer

21
n = 1.923328437452
str(n)[:4]

3
ง่ายและไพโธนิก 4 คือขนาดของจำนวนเต็มไม่ใช่เฉพาะตัวเลขหลังจุด
GaTTaCa

4
ดังนั้นหากผู้ใช้ป้อนตัวอย่างเช่น2คุณจะมีจุดทศนิยม.ที่ท้ายสตริงซึ่งไม่ใช่วิธีแก้ปัญหาที่ดีจริงๆ
Zelphir Kaltstahl

นี่เป็นกรณีเฉพาะสำหรับตัวเลขนี้ มันจะสรุปเป็น 11.923328437452 ได้อย่างไร?
โพลาไรซ์

ตอบดีที่สุด! คุณยังสามารถเพิ่ม float () เพื่อส่งกลับตัวเลข: float (str (n) [: 4])
justSaid


11

สคริปต์ python อย่างง่าย -

n = 1.923328437452
n = float(int(n * 1000))
n /=1000

3
คำตอบที่สะอาด คุณพลาดเพียงขั้นตอนเดียวในการแปลงกลับเป็นลอยก่อนหารด้วย 1,000 มิฉะนั้นคุณจะได้รับ 1.
Yohan Obadia

9
def trunc(num, digits):
   sp = str(num).split('.')
   return '.'.join([sp[0], sp[1][:digits]])

สิ่งนี้ควรใช้งานได้ ควรให้การตัดทอนที่คุณกำลังมองหา


9

วิธีการทำแบบไพ ธ อนิกที่แท้จริงคือ

from decimal import *

with localcontext() as ctx:
    ctx.rounding = ROUND_DOWN
    print Decimal('1.923328437452').quantize(Decimal('0.001'))

หรือสั้นกว่า:

from decimal import Decimal as D, ROUND_DOWN

D('1.923328437452').quantize(D('0.001'), rounding=ROUND_DOWN)

อัปเดต

โดยปกติแล้วปัญหาไม่ได้อยู่ที่การตัดการลอยตัวเอง แต่เกิดจากการใช้ตัวเลขลูกลอยที่ไม่เหมาะสมก่อนการปัดเศษ

ตัวอย่างเช่น: int(0.7*3*100)/100 == 2.09.

หากคุณถูกบังคับให้ใช้โฟลท (เช่นคุณกำลังเร่งโค้ดของคุณด้วยnumba) ควรใช้เซ็นต์เป็น "การนำเสนอภายใน" ของราคา: ( 70*3 == 210) และคูณ / หารอินพุต / เอาต์พุต


Parson ฉันถามเรื่องนี้ แต่ ... ทำไม?
markroxor

@markroxor ไม่แน่ใจว่าคุณกำลังถามเกี่ยวกับอะไร โดยทั่วไปแล้วปัญหาไม่ได้อยู่ที่การปัดเศษ แต่เกิดจากการใช้ตัวเลขลอยที่ไม่เหมาะสมก่อนการปัดเศษ เช่นint(0.7*3*100)/100 == 2.09. เงิน 1 เซ็นต์ของฉันหายไปไหน
Antony Hatchkins

ที่สมเหตุสมผลคุณสามารถแก้ไขคำตอบของคุณด้วยคำอธิบายนี้ได้หรือไม่ ขอบคุณ.
markroxor

ได้รับImportError: cannot import name 'D'ฉันเชื่อว่าคุณต้องการสร้างชื่อนำเข้าไม่?
Overdrivr

8

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

นี่เป็นผลการค้นหาอันดับต้น ๆ ของ Google เมื่อฉันค้นหา 'Python truncate float' ซึ่งเป็นแนวคิดที่ตรงไปตรงมามากและสมควรได้รับคำตอบที่ดีกว่า ฉันเห็นด้วยกับ Hatchkins ว่าการใช้decimalโมดูลเป็นวิธีการทำแบบ pythonic ดังนั้นฉันจึงให้ฟังก์ชั่นที่ฉันคิดว่าตอบคำถามได้ถูกต้องและใช้ได้ตามที่คาดไว้สำหรับทุกกรณี

โดยทั่วไปแล้วค่าเศษส่วนจะไม่สามารถแสดงได้อย่างแน่นอนโดยตัวแปรจุดลอยตัวไบนารี (ดูที่นี่สำหรับการอภิปรายเกี่ยวกับเรื่องนี้) ซึ่งเป็นสาเหตุที่ฟังก์ชันของฉันส่งคืนสตริง

from decimal import Decimal, localcontext, ROUND_DOWN

def truncate(number, places):
    if not isinstance(places, int):
        raise ValueError("Decimal places must be an integer.")
    if places < 1:
        raise ValueError("Decimal places must be at least 1.")
    # If you want to truncate to 0 decimal places, just do int(number).

    with localcontext() as context:
        context.rounding = ROUND_DOWN
        exponent = Decimal(str(10 ** - places))
        return Decimal(str(number)).quantize(exponent).to_eng_string()

4

ฉันทำสิ่งนี้:

from math import trunc


def truncate(number, decimals=0):
    if decimals < 0:
        raise ValueError('truncate received an invalid value of decimals ({})'.format(decimals))
    elif decimals == 0:
        return trunc(number)
    else:
        factor = float(10**decimals)
        return trunc(number*factor)/factor

4

คุณทำได้:

def truncate(f, n):
    return math.floor(f * 10 ** n) / 10 ** n

การทดสอบ:

>>> f=1.923328437452
>>> [truncate(f, n) for n in range(5)]
[1.0, 1.9, 1.92, 1.923, 1.9233]

สิ่งนี้จะตัดทอนด้วยจำนวนบวกเท่านั้นจำนวนลบจะปัดเศษลง (ห่างจากศูนย์)
Aaron D

3

หากคุณชอบคณิตศาสตร์สิ่งนี้ใช้ได้กับตัวเลข + ve:

>>> v = 1.923328437452
>>> v - v % 1e-3
1.923

ตามที่ฉันเข้าใจ 1e-3 จะตัดเป็น 3 หลักหลังจุด ฉันชอบคำตอบนี้ แต่ดูเหมือนว่าจะใช้ไม่ได้สำหรับ 4 และ 5
egvo

2

เมื่อใช้แพนด้า df สิ่งนี้ได้ผลสำหรับฉัน

import math
def truncate(number, digits) -> float:
    stepper = 10.0 ** digits
    return math.trunc(stepper * number) / stepper

df['trunc'] = df['float_val'].apply(lambda x: truncate(x,1))
df['trunc']=df['trunc'].map('{:.1f}'.format)

1

แค่อยากจะบอกว่าเคล็ดลับ "make round () with floor ()" แบบเก่าของ

round(f) = floor(f+0.5)

สามารถหมุนไปรอบ ๆ เพื่อสร้างพื้น () จากรอบ ()

floor(f) = round(f-0.5)

แม้ว่ากฎทั้งสองนี้จะทำลายจำนวนลบดังนั้นการใช้จึงน้อยกว่าอุดมคติ:

def trunc(f, n):
    if f > 0:
        return "%.*f" % (n, (f - 0.5*10**-n))
    elif f == 0:
        return "%.*f" % (n, f)
    elif f < 0:
        return "%.*f" % (n, (f + 0.5*10**-n))

1

int (16.5); สิ่งนี้จะให้ค่าจำนวนเต็ม 16 เช่น trunc จะไม่สามารถระบุทศนิยมได้ แต่เดาว่าคุณสามารถทำได้โดย

import math;

def trunc(invalue, digits):
    return int(invalue*math.pow(10,digits))/math.pow(10,digits);

1

นี่คือวิธีง่ายๆ:

def truncate(num, res=3):
    return (floor(num*pow(10, res)+0.5))/pow(10, res)

สำหรับ num = 1.923328437452 เอาต์พุตนี้ 1.923



1

ฟังก์ชันทั่วไปและใช้งานง่าย:

def truncate_float(number, length):
    """Truncate float numbers, up to the number specified
    in length that must be an integer"""

    number = number * pow(10, length)
    number = int(number)
    number = float(number)
    number /= pow(10, length)
    return number

เยี่ยมมาก! การโยนเป็น int จะตัดทอนทั้งจำนวนบวกและลบ
Aaron D

1

มีวิธีแก้ปัญหาง่ายๆใน python 3 ที่ที่จะตัดฉันกำหนดด้วยตัวแปรความช่วยเหลือ decPlace เพื่อให้ปรับตัวได้ง่าย

f = 1.12345
decPlace= 4
f_cut = int(f * 10**decPlace) /10**decPlace

เอาท์พุต:

f = 1.1234

หวังว่าจะช่วยได้


1
def precision(value, precision):
    """
    param: value: takes a float
    param: precision: int, number of decimal places
    returns a float
    """
    x = 10.0**precision
    num = int(value * x)/ x
    return num
precision(1.923328437452, 3)

1.923


ดี แต่คุณไม่ได้ปัดเศษ
Alex

1

ตัวแปรที่สั้นและง่าย

def truncate_float(value, digits_after_point=2):
    pow_10 = 10 ** digits_after_point
    return (float(int(value * pow_10))) / pow_10

>>> truncate_float(1.14333, 2)
>>> 1.14

>>> truncate_float(1.14777, 2)
>>> 1.14


>>> truncate_float(1.14777, 4)
>>> 1.1477

1

คำตอบส่วนใหญ่ซับซ้อนเกินไปในความคิดของฉันแล้วสิ่งนี้ล่ะ?

digits = 2  # Specify how many digits you want

fnum = '122.485221'
truncated_float = float(fnum[:fnum.find('.') + digits + 1])

>>> 122.48

เพียงแค่สแกนหาดัชนีของ "." และตัดทอนตามต้องการ (ไม่มีการปัดเศษ) แปลงสตริงให้ลอยเป็นขั้นตอนสุดท้าย

หรือในกรณีของคุณถ้าคุณได้ float เป็นอินพุตและต้องการสตริงเป็นเอาต์พุต:

fnum = str(122.485221)  # convert float to string first
truncated_float = fnum[:fnum.find('.') + digits + 1]  # string output

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



0

สิ่งที่ง่ายพอที่จะทำให้เข้าใจในรายการโดยไม่มีไลบรารีหรือการอ้างอิงภายนอกอื่น ๆ สำหรับ Python> = 3.6 การเขียนด้วย f-strings นั้นง่ายมาก

แนวคิดคือปล่อยให้การแปลงสตริงทำการปัดเศษไปยังอีกที่หนึ่งมากกว่าที่คุณต้องการแล้วตัดตัวเลขสุดท้ายออก

>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1] for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.800', '0.888', '1.125', '1.250', '1.500']

แน่นอนว่ายังมีการปัดเศษเกิดขึ้นที่นี่ (คือสำหรับหลักที่สี่) แต่การปัดเศษในบางจุดเป็น unvoidable ในกรณีที่การเปลี่ยนระหว่างการตัดทอนและการปัดเศษมีความเกี่ยวข้องนี่คือตัวอย่างที่ดีกว่าเล็กน้อย:

>>> nacc = 6  # desired accuracy (maximum 15!)
>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nacc}f}'[:-(nacc-nout)] for x in [2.9999, 2.99999, 2.999999, 2.9999999]]
>>> ['2.999', '2.999', '2.999', '3.000']

โบนัส: ลบศูนย์ทางด้านขวา

>>> nout = 3  # desired number of digits in output
>>> [f'{x:.{nout+1}f}'[:-1].rstrip('0') for x in [2/3, 4/5, 8/9, 9/8, 5/4, 3/2]]
['0.666', '0.8', '0.888', '1.125', '1.25', '1.5']

0

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

def trunc(num, digits):
    l = str(float(num)).split('.')
    digits = min(len(l[1]), digits)
    return (l[0]+'.'+l[1][:digits])

ซึ่งควรดูแลกรณีมุมทั้งหมดที่พบที่นี่และที่นี่


-1

ฉันยังเป็นมือใหม่หัดงูและหลังจากใช้ประโยชน์จากบิตและชิ้นส่วนที่นี่ฉันขอเสนอสองเซ็นต์ของฉัน

print str(int(time.time()))+str(datetime.now().microsecond)[:3]

str (int (time.time ())) จะใช้เวลา epoch เป็น int และแปลงเป็นสตริงและเข้าร่วมกับ ... str (datetime.now (). microsecond) [: 3] ซึ่งส่งคืนไมโครวินาทีเท่านั้นแปลง เพื่อสตริงและตัดทอนเป็น 3 ตัวอักษรแรก



-3

หากคุณหมายถึงเมื่อพิมพ์สิ่งต่อไปนี้ควรใช้งานได้:

print '%.3f' % number

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