Cara memeriksa apakah nilai float adalah bilangan bulat


202

Saya mencoba menemukan akar pangkat tiga terbesar yang merupakan bilangan bulat, yaitu kurang dari 12.000.

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

Saya tidak yakin bagaimana memeriksa apakah itu bilangan bulat atau tidak! Saya bisa mengubahnya menjadi string kemudian menggunakan pengindeksan untuk memeriksa nilai akhir dan melihat apakah mereka nol atau tidak, yang tampaknya agak rumit sekalipun. Apakah ada cara yang lebih sederhana?


3
itu akan membuatnya lebih mudah untuk bekerja dari cube root n -> (n * n * n <12000)
suspus

Jawaban:


367

Untuk memeriksa apakah nilai float adalah bilangan bulat, gunakan float.is_integer()metode ini :

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

Metode ini ditambahkan ke floattipe Python 2.6.

Mempertimbangkan bahwa dalam Python 2, 1/3adalah 0(pembagian lantai untuk operan bilangan bulat!), Dan bahwa aritmatika titik apung dapat tidak tepat (a floatadalah perkiraan menggunakan fraksi biner, bukan bilangan real yang tepat). Tetapi sedikit menyesuaikan loop Anda ini memberi:

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

yang berarti bahwa lebih dari 3 potong dadu, (termasuk 10648) terlewatkan karena ketidaktepatan yang disebutkan di atas:

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

Anda harus memeriksa nomor yang dekat dengan seluruh nomor, atau tidak menggunakan float()untuk menemukan nomor Anda. Seperti membulatkan akar pangkat tiga dari 12000:

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

Jika Anda menggunakan Python 3.5 atau yang lebih baru, Anda dapat menggunakan math.isclose()fungsi ini untuk melihat apakah nilai floating point berada dalam margin yang dapat dikonfigurasi:

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

Untuk versi yang lebih lama, implementasi naif dari fungsi itu (melewatkan pemeriksaan kesalahan dan mengabaikan infinity dan NaN) sebagaimana disebutkan dalam 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)

Tidak tahu python, pernyataan semacam ini akan membuat saya gugup karena tampaknya membutuhkan matematika yang sempurna untuk bekerja di dunia nyata.
Peter M

1
@PeterM: Metode ini memang hanya mengembalikan Truejika tidak ada desimal sama sekali. Mungkin ada kesalahpahaman di pihak OP tentang aritmatika dan presisi floating point, tentu saja.
Martijn Pieters

1
@ MartijnPieters Ya dan satu slip kecil dalam perhitungan floating point dan tiba-tiba Anda memiliki desimal kecil yang tidak diinginkan ini seperti 0,0000000000000000000001
Peter M

1
@PeterM: dan dalam Python 2 representasi default akan dibulatkan menjadi 16 digit; 1.0000000000000001ditampilkan sebagai 1.0, dalam 3 representasi string terpendek yang menghasilkan nilai yang sama ditampilkan.
Martijn Pieters

Anda range(12000, -1, -1)dapat (imo, lebih bersih) ditulis ulang sebagaireversed(range(12000+1))
cs95

36

Kita dapat menggunakan operator modulo (%). Ini memberitahu kita berapa banyak sisa yang kita miliki ketika kita membagi x dengan y - menyatakan sebagai x % y. Setiap bilangan bulat harus dibagi dengan 1, jadi jika ada sisa, itu tidak harus menjadi bilangan bulat.

Fungsi ini akan mengembalikan boolean, Trueatau False, tergantung pada apakah nbilangan bulat.

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

15

Anda bisa menggunakan ini:

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

5
gagal untuk angka yang lebih besar sambil .is_integer()terus bekerja.
jfs

Tautan IMHO Anda tidak menunjukkan bahwa itu tidak berfungsi. Itu hanya menunjukkan bahwa pelampung besar kehilangan presisi. is_integermenggunakan metode serupa ( o = (floor(x) == x) ? Py_True : Py_False;). Tapi saya setuju, orang harus menggunakan is_integer()karena jauh lebih jelas.
Juri Robl

1
Iya. Itu hanya menunjukkan bahwa pelampung besar mungkin kehilangan presisi yaitu, large_float == large_intmungkin gagal bahkan jika large_float == float(large_int).
jfs

2
123456789012345678901234567890.0 != 123456789012345678901234567890tapi123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs

2
Ya, tetapi k = 123456789012345678901234567890.0kemudian k == int(k)Benar, yang merupakan jawaban yang benar.
Juri Robl

9

Anda tidak perlu mengulang atau memeriksa apa pun. Cukup ambil akar pangkat 12.000 dan bulatkan:

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

Ini jawaban yang masuk akal.
hughdbrown

7

Anda dapat menggunakan operasi modulo untuk itu.

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

2
jika n6.2, 6.0, 6.12312412, kita semua miliki "We have a decimal number here!"?
Jay Wong

@ JayWong tidak yakin bagaimana Anda memuat tes Anda, tetapi ini berfungsi dengan baik di komputer saya menggunakan Python3.7.
Zchpyvr

6

Bukankah lebih mudah untuk menguji akar kubus? Mulai dengan 20 (20 ** 3 = 8000) dan naik hingga 30 (30 ** 3 = 27000). Maka Anda harus menguji kurang dari 10 bilangan bulat.

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
Selain itu, float memiliki kesalahan pembulatan sehingga Anda dapat kehilangan nomor saat menghitung jika n**(1/3)bilangan bulat. Misalnya di komputer saya `10648 ** (1/3) = 21.999999999999996` bukan 22: masalah! Dengan metode jawaban ini tidak ada masalah seperti itu. Saya pikir ini adalah satu-satunya solusi yang benar dari sudut pandang matematika (solusi lain adalah Python-benar).
JPG


3

Jawaban di atas berfungsi untuk banyak kasus tetapi mereka kehilangan beberapa. Pertimbangkan yang berikut ini:

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

Menggunakan ini sebagai patokan, beberapa saran lain tidak mendapatkan perilaku yang mungkin kita inginkan:

fl.is_integer() # False

fl % 1 == 0     # False

Alih-alih mencoba:

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

sekarang kita dapatkan:

is_integer(fl)   # True

isclosehadir dengan Python 3.5+ , dan untuk Python lainnya, Anda dapat menggunakan definisi yang sebagian besar setara ini (seperti yang disebutkan dalam PEP yang sesuai )


1
math.fsum([0.1] * 10) == 1
Acumenus

1

Hanya info sampingan, is_integeryang dilakukan secara internal:

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

Tidak persis dengan python, tetapi implementasi cpython diimplementasikan seperti yang disebutkan di atas.


1

Semua jawaban baik tetapi metode api pasti

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

Fungsi ini mengembalikan Benar jika itu seluruh nomor lain Salah .... Saya tahu saya agak terlambat tapi inilah salah satu metode menarik yang saya buat ...

Sunting: sebagaimana dinyatakan oleh komentar di bawah ini, tes setara yang lebih murah adalah:

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

1
Ini seharusnya tidak berbeda secara fungsional dari n % 1 == 0. Dalam hal ini, Anda melakukan dua operasi yang lebih mahal untuk tes setara yang lebih murah.
Zchpyvr

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

Berikut adalah beberapa pedoman untuk Bagaimana cara saya menulis jawaban yang baik? . Jawaban yang diberikan ini mungkin benar, tetapi bisa mendapat manfaat dari penjelasan. Jawaban hanya kode tidak dianggap sebagai jawaban "baik". Dari ulasan .
Trenton McKinney

-1

Coba gunakan:

int(val) == val

Ini akan memberikan lebih banyak presisi daripada metode lainnya.


Bisakah Anda memberikan contoh untuk mendukung klaim bahwa "Ini akan memberikan lebih banyak presisi"? Ini sepertinya tidak berdasar.
Mark Dickinson

-1

Anda dapat menggunakan roundfungsi untuk menghitung nilai.

Ya dengan python seperti yang telah ditunjukkan oleh banyak orang ketika kita menghitung nilai dari sebuah root cube, itu akan memberi Anda sebuah output dengan sedikit kesalahan. Untuk memeriksa apakah nilainya bilangan bulat, Anda dapat menggunakan fungsi berikut:

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

Tetapi ingat itu int(n)setara dengan math.floordan karena ini jika Anda menemukan int(41063625**(1.0/3.0))Anda akan mendapatkan 344 bukannya 345.

Jadi harap berhati-hati saat menggunakan intwithe cube root.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.