Kayan değer tam sayı olup olmadığı nasıl kontrol edilir


204

Ben bir sayı, bu az 12.000 en büyük küp kök bulmaya çalışıyorum.

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

Tam sayı olup olmadığını nasıl kontrol edeceğimi bilmiyorum! Ben bir dizeye dönüştürmek sonra endeksleme kullanarak son değerleri kontrol etmek ve sıfır olup olmadığını görmek için bu oldukça hantal görünüyor. Daha basit bir yol var mı?


3
küp kökünden çalışmayı kolaylaştırır n -> (n * n * n <12000)
suspectus

Yanıtlar:


371

Bir kayan nokta değerinin tam sayı olup olmadığını kontrol etmek için şu float.is_integer()yöntemi kullanın :

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

Yöntem floatPython 2.6 tipine eklendi .

Python 2'de, dikkat edilmesi gerekenler, 1/3ise 0, (a (! Tamsayı işlenenler için zemin bölme) ve kayar nokta aritmetik kesin olmayan olabileceğini floatikili kesirler kullanarak yaklaşık bir değerdir değil kesin gerçek sayı). Ancak döngünüzü biraz ayarlamak bu sağlar:

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

Bu da, yukarıda belirtilen kesinsizlik nedeniyle 3'den fazla küpün (10648 dahil) kaçırıldığı anlamına gelir:

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

Bunun yerine tam sayıya yakın sayıları kontrol etmeniz veya float()numaranızı bulmak için kullanmamanız gerekir. Küp kökü yuvarlamak gibi 12000:

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

Python 3.5 veya daha yenisini kullanıyorsanız, kayan nokta değerinin yapılandırılabilir kenar boşluğu içinde olup olmadığını görmek için math.isclose()işlevi kullanabilirsiniz :

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

Daha eski sürümler için, PEP485'te belirtildiği gibi bu işlevin naif uygulaması (hata kontrolünü ve sonsuzluğu ve NaN'yi atlamak) :

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)

Python bilmeden, bu tür bir ifade gerçek dünyada çalışmak için mükemmel matematik gerektirdiği için beni sinirlendirir.
Peter M

1
@PeterM: Aslında yöntem yalnızca Trueondalık sayı yoksa döner . OP'nin kayan nokta aritmetiği ve kesinliği konusunda elbette bir yanlış anlaşılma olabilir.
Martijn Pieters

1
@MartijnPieters Evet ve kayan nokta hesaplamasında küçük bir kayma ve birdenbire 0.00000000000000000001
Peter M

1
@PeterM: ve Python 2'de varsayılan gösterim 16 basamağa yuvarlanır; 1.0000000000000001olarak gösterilir 1.0, 3'te aynı değeri üreten en kısa dize gösterimi gösterilir.
Martijn Pieters

( range(12000, -1, -1)reversed(range(12000+1))
İmo

37

Modulo (%) operatörünü kullanabiliriz. Bu bize x'i y'ye böldüğümüzde kaç tane kalıntı kaldığımızı söyler - olarak ifade eder x % y. Her tam sayı 1'e bölünmelidir, bu nedenle bir kalan varsa tam sayı olmamalıdır.

Bu işlev bir boole döndürür Trueveya tam sayı Falseolup olmamasına bağlı olarak döner n.

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

15

Bunu kullanabilirsiniz:

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

5
çalışmaya devam ederken daha büyük sayılar için başarısız olur .is_integer().
jfs

IMHO bağlantınız işe yaramadığını göstermiyor. Sadece büyük şamandıraların hassasiyetini kaybettiğini gösterir. is_integerbenzer bir yöntem ( o = (floor(x) == x) ? Py_True : Py_False;) kullanır . Ama katılıyorum, is_integer()çok daha net olduğu için kullanmalıyım .
Juri Robl

1
Evet. Sadece büyük şamandıraların hassasiyeti kaybedebileceğini, yani large_float == large_intolsa bile başarısız olabileceğini gösterir large_float == float(large_int).
jfs

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

2
Evet, ama k = 123456789012345678901234567890.0o zaman k == int(k)doğru cevaptır Doğru, olduğunu.
Juri Robl

9

Döngüye veya herhangi bir şeyi kontrol etmenize gerek yoktur. Sadece 12.000 küp kökü alın ve yuvarlayın:

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

Bu makul bir cevap.
hughdbrown

7

Bunun için bir modulo işlemi kullanabilirsiniz .

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

2
eğer n6.2, 6.0, 6,12312412, hepimizin sahip "We have a decimal number here!"?
Jay Wong

@JayWong, testinizi nasıl yüklediğinizden emin değil, ancak bu Python3.7 kullanarak makinemde iyi çalışıyor.
Zchpyvr

6

Küp köklerini test etmek daha kolay olmaz mıydı? 20 (20 ** 3 = 8000) ile başlayın ve 30'a kadar (30 ** 3 = 27000) gidin. O zaman 10'dan az tamsayıyı test etmelisiniz.

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
Ayrıca, kayan noktalı yuvarlama hataları vardır, böylece n**(1/3)tamsayı olup olmadığını hesaplarken sayıyı kaçırabilirsiniz . Örneğin, bilgisayarımda `` 10648 ** (1/3) = 21.999999999999996 '' yerine 22: sorun! Bu yanıtın yönteminde böyle bir sorun yoktur. Bence bu matematik açısından tek doğru çözüm (diğer çözümler Python-doğru).
JPG


3

Yukarıdaki cevaplar birçok vaka için işe yarıyor ama bazılarını kaçırıyorlar. Aşağıdakileri göz önünde bulundur:

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

Bunu bir karşılaştırma ölçütü olarak kullandığımızda, diğer bazı öneriler isteyebileceğimiz davranışı alamıyor:

fl.is_integer() # False

fl % 1 == 0     # False

Bunun yerine şunu deneyin:

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

şimdi:

is_integer(fl)   # True

isclosePython 3.5+ ile birlikte gelir ve diğer Python'lar için bu çoğunlukla eşdeğer tanımı kullanabilirsiniz (ilgili PEP'te belirtildiği gibi )


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

2

Tüm cevaplar iyi ama kesin bir yangın yöntemi

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

Eğer bir tam sayı yanlışsa fonksiyon True döndürür .... Biraz geç kaldığımı biliyorum ama işte yaptığım ilginç yöntemlerden biri ...

Düzenleme: aşağıdaki yorumda belirtildiği gibi, daha ucuz bir eşdeğer test şöyle olacaktır:

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

1
Bu, işlevsel olarak farklı olmamalıdır n % 1 == 0. Bu durumda, daha ucuz bir eşdeğer test için daha pahalı olan iki işlem yapıyorsunuz.
Zchpyvr

1

Sadece bir yan bilgi, is_integerdahili olarak yapıyor:

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

Tam olarak python'da değil, cpython uygulaması yukarıda belirtildiği gibi uygulanır.


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

İşte için bazı kurallar vardır Ben iyi cevap yazmak nasıl? . Bu verilen cevap doğru olabilir, ancak bir açıklamadan yararlanabilir. Yalnızca kod yanıtları "iyi" yanıtlar olarak değerlendirilmez. Gönderen inceleme .
Trenton McKinney

-1

Kullanmayı deneyin:

int(val) == val

Diğer yöntemlerden çok daha fazla hassasiyet verecektir.


"Çok daha fazla hassasiyet verecek" iddiasını desteklemek için bir örnek verebilir misiniz? Bu asılsız görünüyor.
Mark Dickinson

-1

roundDeğeri hesaplamak için işlevi kullanabilirsiniz .

Evet, bir küp kökü değerini hesaplarken birçok kişinin işaret ettiği gibi, python'da size biraz hata içeren bir çıktı verecektir. Değerin bir tam sayı olup olmadığını kontrol etmek için aşağıdaki işlevi kullanabilirsiniz:

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

Ama bunun int(n)eşdeğer olduğunu unutmayın math.floorve bu nedenle int(41063625**(1.0/3.0))345 yerine 344 alacaksınız.

intKüp kökleri kullanırken lütfen dikkatli olun .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.