วิธีที่ปลอดภัยที่สุดในการแปลง float เป็นจำนวนเต็มในไพ ธ อน?


216

โมดูลคณิตศาสตร์ ธ ประกอบด้วยฟังก์ชั่นที่มีประโยชน์เช่น&floor ceilฟังก์ชั่นเหล่านี้ใช้จำนวนจุดลอยตัวและส่งกลับจำนวนเต็มที่ใกล้เคียงที่สุดหรือต่ำกว่านั้น อย่างไรก็ตามฟังก์ชั่นเหล่านี้คืนคำตอบเป็นจำนวนจุดลอยตัว ตัวอย่างเช่น:

import math
f=math.floor(2.3)

ตอนนี้fผลตอบแทน:

2.0

วิธีที่ปลอดภัยที่สุดในการดึงจำนวนเต็มออกจาก float นี้โดยไม่เสี่ยงต่อการปัดเศษข้อผิดพลาด (ตัวอย่างเช่นถ้า float เท่ากับ 1.99999) หรือบางทีฉันควรใช้ฟังก์ชันอื่นโดยสิ้นเชิง?


7
math.floor ผลตอบแทนที่ลอยใน v2.6แต่มันกลับจำนวนเต็มใน v3 ณ จุดนี้ (เกือบหกปีหลังจาก OP) ปัญหานี้อาจปรากฏขึ้นไม่บ่อยนัก
sancho.s ReinstateMonicaCellio

อย่างไรก็ตามจำนวน numpy ยังคงกลับลอยดังนั้นคำถามที่ถูกต้อง
Vincenzooo

คำตอบ:


178

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

ว่างานนี้ไม่สำคัญเลย! มันเป็นคุณสมบัติของการเป็นตัวแทนจุดลอยตัวของ IEEE ที่ int =floor = ⌊⋅⌋หากขนาดของตัวเลขที่เป็นปัญหานั้นมีขนาดเล็กพอ แต่การแสดงที่ต่างกันนั้นเป็นไปได้โดยที่ int (floor (2.3)) อาจเป็น 1

การอ้างอิงจากวิกิพีเดีย ,

จำนวนเต็มใด ๆ ที่มีค่าสัมบูรณ์น้อยกว่าหรือเท่ากับ 2 24สามารถแสดงได้อย่างแม่นยำในรูปแบบความแม่นยำเดียวและจำนวนเต็มใด ๆ ที่มีค่าสัมบูรณ์น้อยกว่าหรือเท่ากับ 2 53สามารถแสดงได้อย่างแม่นยำในรูปแบบความแม่นยำสองเท่า


8
+1 เพื่อเพิ่มความลึก คุณสามารถอธิบายด้วยเหตุผลสั้น ๆ ว่า: en.wikipedia.org/wiki/Floating_point : D
Gordon Gustafson

ใน Python 2 "int" เหมือนกับ C "int" ใน Python 3 จะไม่มีการ จำกัด ขนาดของ "int, stackoverflow.com/questions/13795758/ ......ความหมายของ" int "นั้นขึ้นอยู่กับระบบปฏิบัติการและฮาร์ดแวร์พื้นฐานด้วยเช่นกันดูen.wikipedia org / wiki / 64-bit_computing # 64-bit_data_modelsหากคุณกำลังเขียนโปรแกรมด้วย C-API, python 3 คุณจะต้องระมัดระวังในคำจำกัดความของ long และ size_t บนแพลตฟอร์มของคุณdocs.python.org/3 /c-api/long.html
Juan

113

int(your non integer number)จะใช้เล็บมัน

print int(2.3) # "2"
print int(math.sqrt(5)) # "2"

4
สิ่งนี้จะไม่ทำงานสำหรับตัวเลขลบ: floorปัดเศษลงในขณะที่intปัดเศษเป็น 0
jochen

1
@ jochen ฉันทดสอบint(-2.3)ใน Python Canopy 2.7.6 และได้-2ตามที่คาดไว้ ตัวเลขจำนวนเต็มอาจเป็นลบได้เช่นเดียวกับคำจำกัดความทางคณิตศาสตร์อย่างเป็นทางการ
srodriguex

5
ฉันเห็นด้วยint(-2.3)ให้-2ตามที่คุณพูดเพราะมันเข้าหา0กันเช่นในกรณีนี้ ในทางตรงกันข้ามคำถามเดิมใช้math.floorซึ่งมักรอบลงให้math.floor(-2.3) -3.0
jochen

1
นั่นไม่ใช่ปัญหาจริงๆ OP แค่ต้องการจำนวนเต็มจากผลลัพธ์math.floorและคำตอบนี้แสดงวิธีแปลง float เป็นจำนวนเต็ม นำทุ่นmath.floorและไปป์intint(math.floor(2.3))
ไลน์

4
คุณยังอ่านคำถามหรือไม่ เขาทราบถึงฟังก์ชั่นint ()แต่ได้ถามว่าคุณอาจมีปัญหากับ 1.9999 แทนที่จะเป็น 2.0 หรือไม่ คำตอบของคุณไม่ได้ใกล้เคียงกับคำตอบเลยคุณพลาดจุดทั้งหมด ...
Mayou36

48

คุณสามารถใช้ฟังก์ชั่นรอบ หากคุณใช้พารามิเตอร์ที่สอง (# ของตัวเลขที่สำคัญ) ฉันคิดว่าคุณจะได้รับพฤติกรรมที่คุณต้องการ

เอาต์พุต IDLE

>>> round(2.99999999999)
3
>>> round(2.6)
3
>>> round(2.5)
3
>>> round(2.4)
2

28
roundส่งคืนเลขทศนิยมเช่นกันอย่างน้อยใน Python 2.6
ฟิลิปป์

8
ใน Python 3.1.2 ปัดเศษคืนค่า int
เบิร์ต

2
อันที่จริงทั้งสองroundและfloorคืนจำนวนเต็มใน Python 3.x ดังนั้นฉันคิดว่าคำถามเกี่ยวข้องกับ Python 2.x
ฟิลิปป์

4
อาจจะint(round(2.65))?
teewuane

1
ทำไมถึงround(6.5)ให้ 6 ดูเหมือนว่าจะceil()ลอยตัวเมื่อมี 5 ทันที (หรือสูงกว่าถึง 9) หลังจากทศนิยมในกรณีอื่นทั้งหมด เหตุใดจึงไม่ทำงานในกรณีนี้ หรือกรณีอื่น ๆ เมื่อจำนวนลงท้ายด้วยหกและมี 5 ขวาหลังจากทศนิยม ...
candh

43

เมื่อรวมผลลัพธ์สองรายการก่อนหน้าเข้าด้วยกันเรามี:

int(round(some_float))

สิ่งนี้จะแปลงทศนิยมเป็นจำนวนเต็มอย่างน่าเชื่อถือ


จะเกิดอะไรขึ้นถ้าคุณพยายามปัดเศษที่ยาวมาก ๆ ? อย่างน้อยจะยกข้อยกเว้นนี้หรือไม่
Agostino

@Agostino คุณหมายถึงอะไร "โฟลตติ้งที่ยาวมาก"?
kralyk

@ kralyk ฉันหมายfloatถึงตัวเลขที่มากกว่าจำนวนที่ปกติintสามารถถือได้ ใน Python 2 มีfloatค่าที่คุณสามารถใช้แทนlong(หลังจากการปัดเศษ) หรือไม่?
Agostino

@kralyk คุณหมายถึงหลังจากรอบหรือไม่ ดังนั้นจะหล่อพวกเขาเพื่อยกข้อยกเว้นหรือเพียงแค่ตัดพวกเขา?
Agostino

@Agostino ไม่int()ฟังก์ชั่นจะสร้างintหรือlongขึ้นอยู่กับสิ่งที่จำเป็น ...
kralyk

18

ว่างานนี้ไม่สำคัญเลย! มันเป็นคุณสมบัติของการเป็นตัวแทนจุดลอยตัวของ IEEE ที่ int =floor = ⌊⋅⌋หากขนาดของตัวเลขที่เป็นปัญหานั้นมีขนาดเล็กพอ แต่การแสดงที่ต่างกันนั้นเป็นไปได้โดยที่ int (floor (2.3)) อาจเป็น 1

โพสต์นี้จะอธิบายว่าเพราะเหตุใดจึงใช้งานได้ในช่วงนั้น

ใน double คุณสามารถแทนจำนวนเต็ม 32 บิตได้โดยไม่มีปัญหา มีไม่สามารถจะมีปัญหาการปัดเศษใด ๆ แม่นยำยิ่งขึ้นเป็นสองเท่าสามารถเป็นตัวแทนของจำนวนเต็มทั้งหมดระหว่างและรวมถึง2 53และ-2 53 53

คำอธิบายสั้น ๆ : Double สามารถเก็บได้ถึง 53 หลักไบนารี เมื่อคุณต้องการมากกว่าหมายเลขจะถูกเติมด้วยเลขศูนย์ทางด้านขวา

ตามมาว่า 53 รายการเป็นหมายเลขที่ใหญ่ที่สุดที่สามารถจัดเก็บได้โดยไม่ต้องแพ็ดดิง โดยปกติแล้วตัวเลข (จำนวนเต็ม) ทั้งหมดที่ต้องการตัวเลขน้อยกว่าสามารถจัดเก็บได้อย่างถูกต้อง

เพิ่มหนึ่งถึง111 (ละเว้น) 111 (53 รายการ) ให้ผลตอบแทน 100 ... 000, (53 ศูนย์) อย่างที่เราทราบเราสามารถเก็บ 53 หลักซึ่งทำให้การเติมเต็มเป็นศูนย์ที่ถูกต้องที่สุด

นี่คือที่ 2 53มาจาก


รายละเอียดเพิ่มเติม:เราต้องพิจารณาว่าจุดลอยตัวของ IEEE-754 ทำงานอย่างไร

  1 bit    11 / 8     52 / 23      # bits double/single precision
[ sign |  exponent | mantissa ]

จากนั้นคำนวณจำนวนดังนี้ (ยกเว้นกรณีพิเศษที่ไม่เกี่ยวข้องที่นี่):

-1 sign × 1.mantissa × 2 exponent - bias

โดยที่bias = 2 เลขชี้กำลัง - 1 - 1คือ 1023 และ 127 สำหรับความแม่นยำสองเท่า / เดี่ยว

เมื่อรู้ว่าการคูณด้วย2 Xจะเลื่อนบิตXทั้งหมดไปทางซ้ายมันเป็นเรื่องง่ายที่จะเห็นว่าจำนวนเต็มใด ๆ จะต้องมีบิตทั้งหมดในแมนทิสซาที่จบลงทางขวาของจุดทศนิยมเป็นศูนย์

จำนวนเต็มใด ๆ ยกเว้นศูนย์มีรูปแบบต่อไปนี้ในไบนารี:

1x ... xโดยที่x- e แทนบิตทางด้านขวาของ MSB (บิตที่สำคัญที่สุด)

เพราะเราได้รับการยกเว้นศูนย์จะมีเสมอจะ MSB ที่เป็นหนึ่งซึ่งเป็นเหตุผลที่มันไม่ได้เก็บไว้ ในการจัดเก็บจำนวนเต็มที่เราจะต้องนำมาไว้ในรูปแบบดังกล่าวข้างต้น: -1 ลงชื่อ × 1.mantissa × 2 ยกกำลัง - อคติ

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

จากนี้เราจะเห็นได้ว่าเราสามารถเก็บได้มากที่สุด 52 หลักไบนารีนอกเหนือจาก MSB

ตามด้วยจำนวนสูงสุดที่มีการจัดเก็บบิตทั้งหมดไว้อย่างชัดเจน

111(omitted)111.   that's 53 ones (52 + implicit 1) in the case of doubles.

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

111(omitted)111x.

ตามแบบแผนคือ 0 ตั้งค่า mantissa ทั้งหมดเป็นศูนย์เราได้รับหมายเลขต่อไปนี้:

100(omitted)00x. = 100(omitted)000.

นั่นคือ 1 ตามด้วย 53 ศูนย์, 52 ที่เก็บไว้และ 1 เพิ่มเนื่องจากเลขชี้กำลัง

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


8

math.floorจะส่งกลับตัวเลขจำนวนเต็มเสมอและดังนั้นint(math.floor(some_float))จะไม่แนะนำข้อผิดพลาดในการปัดเศษ

ข้อผิดพลาดในการปัดเศษอาจถูกนำมาใช้ในmath.floor(some_large_float)แม้ว่าหรือแม้กระทั่งเมื่อเก็บจำนวนมากในการลอยในสถานที่แรก (ตัวเลขจำนวนมากอาจสูญเสียความแม่นยำเมื่อเก็บไว้ในโฟลต)


7
จาก: docs.python.org/2/library/math.html - math.floor (x) - คืนค่าพื้นของ x เป็นทศนิยมค่าจำนวนเต็มที่มากที่สุดน้อยกว่าหรือเท่ากับ x
Bill Rosmus

ทำไมคุณต้องโทรหา math.floor เมื่อ int ทำสิ่งเดียวกันอยู่แล้ว?
Alex

1
@Alex: intและfloorคืนค่าที่แตกต่างกันสำหรับจำนวนลบแน่นอน

8

หากคุณต้องการแปลงสตริงลอยให้เป็น int คุณสามารถใช้วิธีนี้

ตัวอย่าง: '38.0'ถึง38

ในการแปลงค่านี้เป็น int คุณสามารถร่ายมันเป็นทุ่นและ int สิ่งนี้จะทำงานสำหรับสตริงลอยหรือสตริงจำนวนเต็ม

>>> int(float('38.0'))
38
>>> int(float('38'))
38

หมายเหตุ : สิ่งนี้จะตัดจำนวนใด ๆ หลังจุดทศนิยม

>>> int(float('38.2'))
38

1

ตัวอย่างโค้ดอื่นเพื่อแปลงค่าจริง / จำนวนเต็มเป็นจำนวนเต็มโดยใช้ตัวแปร "vel" เป็นจำนวนจริง / จำนวนลอยตัวและแปลงเป็น INTEGER ที่สูงที่สุดถัดไป "newvel"

import arcpy.math, os, sys, arcpy.da
.
.
with arcpy.da.SearchCursor(densifybkp,[floseg,vel,Length]) as cursor:
 for row in cursor:
    curvel = float(row[1])
    newvel = int(math.ceil(curvel))

0

เมื่อคุณขอวิธีที่ 'ปลอดภัยที่สุด' ฉันจะให้คำตอบอื่นที่ไม่ใช่คำตอบยอดนิยม

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

if int(some_value) == some_value:
     some_value = int(some_value)

ถ้า float เป็น 1.0 เช่น 1.0 เท่ากับ 1 ดังนั้นการแปลงเป็น int จะทำงาน และถ้าลอยเป็น 1.1, int (1.1) เท่ากับ 1 และ 1.1! = 1 ดังนั้นค่าจะยังคงลอยและคุณจะไม่สูญเสียความแม่นยำใด ๆ


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