Ich kann die Ergebnisse auf meinem gcc (Ubuntu 5.2.1-22ubuntu2) bestätigen. Was zu passieren scheint ist, dass der 32-Bit nicht optimierte Code 387 FPU mit FMUL
Opcode verwendet, während 64-Bit den SSE MULS
Opcode verwendet. (Führen Sie einfach gcc -S test.c
mit verschiedenen Parametern aus und sehen Sie den Assembler-Ausgang). Und wie bekannt ist, hat die 387 FPU, die die FMUL
ausführt, mehr als 64 Bits Präzision (80!), So scheint es, dass es hier anders Runden. Der Grund ist natürlich, dass der genaue Wert von 64-Bit-IEEE Doppel 210.01
ist das nicht, aber
210.009999999999990905052982270717620849609375
und wenn man mit 1000 multiplizieren, sind Sie eigentlich nicht nur die Dezimalpunkt Verschiebung - schließlich gibt ist kein Dezimalpunkt, sondern Binärpunkt im Fließkommawert; Also muss der Wert gerundet werden. Und bei 64-Bit-Doppel ist es aufgerundet. Bei 80-Bit-387-FPU-Registern ist die Berechnung präziser und es wird abgerundet down.
Nachdem ich etwas mehr gelesen habe, glaube ich, dass das Ergebnis, das von GCC auf 32-Bit-Arch erzeugt wird, nicht standardkonform ist. Wenn Sie also den Standard zu C99 oder C11 zwingen, mit -std=c99
, -std=c11
, erhalten Sie das richtige Ergebnis
% gcc -m32 -std=c11 test.c; ./a.out
210010
Wenn Sie wollen nicht mit Gewalt C99 oder C11-Standard, können Sie auch den -fexcess-precision=standard
Schalter verwenden.
Aber Spaß hört hier nicht auf.
% gcc -m32 test.c; ./a.out
210009
% gcc -m32 -O3 test.c; ./a.out
210010
So erhalten Sie die "richtige" führen, wenn Sie mit -O3
kompilieren; Das liegt natürlich daran, dass der 64-Bit-Compiler die 64-Bit-SSE-Mathematik verwendet, um die Berechnung konstant zu falten.
Um die zusätzliche Genauigkeit wirkt sich dies zu bestätigen, Sie ein long double
verwenden:
#include "stdio.h"
#include <stdint.h>
int main()
{
long double d1 = 210.01; // double constant to long double!
uint32_t m = 1000;
uint32_t v1 = (uint32_t) (d1 * m);
printf("%d",v1);
return 0;
}
Jetzt noch -m64
Runden es 210009.
% gcc -m64 test.c; ./a.out
210009
Wenn Sie gcc so nennen, es ist als C-Code kompiliert (was es zu sein scheint), nicht C++. Fügen Sie keine Tags für nicht verwandte Sprachen hinzu. – Olaf
@Olaf: Ok. Ich werde die Frage aktualisieren. Es tritt sowohl für den gcc- als auch für den g ++ - Compiler auf. Es ist also nicht spezifisch für c/C++. Vielen Dank! –
1) Mach das nicht zu einer C++ Frage! C und C++ sind ** verschiedene ** Sprachen. 1a) Sie sollten anderen Code in C++ mit Iostreams und C++ Cast-Operatoren verwenden. 2) Sie verwenden den falschen Typ-Spezifizierer in der Formatzeichenfolge. Verwenden Sie 'inttypes.h' Makros, um eine Ganzzahl mit fester Breite zu drucken. – Olaf