Warum pow(10,5) = 9.999 in C++

Lesezeit: 5 Minuten

Warum pow105 9999 in C
Eisvogel Phuoc

Kürzlich habe ich einen Codeblock geschrieben:

const int sections = 10;

for(int t= 0; t < 5; t++){
   int i = pow(sections, 5- t -1);  
   cout << i << endl;
}

Und das Ergebnis ist falsch:

9999
1000
99
10
1

Wenn ich nur diesen Code verwende:

for(int t = 0; t < 5; t++){
    cout << pow(sections,5-t-1) << endl; 
}

Das Problem tritt nicht mehr auf:

10000
1000
100
10
1

Gibt mir jemand eine Erklärung? Vielen Dank!

  • Welche Art ist sectionsund wie wird es initialisiert?

    – pmdj

    14. März 2012 um 14:49 Uhr

Warum pow105 9999 in C
Taskinoor

Aufgrund der Darstellung von Fließkommawerten pow(10.0, 5) könnte 9999,9999999 oder so ähnlich sein. Wenn Sie das einer Ganzzahl zuweisen, die abgeschnitten wurde.

EDIT: Im Falle von cout << pow(10.0, 5); Es sieht so aus, als wäre die Ausgabe gerundet, aber ich habe derzeit kein unterstützendes Dokument, das dies bestätigt.

EDIT 2: Der Kommentar von BoBTFish und diese Frage bestätigen das wann pow(10.0, 5) wird direkt in verwendet cout das wird rund.

  • Dies erklärt nicht, warum beim direkten Drucken nicht 9999,9999999 gedruckt wird

    – Luchian Grigore

    14. März 2012 um 14:50 Uhr

  • @Luchian Grigore, ist es möglich, dass es in diesem Fall rund wird? Diese Erklärung würde ich auch gerne hören.

    – Taskinoor

    14. März 2012 um 14:52 Uhr

  • Wenn die Standardgenauigkeit kleiner als die Anzahl der Dezimalstellen ist, wird gerundet.

    – BoBTFisch

    14. März 2012 um 15:01 Uhr

  • @Kingfisher, auf meiner Maschine int i = pow(10, 5) ergibt 10000, aber pow(10.0, 5) nicht. Sieht aus wie sections ist doppelt in Ihrem Code. Wenn Sie wirklich brauchen sections dann doppelt zu sein, anstatt es zuzuweisen i Sie müssen die Leistung runden.

    – Taskinoor

    14. März 2012 um 15:10 Uhr

  • std::cout rundet Floats auf eine bestimmte Anzahl signifikanter Stellen, die mit geändert werden können std::setprecision Manipulator. Also, wenn Sie versuchen, auszugeben 99.9999 (was eigentlich die engste Annäherung an das ist, was es schaffen kann, nicht die genaue Zahl) mit einer Genauigkeit von sagen wir 4, die Rundung “trägt die 1” ganz nach oben und druckt 100.

    – BoBTFisch

    14. März 2012 um 15:13 Uhr

Bei Verwendung mit Bruchexponenten wird pow(x,y) üblicherweise als ausgewertet exp(log(x)*y); Eine solche Formel würde mathematisch korrekt sein, wenn sie mit unendlicher Genauigkeit ausgewertet würde, kann jedoch in der Praxis zu Rundungsfehlern führen. Wie andere angemerkt haben, ergibt ein Wert von 9999,999999999, wenn er in eine Ganzzahl umgewandelt wird, 9999. Einige Sprachen und Bibliotheken verwenden eine solche Formulierung ständig, wenn sie einen Potenzierungsoperator mit einem Gleitkommaexponenten verwenden; andere versuchen zu erkennen, wann der Exponent eine ganze Zahl ist, und verwenden gegebenenfalls eine iterative Multiplikation. Suche nach Dokumentation für die pow Funktion, es scheint, dass es funktionieren soll, wenn x ist negativ und y hat keinen Bruchteil (wenn x ist negativ und `y gleichmäßig ist, sollte das Ergebnis sein pow(-x,y); wann y ungerade ist, sollte das Ergebnis sein -pow(-x,y). Es erscheint logisch, wann y hat keinen Bruchteil einer Bibliothek, die sich die Mühe machen wird, mit einem Negativ umzugehen x value sollte iterierte Multiplikation verwenden, aber ich kenne keine Spezifikation, die dies vorschreibt.

Wenn Sie versuchen, eine Ganzzahl zu potenzieren, ist es auf jeden Fall am besten, Ganzzahlmathematik für die Berechnung zu verwenden, oder, wenn die zu potenzierende Ganzzahl eine Konstante oder immer klein ist, einfach eine Nachschlagetabelle zu verwenden (Das Erhöhen von Zahlen von 0 bis 15 um eine Potenz, die in eine 64-Bit-Ganzzahl passen würde, würde nur eine Tabelle mit 4.096 Elementen erfordern).

Warum pow105 9999 in C
Aleeee

Von Hier

Mit Blick auf die pow() Funktion: double pow (double base, double exponent); Wir wissen, dass die Parameter und der Rückgabewert alle sind double Art. Aber die Variable num, i und res sind alle int Geben Sie den obigen Code ein, wenn Sie ihn transformieren int zu double oder double zu int, kann es zu Präzisionsverlusten kommen. Zum Beispiel (vielleicht nicht streng) die Gleitkommaeinheit (FPU) berechnen pow(10, 4)=9999.99999999dann int(9999.9999999)=9999 durch Typtransformation in C++.

Wie man es löst?

Lösung1

Ändern Sie den Code:

    const int num = 10;

    for(int i = 0; i < 5; ++i){
       double res = pow(num, i);
       cout << res << endl;
    }

Lösung2

Ersetzen Sie die Gleitkommaeinheit (FPU) mit höherer Rechengenauigkeit in double Art. Zum Beispiel verwenden wir SSE in der Windows-CPU. In Code::Block 13.12 können wir diese Schritte ausführen, um das Ziel zu erreichen: Setting -> Compiler setting -> GNU GCC Compile -> Other options, add

-mfpmath=sse -msse3

Das Bild ist wie folgt:

1647138008 597 Warum pow105 9999 in C-mfpmath=sse -msse3 hinzu”>
(Quelle: qiniudn.com)

Was passiert, ist, dass die pow-Funktion ein Double zurückgibt, wenn Sie dies tun

int i = pow(sections, 5- t -1);  

die Dezimalzahl .99999 schneidet ab und Sie erhalten 9999.

beim direkten Drucken oder Vergleichen mit 10000 ist kein Problem, weil es in gewissem Sinne rund ist.

Wenn der Code in Ihrem ersten Beispiel genau der Code ist, den Sie ausführen, dann haben Sie eine fehlerhafte Bibliothek. Egal ob Sie abheben std::pow oder Cs pow was Doubles nimmt, auch wenn die Double-Version gewählt wird, ist 10 genau als a darstellbar double. Damit ist die Potenzierung exakt als a darstellbar double. Es darf keine Rundung oder Kürzung oder ähnliches auftreten.

Mit g ++ 4.5 konnte ich Ihr (seltsames) Verhalten nicht einmal mit reproduzieren -ffast-math und -O3.

Was ich jetzt vermute, ist das sections ist nicht dem Literal 10 direkt zugewiesen wird, aber stattdessen intern gelesen oder berechnet wird, so dass sein Wert etwa so ist 9.9999999999999die in die vierte Potenz erhoben eine Zahl wie erzeugt 9999.9999999. Dies wird dann auf die angezeigte Ganzzahl 9999 gekürzt.

Abhängig von Ihren Anforderungen möchten Sie möglicherweise entweder die Quellzahl oder die endgültige Zahl vor der Zuweisung in eine Ganzzahl runden. Zum Beispiel: int i = pow(sections, 5- t -1) + 0.5; // Add 0.5 and truncate to round to nearest.

1647138009 723 Warum pow105 9999 in C
Leichtigkeitsrennen im Orbit

Da muss was kaputt sein pow Funktion im globalen Namensraum. Dann std::pow wird stattdessen in Ihrem zweiten Beispiel wegen ADL “automatisch” verwendet.

Entweder das oder t ist in Ihrem ersten Beispiel tatsächlich eine Gleitkommazahl, und Sie stoßen auf Rundungsfehler.

1647138010 970 Warum pow105 9999 in C
Charly Martin

Sie weisen das Ergebnis einem int zu. Das erzwingt es und schneidet die Nummer ab.

Das sollte gut funktionieren:

for(int t= 0; t < 5; t++){
   double i = pow(sections, 5- t -1);  
   cout << i << endl;
}

995680cookie-checkWarum pow(10,5) = 9.999 in C++

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

Privacy policy