Prüfen, ob Float eine ganze Zahl ist

Lesezeit: 7 Minuten

Benutzeravatar von sidyll
sidyll

Wie kann ich überprüfen, ob a float Variable enthält einen ganzzahligen Wert? Bisher habe ich verwendet:

float f = 4.5886;
if (f-(int)f == 0)
     printf("yes\n");
else printf("no\n");

Aber ich frage mich, ob es eine bessere Lösung gibt oder ob diese irgendwelche (oder viele) Nachteile hat.

  • Ihre Methode schlägt fehl, wenn die Zahl größer als der maximal zulässige ganzzahlige Wert ist.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:08 Uhr

  • Siehe meine Antwort, um das Problem mit dem Ansatz von OP zu beheben.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. April 2011 um 22:13 Uhr

  • Sicherlich ist die richtige Antwort: Sie stellen die falsche Frage.

    – Johannes Marshall

    27. April 2011 um 1:32 Uhr

  • @John Marshall: Also, was wäre die richtige Frage?

    – Sidyl

    28. April 2011 um 0:00 Uhr

  • Nun, was versuchst du zu tun? Wenn Sie einen Wert in a speichern float, vermutlich liegt es daran, dass Sie Gleitkommaarithmetik darauf ausführen möchten. Dann lautet Ihre Frage: Hat diese Variable, deren Wert in domänenspezifischer Weise und in einer Weise, die davon abhängt, wie sorgfältig Sie die Arithmetik durchführen, etwas schwammig ist, einen Wert, der schwammig ganzzahlig ist? Um das sinnvoll zu beantworten, müssen Sie die domänenspezifische Flauschigkeit berücksichtigen. Oder anders ausgedrückt: Was ist dieses Szenario, in dem der richtige Ansatz darin besteht, Ihren Wert nicht in einem zu speichern? int in der passenden Größe?

    – Johannes Marshall

    28. April 2011 um 13:47 Uhr

Marc Mutz - Benutzeravatar von mmutz
Marc Mutz – mmutz

Abgesehen von den bereits gegebenen feinen Antworten können Sie auch verwenden ceilf(f) == f oder floorf(f) == f. Beide Ausdrücke werden zurückgegeben true wenn f ist eine ganze Zahl. Sie kehren auch zurückfalse für NaNs (NaNs vergleichen immer ungleich) und true für ±unendlich, und haben kein Problem mit dem Überlaufen des Integer-Typs, der zum Speichern des abgeschnittenen Ergebnisses verwendet wird, weil floorf()/ceilf() Rückkehr floats.

  • Nun, das verfehlt den Zweck. Was ich möchte, ist zu überprüfen, ob der Float eine ganze Zahl ist, wie der Titel sagt; und nicht runden. Im letzteren Fall hätte ich immer eine Ganzzahl. Aber danke auch für den Hinweis.

    – Sidyl

    28. April 2011 um 0:03 Uhr

  • @sidyll: beide Ausdrücke runden fja, aber sie tun es, um es zu tun überprüfen ob es eine ganze Zahl ist.

    – Marc Mutz – mmutz

    28. April 2011 um 5:20 Uhr

  • @sidyll: genauer gesagt: achte darauf, wie das Ergebnis der Rundungsoperation wiederum im Vergleich ist fich habe meine Antwort bearbeitet, um dies klarer zu machen, danke.

    – Marc Mutz – mmutz

    28. April 2011 um 5:28 Uhr

  • Während dies funktioniert, ceilf und floorf sind unnötig teure Operationen auf zumindest einigen Bögen (hauptsächlich x86) aufgrund der Notwendigkeit, den Rundungsmodus zu ändern und wiederherzustellen. Ein schnellerer Test wäre rintf(f)==f. Mit -fno-math-errnoGCC wird kompiliert rintf zu einer einzelnen Inline-Anweisung.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    12. Juni 2013 um 18:37 Uhr

  • @R .. Gehe ich richtig in der Annahme nearbyintf wird dasselbe tun, ohne die Ausnahme noch Flagge?

    – Slipp D. Thompson

    1. Mai 2014 um 4:39 Uhr

Benutzeravatar von Jason C
Jason C

Denken Sie daran, dass die meisten Techniken hier gültig sind, vorausgesetzt, dass Rundungsfehler aufgrund früherer Berechnungen kein Faktor sind. Bsp du könnte verwenden roundfso was:

float z = 1.0f;

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Das Problem mit dieser und anderen ähnlichen Techniken (wie z ceilfGießen zu long, usw.) ist, dass sie zwar hervorragend für ganzzahlige Konstanten funktionieren, aber fehlschlagen, wenn die Zahl das Ergebnis einer Berechnung ist, bei der ein Gleitkomma-Rundungsfehler aufgetreten ist. Zum Beispiel:

float z = powf(powf(3.0f, 0.05f), 20.0f);

if (roundf(z) == z) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Gibt „Bruch“ aus, obwohl (31/20)20 sollte gleich 3 sein, denn das eigentliche Berechnungsergebnis war 2.9999992847442626953125.

Jede ähnliche Methode, sei es fmodf oder was auch immer, unterliegt diesem. In Anwendungen, die komplexe oder rundungsanfällige Berechnungen durchführen, möchten Sie normalerweise einen “Toleranzwert” für das definieren, was eine “ganze Zahl” ausmacht (dies gilt im Allgemeinen für Gleitkommagleichheitsvergleiche). Wir nennen das oft Toleranz Epsilon. Nehmen wir zum Beispiel an, dass wir dem Computer einen Rundungsfehler von bis zu +/- 0,00001 verzeihen. Dann, wenn wir testen zkönnen wir ein Epsilon von 0,00001 wählen und tun:

if (fabsf(roundf(z) - z) <= 0.00001f) {
    printf("integer\n");
} else {
    printf("fraction\n");
}

Sie möchten nicht wirklich verwenden ceilf hier weil zB ceilf(1.0000001) ist 2 nicht 1, und ceilf(-1.99999999) ist -1 nicht -2.

Du könntest benutzen rintf anstelle von roundf wenn Sie es vorziehen.

Wählen Sie einen Toleranzwert, der für Ihre Anwendung geeignet ist (und ja, manchmal ist eine Nulltoleranz angemessen). Weitere Informationen finden Sie in diesem Artikel auf Gleitkommazahlen vergleichen.

if (fmod(f, 1) == 0.0) {
  ...
}

Nicht vergessen math.h und libm.

  • Das funktioniert, aber im Prinzip fmod ist eine ziemlich teure Operation.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. April 2011 um 22:21 Uhr

stdlib float modf (float x, float *ipart) teilt sich in zwei Teile, prüfen Sie, ob der Rückgabewert (Bruchteil) == 0 ist.

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

if (f <= LONG_MIN || f >= LONG_MAX || f == (long)f) /* it's an integer */

  • Wenn sizeof(f) > sizeof(long) das könnte nicht halten.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:27 Uhr

  • Nur für den Fall, dass jemand diese Antwort findet und versucht, sie auf a anzuwenden double.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:34 Uhr

  • Guter Punkt. Zum double ich würde … benutzen long long und LLONG_MAX/LLONG_MIN.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. April 2011 um 22:35 Uhr

  • @mangledorf: Deine Transformation ist ungültig. (long)f ruft undefiniertes Verhalten auf, wenn der Wert nicht als darstellbar ist long. Also muss man sicherheitshalber erstmal vergleichen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    23. September 2014 um 1:29 Uhr

  • @EmileCormier: Als Zahl ist -1,1 * 10 ^ 20 sowieso eine ganze Zahl, also hast du wohl etwas anderes gemeint. Allerdings ist die Präzision von float ist so begrenzt, dass der nächste darstellbare Wert zu dieser Zahl -109999998686059298816 ist, was ebenfalls eine Ganzzahl ist. Seit float einen 24-Bit-Signifikanten hat, hat jeder Wert mit einer Größe von mindestens 2^24 keine Signifikantenbits nach dem Basispunkt. C erfordert long mindestens 32 Bit sein, also Werte größer als LONG_MAX oder weniger als LONG_MIN liegen weit außerhalb dieses Bereichs.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    12. Januar 2020 um 0:04 Uhr

Benutzeravatar von Jiminion
Jiminion

Dies betrifft die rechnerische Rundung. Sie stellen das Epsilon wie gewünscht ein:

bool IsInteger(float value)
{
    return fabs(ceilf(value) - value) < EPSILON;
}

  • Wenn sizeof(f) > sizeof(long) das könnte nicht halten.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:27 Uhr

  • Nur für den Fall, dass jemand diese Antwort findet und versucht, sie auf a anzuwenden double.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:34 Uhr

  • Guter Punkt. Zum double ich würde … benutzen long long und LLONG_MAX/LLONG_MIN.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. April 2011 um 22:35 Uhr

  • @mangledorf: Deine Transformation ist ungültig. (long)f ruft undefiniertes Verhalten auf, wenn der Wert nicht als darstellbar ist long. Also muss man sicherheitshalber erstmal vergleichen.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    23. September 2014 um 1:29 Uhr

  • @EmileCormier: Als Zahl ist -1,1 * 10 ^ 20 sowieso eine ganze Zahl, also hast du wohl etwas anderes gemeint. Allerdings ist die Präzision von float ist so begrenzt, dass der nächste darstellbare Wert zu dieser Zahl -109999998686059298816 ist, was ebenfalls eine Ganzzahl ist. Seit float einen 24-Bit-Signifikanten hat, hat jeder Wert mit einer Größe von mindestens 2^24 keine Signifikantenbits nach dem Basispunkt. C verlangt long mindestens 32 Bit sein, also Werte größer als LONG_MAX oder weniger als LONG_MIN liegen weit außerhalb dieses Bereichs.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    12. Januar 2020 um 0:04 Uhr

Benutzeravatar von Controllerface
Controllerface

Ich bin mir nicht 100% sicher, aber wenn Sie f in ein int umwandeln und es von f subtrahieren, glaube ich, dass es in einen Float zurückgeworfen wird. Dies wird in diesem Fall wahrscheinlich keine Rolle spielen, aber es könnte später zu Problemen führen, wenn Sie aus irgendeinem Grund erwarten, dass dies ein Int ist.

Ich weiß nicht, ob es an sich eine bessere Lösung ist, aber Sie könnten stattdessen Modulus-Mathematik verwenden, zum Beispiel:

float f = 4.5886;
bool isInt;
isInt = (f % 1.0 != 0) ? false : true;

Abhängig von Ihrem Compiler benötigen Sie möglicherweise die .0 nach der 1, auch hier kommt die ganze Sache mit impliziten Umwandlungen ins Spiel. In diesem Code sollte der boolsche isInt wahr sein, wenn rechts vom Dezimalkomma nur Nullen sind, andernfalls falsch.

  • Das % Der Operator funktioniert nur mit ganzen Zahlen. Sie haben jedoch Recht damit, dass int in einen Float zurückgeworfen wird.

    – Markieren Sie Lösegeld

    26. April 2011 um 22:41 Uhr


  • Mein Fehler, ich hätte stattdessen (fmod(f , 1.0) != 0) verwenden sollen.

    – Controllerface

    27. April 2011 um 13:09 Uhr

  • Ja, ich bin mir bewusst, dass es als Float bleiben wird, aber ich möchte es nur überprüfen.

    – Sidyl

    28. April 2011 um 0:05 Uhr

  • kompiliert nicht auf gcc

    – Weima

    26. September 2018 um 13:55 Uhr

1419290cookie-checkPrüfen, ob Float eine ganze Zahl ist

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy