2015-02-04 14 views
5

Ich bin neu in C, und wenn ich den Code ausführen, den Wert, ist löschte ist 12098 statt 12099.Umzug Dezimalstelle nach rechts in c

Ich bin mir bewusst, dass mit Dezimalzahlen arbeiten immer beinhaltet ein Grad an Ungenauigkeit, aber gibt es eine Möglichkeit, den Dezimalpunkt jedesmal genau nach zwei Stellen zu verschieben?

#include <stdio.h> 

int main(void) 
{ 
    int i; 
    float f = 120.99; 

    i = f * 100; 
    printf("%d", i); 
} 
+0

Versuchen Sie, diese 'float i, f = 120.99f;'. – haccks

+0

keine in Standard C++, Sie benötigen einen Dezimaltyp, wie http://sourceforge.net/projects/stddecimal/ – sp2danny

+0

Verwenden Sie 'ftoa()' und kopieren Sie jede Zahl in einen 'char' Puffer, wobei Sie das Dezimalzeichen über' überspringen isdigit() '. –

Antwort

0

Sie können

float f = 120.99f 

oder

double f = 120.99 

standardmäßig cspeicher Gleitkommawerte als doppelt so, wenn Sie sie speichern in float-Variable implizites Casting passiert ist, und es ist schlecht ...
ich denke, das funktioniert.

+0

Es findet kein Casting statt, wenn Sie einen "double" -Wert in einer "float" -Variablen speichern. Was passiert, ist eine implizite Konvertierung. –

+0

Float ist 32-Wert und Double ist 64-Bit-Wert und ihre Speicher-Algorithmus ist anders, so dass Gießen zwischen ihnen gefährlich ist. Sie können [Wikipeadia] (http://en.wikipedia.org/wiki/Floating_point) für Details sehen. –

+0

Bitte bringen Sie mir keine Fließkommazahlen bei. Mir sind die Unzulänglichkeiten beim Konvertieren zwischen FP-Nummern unterschiedlicher Genauigkeit durchaus bewusst. Ich bezog mich auf den falschen Wortlaut in Ihrer Antwort (ein "Cast" ist eine explizite Konvertierung per definitionem; daher kann eine implizite Konvertierung nicht als "Cast" bezeichnet werden.) –

5

Verwenden Sie die round Funktion

float f = 120.99; 
int i = round(f * 100.0); 

bewusst jedoch sein, dass ein float typischerweise nur 6 oder 7 Stellen der Präzision hat, so gibt es einen Maximalwert, wenn dies funktionieren wird. Der kleinste float Wert, der nicht richtig konvertiert wird, ist die Nummer 131072.01. Wenn Sie mit 100 multiplizieren und runden, wird das Ergebnis 13107202 sein.

Sie können den Bereich Ihrer Nummern erweitern, indem Sie double Werte verwenden, aber auch ein double hat eine begrenzte Reichweite. (A double hat 16 oder 17 Ziffern der Präzision.) Zum Beispiel wird der folgende Code 10000000000000098

double d = 100000000000000.99; 
uint64_t j = round(d * 100.0); 
printf("%llu\n", j); 

drucken, das nur ein Beispiel ist, finden die kleinste Zahl ist, dass die Genauigkeit eines double überschreitet, wird als Übung für den Leser.

4

Verwenden Festkommaarithmetik auf ganze Zahlen:

#include <stdio.h> 

#define abs(x) ((x)<0 ? -(x) : (x)) 

int main(void) 
{ 
    int d = 12099; 
    int i = d * 100; 
    printf("%d.%02d\n", d/100, abs(d)%100); 
    printf("%d.%02d\n", i/100, abs(i)%100); 
} 
1

Wenn Sie auf die Zahl als Gleitkommazahl fortsetzen möchte arbeiten, dann ist die Antwort mehr oder weniger kein. Es gibt verschiedene Dinge, die Sie für kleine Zahlen tun können, aber wenn Ihre Zahlen größer werden, werden Sie Probleme haben.

Wenn Sie nur die Zahl drucken möchten, dann wäre meine Empfehlung, die Zahl in eine Zeichenfolge zu konvertieren und dann den Dezimalpunkt dorthin zu verschieben. Dies kann etwas kompliziert sein, abhängig davon, wie Sie die Zahl in der Zeichenfolge darstellen (exponentiell und was nicht).

Wenn Sie möchten, dass dies funktioniert und es Ihnen nichts ausmacht, keine Fließkommazahl zu verwenden, dann würde ich Ihnen empfehlen, eine beliebige Anzahl fester dezimaler Bibliotheken zu recherchieren.

2

Ihr Problem ist, dass Float intern mit IEEE-754 dargestellt werden. Das ist in der Basis 2 und nicht in der Basis 10. 0.25 wird eine genaue Darstellung haben, aber 0.1 hat nicht, noch 120.99.

Was wirklich passiert ist, dass aufgrund Punktes inacuracy schwebend, die IEEE-754 auf den Dezimalwert schweben am nächsten 120.99 multipliziert mit 100 leicht unter 12099, so ist es abgeschnittene-12098. Ihr Compiler sollte Sie gewarnt haben, dass Sie eine Trunkierung von float zu (meins tat) hatten.

Die einzige harmlose Weise, was Sie zu bekommen erwarten ist, bevor das Abschneiden 0.5 mit dem Schwimmer hinzufügen int:

i = (f * 100) + 0.5 

Aber passen Gleitkomma von Natur aus ungenau sind, wenn Dezimalzahlen verarbeiten.

Edit:

Natürlich für negative Zahlen, sollte es i = (f * 100) - 0.5 ...

+0

@chux: Beitrag bearbeitet. Danke für die Präzision –

+0

Minor Punkt: "IEEE-754" spezifiziert sowohl Fließkomma binäre als auch Fließkomma-Dezimalformate, von denen Ihre Antwort auf den weit populäreren binären basiert. Dezimalformate waren in der Vergangenheit etwas populär und ich vermute, dass sie für genau diese Art von Problemen ein kleines Wiederaufleben haben werden. – chux

+0

@chux: Ich habe die Wikipedia-Seite zitiert, die aus diesem Grund mehr Details enthält. Aber wenn OP-System dezimale IEEE 754 verwenden würde, hätte es kein Problem gefunden :-) –