So überprüfen Sie, ob ein Gleitkommawert eine ganze Zahl ist


200

Ich versuche, die größte Kubikwurzel zu finden, die eine ganze Zahl ist, also weniger als 12.000.

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

Ich bin mir nicht sicher, wie ich überprüfen soll, ob es sich um eine ganze Zahl handelt oder nicht! Ich könnte es in einen String konvertieren und dann mithilfe der Indizierung die Endwerte überprüfen und feststellen, ob sie Null sind oder nicht, was jedoch ziemlich umständlich erscheint. Gibt es einen einfacheren Weg?


3
es würde es einfacher machen, von der Kubikwurzel aus zu arbeiten n -> (n * n * n <12000)
verdächtiger

Antworten:


364

Verwenden Sie die folgende float.is_integer()Methode , um zu überprüfen, ob ein Gleitkommawert eine ganze Zahl ist :

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

Die Methode wurde dem floatTyp in Python 2.6 hinzugefügt .

Zu Berücksichtigen , dass in Python 2, 1/3ist 0(Bodenteilung für ganzzahlige Operanden!), Und daß Gleitpunktarithmetik kann ungenau sein (a floatist eine Annäherung Binärbrüche verwenden, nicht eine genaue reelle Zahl). Wenn Sie jedoch Ihre Schleife ein wenig anpassen, erhalten Sie Folgendes:

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

was bedeutet, dass alles über 3 Würfel (einschließlich 10648) aufgrund der oben genannten Ungenauigkeit verpasst wurde:

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

Sie müssten stattdessen nach Nummern suchen, die nahe an der gesamten Nummer liegen, oder sie nicht verwenden float(), um Ihre Nummer zu finden. Als würde man die Kubikwurzel abrunden von 12000:

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

Wenn Sie Python 3.5 oder höher verwenden, können Sie mit der math.isclose()Funktion feststellen , ob ein Gleitkommawert innerhalb eines konfigurierbaren Bereichs liegt:

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

Für ältere Versionen die naive Implementierung dieser Funktion (Überspringen der Fehlerprüfung und Ignorieren von Unendlichkeit und NaN), wie in PEP485 erwähnt :

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)

Wenn ich Python nicht kenne, würde mich diese Art von Aussage nervös machen, da es anscheinend perfekte Mathematik erfordert, um in der realen Welt zu arbeiten.
Peter M.

1
@PeterM: Die Methode gibt tatsächlich nur zurück, Truewenn überhaupt keine Dezimalstellen vorhanden sind. Natürlich kann es seitens des OP zu Missverständnissen hinsichtlich Gleitkomma-Arithmetik und Präzision kommen.
Martijn Pieters

1
@MartijnPieters Ja und ein kleiner Fehler in einer Gleitkommaberechnung, und plötzlich haben Sie diese kleinen, unerwünschten Dezimalstellen wie 0,00000000000000000001
Peter M.

1
@PeterM: In Python 2 wird die Standarddarstellung auf 16 Stellen gerundet. 1.0000000000000001wird angezeigt als 1.0, in 3 wird die kürzeste Zeichenfolgendarstellung angezeigt , die denselben Wert erzeugt.
Martijn Pieters

Ihr range(12000, -1, -1)könnte (imo, sauberer) umgeschrieben werden alsreversed(range(12000+1))
cs95

36

Wir können den Modulo (%) -Operator verwenden. Dies sagt uns, wie viele Reste wir haben, wenn wir x durch y teilen - ausgedrückt als x % y. Jede ganze Zahl muss durch 1 geteilt werden. Wenn es also einen Rest gibt, darf es keine ganze Zahl sein.

Diese Funktion gibt einen Booleschen Wert zurück Trueoder False, je nachdem, ob nes sich um eine ganze Zahl handelt.

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

15

Sie könnten dies verwenden:

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

5
Es schlägt bei größeren Zahlen fehl, während es .is_integer()weiter funktioniert.
JFS

Ihr Link zeigt meiner Meinung nach nicht, dass es nicht funktioniert. Es zeigt nur, dass große Schwimmer an Präzision verlieren. is_integerverwendet eine ähnliche Methode ( o = (floor(x) == x) ? Py_True : Py_False;). Aber ich stimme zu, man sollte es verwenden, is_integer()da es viel klarer ist.
Juri Robl

1
Ja. Es zeigt nur, dass ein großer Schwimmer an Präzision verlieren kann, dh large_float == large_intauch wenn er ausfällt large_float == float(large_int).
JFS

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

2
Ja, aber k = 123456789012345678901234567890.0dann k == int(k)ist es wahr, was die richtige Antwort ist.
Juri Robl

9

Sie müssen nichts schleifen oder überprüfen. Nehmen Sie einfach eine Kubikwurzel von 12.000 und runden Sie sie ab:

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

Dies ist eine vernünftige Antwort.
Hughdbrown

7

Sie können dafür eine Modulo- Operation verwenden.

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

2
Wenn n6.2, 6.0, 6.12312412 ist, haben wir alle "We have a decimal number here!"?
Jay Wong

@ JayWong nicht sicher, wie Sie Ihren Test geladen haben, aber dies funktioniert gut auf meinem Computer mit Python3.7.
Zchpyvr

6

Wäre es nicht einfacher, die Kubikwurzeln zu testen? Beginnen Sie mit 20 (20 ** 3 = 8000) und gehen Sie bis zu 30 (30 ** 3 = 27000). Dann müssen Sie weniger als 10 Ganzzahlen testen.

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
Darüber hinaus weisen Floats Rundungsfehler auf, sodass Sie bei der Berechnung der n**(1/3)Ganzzahl die Zahl übersehen können . Zum Beispiel auf meinem Computer `10648 ** (1/3) = 21.999999999999996` statt 22: Problem! Mit der Methode dieser Antwort gibt es kein solches Problem. Ich denke, dies ist aus mathematischer Sicht die einzig richtige Lösung (andere Lösungen sind Python-korrekt).
JPG


3

Die obigen Antworten funktionieren in vielen Fällen, aber sie vermissen einige. Folgendes berücksichtigen:

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

Wenn Sie dies als Benchmark verwenden, erhalten einige der anderen Vorschläge nicht das gewünschte Verhalten:

fl.is_integer() # False

fl % 1 == 0     # False

Versuchen Sie stattdessen:

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

jetzt bekommen wir:

is_integer(fl)   # True

isclosekommt mit Python 3.5+ und für andere Pythons können Sie diese meist äquivalente Definition verwenden (wie im entsprechenden PEP erwähnt ).


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

1

Nur eine Nebeninfo, is_integermacht intern:

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

Nicht genau in Python, aber die cpython-Implementierung wird wie oben erwähnt implementiert.


1

Alle Antworten sind gut, aber eine sichere Feuermethode wäre

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

Die Funktion gibt True zurück, wenn es sich um eine ganze Zahl handelt. False .... Ich weiß, dass ich etwas spät dran bin, aber hier ist eine der interessanten Methoden, die ich gemacht habe ...

Bearbeiten: Wie im Kommentar unten angegeben, wäre ein billigerer gleichwertiger Test:

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

1
Dies sollte funktional nicht anders sein als n % 1 == 0. In diesem Fall führen Sie zwei Operationen aus, die für einen günstigeren äquivalenten Test teurer sind.
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
>>>

Hier sind einige Richtlinien für Wie schreibe ich eine gute Antwort? . Diese Antwort mag richtig sein, könnte aber von einer Erklärung profitieren. Nur-Code-Antworten gelten nicht als "gute" Antworten. Aus der Überprüfung .
Trenton McKinney

-1

Versuchen Sie es mit:

int(val) == val

Es gibt viel mehr Präzision als alle anderen Methoden.


Können Sie ein Beispiel geben, um die Behauptung zu untermauern, dass "es viel mehr Präzision geben wird"? Dies scheint unbegründet.
Mark Dickinson

-1

Du kannst den ... benutzen round Funktion den Wert berechnen.

Ja, in Python haben viele darauf hingewiesen, dass wir bei der Berechnung des Werts einer Kubikwurzel eine Ausgabe mit ein wenig Fehler erhalten. Um zu überprüfen, ob der Wert eine ganze Zahl ist, können Sie die folgende Funktion verwenden:

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

Aber denken Sie daran, das int(n)ist gleichbedeutend mit math.floorund aus diesem Grund, wenn Sie die findenint(41063625**(1.0/3.0)) erhalten Sie 344 statt 345, .

intSeien Sie also bitte vorsichtig, wenn Sie mit den Kubikwurzeln arbeiten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.