Jak sprawdzić, czy liczba zmiennoprzecinkowa jest liczbą całkowitą

202

Próbuję znaleźć największy pierwiastek kostki, który jest liczbą całkowitą, czyli mniej niż 12 000.

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

Nie jestem jednak pewien, jak sprawdzić, czy jest to liczba całkowita, czy nie! Mógłbym przekonwertować go na ciąg, a następnie użyć indeksowania, aby sprawdzić wartości końcowe i sprawdzić, czy są one zerowe, czy nie, co wydaje się dość kłopotliwe. Czy istnieje prostszy sposób?

chopper draw lion4
źródło
3
ułatwiłoby to pracę z katalogu głównego n -> (n * n * n <12000)
podejrzenie

Odpowiedzi:

366

Aby sprawdzić, czy liczba zmiennoprzecinkowa jest liczbą całkowitą, użyj float.is_integer()metody :

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

Metodę dodano do floattypu w Pythonie 2.6.

Weź pod uwagę, że w Pythonie 2 1/3jest 0(dzielenie podłogi dla argumentów całkowitych!), A arytmetyka zmiennoprzecinkowa może być nieprecyzyjna (a floatjest przybliżeniem przy użyciu ułamków binarnych, a nie dokładną liczbą rzeczywistą). Ale nieznaczne dostosowanie pętli daje:

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

co oznacza, że ​​cokolwiek powyżej 3 kostek (w tym 10648) zostało pominięte z powodu wyżej wspomnianej niedokładności:

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

Zamiast tego musisz sprawdzić liczby zbliżone do całego numeru lub nie użyć go float()do znalezienia swojego numeru. Jak zaokrąglenie w dół pierwiastka z 12000:

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

Jeśli używasz języka Python 3.5 lub nowszego, możesz użyć tej math.isclose()funkcji, aby sprawdzić, czy wartość zmiennoprzecinkowa mieści się w konfigurowalnym marginesie:

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

W starszych wersjach naiwna implementacja tej funkcji (pomijanie sprawdzania błędów i ignorowanie nieskończoności i NaN), jak wspomniano w 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)
Martijn Pieters
źródło
Nie znając pytona, tego rodzaju stwierdzenie denerwuje mnie, ponieważ wydaje się, że wymaga idealnej matematyki do pracy w prawdziwym świecie.
Peter M
1
@PeterM: Metoda rzeczywiście zwraca tylko Truewtedy, gdy nie ma żadnych miejsc po przecinku. Oczywiście może wystąpić nieporozumienie dotyczące arytmetyki zmiennoprzecinkowej i precyzji.
Martijn Pieters
1
@MartijnPieters Tak i jeden mały poślizg w obliczeniach zmiennoprzecinkowych i nagle masz te małe, niechciane miejsca po przecinku, takie jak 0,00000000000000000001
Peter M
1
@PeterM: aw Pythonie 2 domyślna reprezentacja zaokrągli się do 16 cyfr; 1.0000000000000001jest wyświetlany jako 1.0, w 3 pokazano najkrótszą reprezentację ciągu, która daje tę samą wartość.
Martijn Pieters
Twój range(12000, -1, -1)może być (imo, bardziej czysto) przepisany jakoreversed(range(12000+1))
CS95
36

Możemy użyć operatora modulo (%). To pokazuje nam, ile mamy resztek, gdy podzielimy x przez y - wyraża się jako x % y. Każda liczba całkowita musi się dzielić przez 1, więc jeśli pozostała liczba nie może być liczbą całkowitą.

Ta funkcja zwróci wartość logiczną Truelub False, w zależności od tego, czy njest liczbą całkowitą.

def is_whole(n):
    return n % 1 == 0
MagikCow
źródło
15

Możesz użyć tego:

if k == int(k):
    print(str(k) + " is a whole number!")
Juri Robl
źródło
5
nie działa w przypadku większych liczb, a .is_integer()nadal działa.
jfs
Twój link IMHO nie pokazuje, że to nie działa. To po prostu pokazuje, że duże pływaki tracą precyzję. is_integerużywa podobnej metody ( o = (floor(x) == x) ? Py_True : Py_False;). Ale zgadzam się, że należy używać, is_integer()ponieważ jest to o wiele wyraźniejsze.
Juri Robl,
1
tak. To po prostu pokazuje, że duży pływak może stracić precyzję, tzn. large_float == large_intMoże zawieść, nawet jeśli large_float == float(large_int).
jfs
2
123456789012345678901234567890.0 != 123456789012345678901234567890ale123456789012345678901234567890.0 == float(123456789012345678901234567890)
jfs,
2
Tak, ale k = 123456789012345678901234567890.0wtedy k == int(k)jest Prawda, która jest poprawną odpowiedzią.
Juri Robl,
9

Nie musisz niczego zapętlać ani sprawdzać. Wystarczy wziąć pierwiastek kostki z 12 000 i zaokrąglić w dół:

r = int(12000**(1/3.0))
print r*r*r # 10648
Georg
źródło
To rozsądna odpowiedź.
hughdbrown
7

Możesz do tego użyć operacji modulo .

if (n ** (1.0/3)) % 1 != 0:
    print("We have a decimal number here!")
Jakub Jirutka
źródło
2
jeśli njest 6.2, 6.0, 6.12312412, wszyscy mamy "We have a decimal number here!"?
Jay Wong
@JayWong nie jestem pewien, jak załadowałeś swój test, ale działa to dobrze na mojej maszynie przy użyciu Python3.7.
Zchpyvr
6

Czy nie byłoby łatwiej przetestować pierwiastki sześcianu? Zacznij od 20 (20 ** 3 = 8000) i idź do 30 (30 ** 3 = 27000). Następnie musisz przetestować mniej niż 10 liczb całkowitych.

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
Hughdbrown
źródło
1
Ponadto zmiennoprzecinkowe mają błędy zaokrąglania, dzięki czemu można pominąć liczbę przy obliczaniu n**(1/3)liczby całkowitej. Na przykład na moim komputerze `10648 ** (1/3) = 21.99999999999999996` zamiast 22: problem! Przy metodzie tej odpowiedzi nie ma takiego problemu. Myślę, że jest to jedyne poprawne rozwiązanie z matematycznego punktu widzenia (inne rozwiązania są poprawne w języku Python).
JPG
5

Co powiesz na

if x%1==0:
    print "is integer"
Daniel
źródło
3

Powyższe odpowiedzi działają w wielu przypadkach, ale niektóre pomijają. Rozważ następujące:

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

Wykorzystując to jako punkt odniesienia, niektóre inne sugestie nie zachowują się tak, jak byśmy chcieli:

fl.is_integer() # False

fl % 1 == 0     # False

Zamiast tego spróbuj:

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

teraz otrzymujemy:

is_integer(fl)   # True

isclosepochodzi z Python 3.5+ , a dla innych Pythona możesz użyć tej w większości równoważnej definicji (jak wspomniano w odpowiednim PEP )

control_fd
źródło
1
math.fsum([0.1] * 10) == 1
Acumenus
1

Po prostu informacje dodatkowe, is_integerrobi wewnętrznie:

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

Nie do końca w pythonie, ale implementacja cpython jest implementowana jak wspomniano powyżej.

użytkownik1767754
źródło
1

Wszystkie odpowiedzi są dobre, ale pewna byłaby metoda ognia

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

Funkcja zwraca wartość Prawda, jeśli jest liczbą całkowitą. Fałsz .... Wiem, że jestem trochę spóźniony, ale oto jedna z interesujących metod, które zrobiłem ...

Edycja: jak stwierdzono w komentarzu poniżej, tańszym równoważnym testem byłoby:

def whole(n):
    return n%1==0
random_npc
źródło
1
To nie powinno funkcjonalnie różnić się od n % 1 == 0. W takim przypadku wykonujesz dwie operacje, które są droższe w przypadku tańszego równoważnego testu.
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
>>>
csaszizoltan
źródło
Oto kilka wskazówek, jak napisać dobrą odpowiedź? . Ta podana odpowiedź może być poprawna, ale może przydać się wyjaśnienie. Odpowiedzi tylko w kodzie nie są uważane za „dobre”. Z przeglądu .
Trenton McKinney
-1

Spróbuj użyć:

int(val) == val

Zapewni znacznie większą precyzję niż jakiekolwiek inne metody.

Nishant Ingle
źródło
Czy możesz podać przykład na poparcie twierdzenia, że ​​„da dużo więcej precyzji”? To wydaje się nieuzasadnione.
Mark Dickinson
-1

Możesz użyć round funkcji do obliczenia wartości.

Tak w pythonie, jak wielu wskazywało, gdy obliczamy wartość pierwiastka kostki, da to wynik z niewielkim błędem. Aby sprawdzić, czy wartość jest liczbą całkowitą, możesz użyć następującej funkcji:

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

Pamiętaj jednak, że int(n)jest to równoważne math.floorz tego powodu, jeśli znajdzieszint(41063625**(1.0/3.0)) 344 zamiast 345.

Dlatego należy zachować ostrożność, używając intkorzeni sześcianu.

Anivarth
źródło