2016-07-04 13 views
1

Für den folgenden Code:Gleitkommakonstante

#include<stdio.h> 

int main() 
{ 
    float a = 0.7; 
    printf("%.10f %.10f\n", 0.7f, a); 
    return 0; 
} 

Der Ausgang ich erhalte, ist:

0,7000000000 0,6999999881

Bitte erklären, warum a als 0.6999999881 während die wörtliche konstant gedruckt wird wird gedruckt als 0.7000000000?

Ist die Verwendung einer Gleitkommazahl in diesem Fall vom Compiler abhängig?

+0

@LPs: das dachte ich auch zuerst, aber es gibt eine interessantere Frage, warum wird die wörtliche Konstante '0.7f' genau gedruckt? Wählen, um wieder zu öffnen. –

+0

YMMV: Dies druckt '0.6999999881 0.6999999881' auf meinem Rechner und auf anderen habe ich Zugriff auf. Was auch immer Ihre Compiler/C-Bibliothek mag, es ist nicht portabel. – dhke

+0

Es muss etwas mit der Umwandlung in "double" zu tun haben, die für variable Argumentfunktionen passiert. Welchen Compiler benutzen Sie? Welche Version davon? –

Antwort

4

obtaining „0,7000000000“, wie der String für printf("%.10f",0.7f) gedruckt ist normal, wenn der Compiler FLT_EVAL_METHOD als 1 oder 2.

Tatsächlich definiert, in diesem Modus kann Gleitkommakonstanten mit einer Genauigkeit dargestellt wird, dass die beyond ihr Typ (C11 5.2.4.2.2: 9):

Außer für die Zuordnung und gegossen (die alles zusätzliche Reichweite und Präzision zu entfernen), die von den Betreibern mit schwimmendem Operanden ergaben Werte und Werte an die üblichen arithmetischen Umwandlungen unterliegen und von floating Konstanten werden zu einem Format ausgewertet, dessen Bereich und Genauigkeit größer sein können als vom Typ gefordert.

Mit anderen Worten, das Drucken 0.7000000000 0.6999999881 FLT_EVAL_METHOD=2is one possible behavior für das modifizierte unten Programm.

#include<stdio.h> 
#include <float.h> 

int main() 
{ 
    float a=0.7; 
    printf("%.10f %.10f FLT_EVAL_METHOD=%d\n",0.7f, a, (int)FLT_EVAL_METHOD); 
    return 0; 
} 

Da der Compiler definiert FLT_EVAL_METHOD zu 2, printf("%.10f %.10f", 0.7f, 0.7) behandelt wird, als ob es printf("%.10f %.10f", (double)0.7L, (double)0.7L) war. In ähnlicher Weise entspricht printf("%.60Lf %.60Lf\n", (long double)0.7f, (long double)0.7)printf("%.60Lf %.60Lf\n", 0.7L, 0.7L).

+0

Was ist der Unterschied zwischen Double und Long Float? –

+0

@PaulStelian gibt es keine "long float" in C. Es gibt einen "long double" -Typ, der auf einigen Plattformen gleich "double" ist und dem 80-Bit IEEE 754-ähnlichen Format zugeordnet ist, das ursprünglich im 8087 implementiert wurde Dies ist die Darstellung, die für alle Konstanten und Zwischen-Fließkomma-Ergebnisse im Compiler von ideone.com verwendet wird. –

+0

Nun, das "% Lf" Ding hat mich verwirrt, deshalb. Die CPU-Register in einer FPU (ich bin nicht sicher, wie die SSE-Implementierung funktioniert) wäre 80-Bit tatsächlich. –

0

Der Grund, warum Sie unterschiedliche Werte erhalten, ist, dass, wie Sie printf(3) sind vorbei als einen ungeprüften Parameter (die eine Vararg Funktion ist), der Compiler tut eine Besetzung zu (double) (und eine Optimierung i vermute ich) Umwandeln die 0.7f Literal ein 0.7Dbevor es printf vorbei, so Sie übergeben tatsächlich zwei verschiedene Werte printf, ist die erste (double)0.7f, und der zweite ist der gespeicherte Wert der variablen a, umgerechnet auf ein (double).