วิธีการตรวจสอบว่าค่าลอยเป็นจำนวนเต็ม


204

ฉันพยายามค้นหารูทคิวบ์ที่ใหญ่ที่สุดที่เป็นจำนวนเต็มนั่นคือน้อยกว่า 12,000

processing = True
n = 12000
while processing:
    n -= 1
    if n ** (1/3) == #checks to see if this has decimals or not

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


3
มันจะทำให้การทำงานจาก cube รูทง่ายขึ้น -> (n * n * n <12000)
suspectus

คำตอบ:


371

ในการตรวจสอบว่าค่าทศนิยมเป็นจำนวนเต็มใช้float.is_integer()วิธีการ :

>>> (1.0).is_integer()
True
>>> (1.555).is_integer()
False

วิธีการถูกเพิ่มเข้ากับfloatชนิดใน Python 2.6

พิจารณาว่าใน Python 2 1/3คือ0(การแบ่งพื้นสำหรับตัวถูกดำเนินการจำนวนเต็ม!) และเลขคณิตจุดลอยตัวนั้นอาจไม่ชัดเจน (a floatเป็นการประมาณโดยใช้เศษส่วนไบนารีไม่ใช่จำนวนจริงที่แม่นยำ) แต่การปรับลูปของคุณเพียงเล็กน้อยก็ทำให้:

>>> for n in range(12000, -1, -1):
...     if (n ** (1.0/3)).is_integer():
...         print n
... 
27
8
1
0

ซึ่งหมายความว่ามีสิ่งใดที่เกิน 3 ลูก (รวมถึง 10,948) ได้พลาดเนื่องจากความไม่แน่นอนดังกล่าวข้างต้น:

>>> (4**3) ** (1.0/3)
3.9999999999999996
>>> 10648 ** (1.0/3)
21.999999999999996

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

>>> int(12000 ** (1.0/3))
22
>>> 22 ** 3
10648

หากคุณใช้ Python 3.5 หรือใหม่กว่าคุณสามารถใช้math.isclose()ฟังก์ชั่นเพื่อดูว่าค่าจุดลอยตัวอยู่ในระยะขอบที่กำหนดได้หรือไม่:

>>> from math import isclose
>>> isclose((4**3) ** (1.0/3), 4)
True
>>> isclose(10648 ** (1.0/3), 22)
True

สำหรับรุ่นเก่าการใช้งานแบบไร้เดียงสาของฟังก์ชั่นนั้น (การข้ามการตรวจสอบข้อผิดพลาดและการละเว้นอินฟินิตี้และ NaN) ดังกล่าวใน PEP485 :

def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
    return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

ไม่ทราบว่าไพ ธ อนคำสั่งประเภทนี้ทำให้ฉันกังวลเพราะมันดูเหมือนว่าต้องใช้คณิตศาสตร์ที่สมบูรณ์แบบในการทำงานในโลกแห่งความจริง
Peter M

1
@PeterM: วิธีการจะกลับเฉพาะในTrueกรณีที่ไม่มีทศนิยม อาจมีความเข้าใจผิดในส่วนของ OP เกี่ยวกับการคำนวณเลขทศนิยมและความแม่นยำแน่นอน
Martijn Pieters

1
@MartijnPieters ใช่และใบเล็ก ๆ แห่งหนึ่งในการคำนวณจุดลอยและทั้งหมดในทันทีที่คุณมีเล็ก ๆ น้อย ๆ เหล่านี้ไม่พึงประสงค์เช่นทศนิยม .00000000000000000001
ปีเตอร์เอ็ม

1
@PeterM: และใน Python 2 การแสดงค่าเริ่มต้นจะปัดเศษเป็นตัวเลข 16 หลัก 1.0000000000000001จะปรากฏเป็น1.0ใน 3 การแสดงสตริงที่สั้นที่สุดที่สร้างค่าเดียวกันจะปรากฏขึ้น
Martijn Pieters

คุณrange(12000, -1, -1)อาจเขียน (imo, reversed(range(12000+1))
cleanly

37

เราสามารถใช้ตัวดำเนินการโมดูโล (%) นี้จะบอกให้เรารู้ว่าหลายคนที่เหลือเรามีเมื่อเราแบ่ง x โดย Y - x % yเป็นการแสดงออกเป็น จำนวนเต็มทั้งหมดต้องหารด้วย 1 ดังนั้นหากมีเศษเหลืออยู่จะต้องไม่เป็นจำนวนเต็ม

ฟังก์ชันนี้จะคืนค่าบูลีนTrueหรือFalseขึ้นอยู่กับว่าnเป็นจำนวนเต็มหรือไม่

def is_whole(n):
    return n % 1 == 0

15

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

if k == int(k):
    print(str(k) + " is a whole number!")

5
มันล้มเหลวสำหรับตัวเลขขนาดใหญ่ในขณะที่.is_integer()ยังคงทำงาน
jfs

ลิงก์ของคุณ IMHO ไม่แสดงว่ามันใช้งานไม่ได้ มันแสดงให้เห็นว่าลอยขนาดใหญ่สูญเสียความแม่นยำ is_integerใช้วิธีการที่คล้ายกัน ( o = (floor(x) == x) ? Py_True : Py_False;) แต่ฉันเห็นด้วยอย่างใดอย่างหนึ่งควรใช้is_integer()เนื่องจากมีความชัดเจนมากขึ้น
Juri Robl

1
ใช่. มันก็แสดงให้เห็นว่าลอยขนาดใหญ่อาจสูญเสียคือความแม่นยำอาจล้มเหลวแม้ว่าlarge_float == large_int large_float == float(large_int)
jfs

2
123456789012345678901234567890.0 != 123456789012345678901234567890แต่123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs

2
ใช่ แต่k = 123456789012345678901234567890.0แล้วก็k == int(k)เป็นจริงซึ่งเป็นคำตอบที่ถูกต้อง
Juri Robl

9

คุณไม่จำเป็นต้องวนซ้ำหรือตรวจสอบอะไรเลย เพียงใช้รูทลูกบาศก์ของ 12,000 และปัดเศษลง:

r = int(12000**(1/3.0))
print r*r*r # 10648

นี่คือคำตอบที่สมเหตุสมผล
hughdbrown

7

คุณสามารถใช้การดำเนินการแบบโมดูโลได้

if (n ** (1.0/3)) % 1 != 0:
    print("We have a decimal number here!")

2
ถ้าnเป็น 6.2, 6.0, 6.12312412 เราทุกคนมี"We have a decimal number here!"?
เจย์หว่อง

@ JayWong ไม่แน่ใจว่าคุณโหลดการทดสอบอย่างไร แต่ใช้งานได้ดีกับเครื่องของฉันโดยใช้ Python3.7
Zchpyvr

6

การทดสอบรูทของลูกบาศก์จะง่ายกว่าหรือไม่ เริ่มต้นด้วย 20 (20 ** 3 = 8000) และขึ้นไปที่ 30 (30 ** 3 = 27000) จากนั้นคุณต้องทดสอบจำนวนเต็มน้อยกว่า 10 ตัว

for i in range(20, 30):
    print("Trying {0}".format(i))
    if i ** 3 > 12000:
        print("Maximum integral cube root less than 12000: {0}".format(i - 1))
        break

1
นอกจากนี้การลอยมีข้อผิดพลาดปัดเศษเพื่อให้คุณสามารถพลาดจำนวนเมื่อคำนวณว่าn**(1/3)เป็นจำนวนเต็ม ตัวอย่างเช่นในคอมพิวเตอร์ของฉัน `10648 ** (1/3) = 21.999999999999996 'แทนที่จะเป็น22: ปัญหา! ด้วยวิธีการของคำตอบนี้ไม่มีปัญหาดังกล่าว ฉันคิดว่านี่เป็นทางออกที่ถูกต้องเพียงอย่างเดียวจากมุมมองทางคณิตศาสตร์ (โซลูชันอื่น ๆ คือ Python-แก้ไข)
JPG


3

คำตอบข้างต้นใช้ได้กับหลาย ๆ กรณี แต่พวกเขาก็คิดถึง พิจารณาสิ่งต่อไปนี้:

fl = sum([0.1]*10)  # this is 0.9999999999999999, but we want to say it IS an int

การใช้สิ่งนี้เป็นเกณฑ์มาตรฐานคำแนะนำอื่น ๆ บางอย่างอาจไม่ได้รับพฤติกรรมที่เราอาจต้องการ:

fl.is_integer() # False

fl % 1 == 0     # False

ลองแทน:

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

def is_integer(fl):
    return isclose(fl, round(fl))

ตอนนี้เราได้รับ:

is_integer(fl)   # True

iscloseมาพร้อมกับPython 3.5+และสำหรับ Python อื่นคุณสามารถใช้คำนิยามที่เทียบเท่ากันได้ส่วนใหญ่ (ดังที่ได้กล่าวไว้ในPEP ที่เกี่ยวข้อง)


1
math.fsum([0.1] * 10) == 1
คิวเมนตัส

2

คำตอบทั้งหมดเป็นสิ่งที่ดี แต่วิธีการดับเพลิงที่แน่นอนจะเป็น

def whole (n):
     return (n*10)%10==0

ฟังก์ชันคืนค่าเป็น True ถ้าเป็นจำนวนเต็มทั้งหมดเป็นเท็จ .... ฉันรู้ว่าฉันมาช้า แต่นี่เป็นหนึ่งในวิธีการที่น่าสนใจที่ฉันทำ ...

แก้ไข: ตามที่ระบุไว้โดยความคิดเห็นด้านล่างการทดสอบที่เทียบเท่าจะถูกกว่า:

def whole(n):
    return n%1==0

1
สิ่งนี้ไม่ควรแตกต่างจากการn % 1 == 0ใช้งาน ในกรณีนี้คุณกำลังดำเนินการสองอย่างซึ่งแพงกว่าสำหรับการทดสอบที่ถูกกว่า
Zchpyvr

1

เพียงแค่ข้อมูลด้านis_integerกำลังทำภายใน:

import math
isInteger = (math.floor(x) == x)

ไม่ได้อยู่ในหลามอย่างแน่นอน แต่การใช้งาน cpython นั้นถูกนำไปใช้ตามที่กล่าวไว้ข้างต้น


0
>>> def is_near_integer(n, precision=8, get_integer=False):
...     if get_integer:
...         return int(round(n, precision))
...     else:
...         return round(n) == round(n, precision)
...
>>> print(is_near_integer(10648 ** (1.0/3)))
True
>>> print(is_near_integer(10648 ** (1.0/3), get_integer=True))
22
>>> for i in [4.9, 5.1, 4.99, 5.01, 4.999, 5.001, 4.9999, 5.0001, 4.99999, 5.000
01, 4.999999, 5.000001]:
...     print(i, is_near_integer(i, 4))
...
4.9 False
5.1 False
4.99 False
5.01 False
4.999 False
5.001 False
4.9999 False
5.0001 False
4.99999 True
5.00001 True
4.999999 True
5.000001 True
>>>

นี่เป็นแนวทางสำหรับฉันจะเขียนคำตอบที่ดีได้อย่างไร . คำตอบที่ให้นี้อาจถูกต้อง แต่อาจได้ประโยชน์จากคำอธิบาย คำตอบของรหัสเท่านั้นจะไม่ถือว่าคำตอบ "ดี" จากการตรวจสอบ
เทรนตัน McKinney

-1

ลองใช้:

int(val) == val

มันจะให้ความแม่นยำมากกว่าวิธีอื่น ๆ


คุณยกตัวอย่างเพื่อสำรองข้อมูลการอ้างสิทธิ์ที่ "จะให้ความแม่นยำมากขึ้น" หรือไม่? ดูเหมือนว่าไม่มีมูลความจริง
Mark Dickinson

-1

คุณสามารถใช้roundฟังก์ชันเพื่อคำนวณค่า

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

def cube_integer(n):
    if round(n**(1.0/3.0))**3 == n:
        return True
    return False

แต่จำไว้ว่าint(n)เท่ากับmath.floorและเพราะสิ่งนี้ถ้าคุณพบint(41063625**(1.0/3.0))คุณจะได้ 344 แทน 345

ดังนั้นโปรดใช้ความระมัดระวังเมื่อใช้กับรูทของintคิวบ์

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