Cast to Int vs Floor

120

Gibt es einen Unterschied zwischen diesen:

float foo1 = (int)(bar / 3.0);
float foo2 = floor(bar / 3.0);

Soweit ich weiß, haben beide Fälle das gleiche Ergebnis. Gibt es einen Unterschied im kompilierten Code?

OgreSwamp
quelle
1
ein bisschen besser mit floor, aber Vorsicht, das ist doublenicht für float. C99 hat auch floorffür float.
Jens Gustedt
2
Sie haben also das gleiche Ergebnis, solange der Balken positiv ist
Zac
1
(Hinweis: in C ++ bitte #include<cmath>und verwenden std::floor)
user202729
Welcher Typ ist bar?
chux
@chux Egal, durch 3,0 teilen wird es sowieso doppelt
kaalus

Antworten:

193

Das Casting auf ein Int wird gegen Null abgeschnitten. floor()wird in Richtung negativ unendlich abschneiden. Dies gibt Ihnen unterschiedliche Werte, wenn barsie negativ waren.

James Curran
quelle
15
Ich denke, Sie haben hier den Nagel auf den Kopf getroffen. Ein weiterer Unterschied, wenn floor()die Absicht ist, ist, wenn der Wert von barzu groß ist, um in eine zu passen int.
Fred Larson
Haben Sie eine Quelle für diese Aussage?
Hallo Auf Wiedersehen
1
Selbst wenn das Ergebnis positiv ist, kann es nicht garantiert werden. Sehen Sie dies und das .
user202729
27

Wie bereits gesagt, sind sie für positive Zahlen gleich, unterscheiden sich jedoch für negative Zahlen. Die Regel ist, dass int gegen 0 rundet, während der Boden gegen negative Unendlichkeit rundet.

floor(4.5) = (int)4.5 = 4
floor(-4.5) = -5 
(int)(-4.5) = -4

Abgesehen davon gibt es auch einen Unterschied in der Ausführungszeit. Auf meinem System habe ich festgelegt, dass das Casting mindestens dreimal schneller ist als der Boden.

Ich habe Code, der den Bodenbetrieb eines begrenzten Wertebereichs einschließlich negativer Zahlen benötigt. Und es muss sehr effizient sein, deshalb verwenden wir die folgende Funktion dafür:

int int_floor(double x) 
{ 
    return (int)(x+100000) - 100000; 
}

Natürlich schlägt dies bei sehr großen Werten von x (bei einigen Überlaufproblemen) und bei negativen Werten unter -100000 usw. fehl. Aber ich habe es so getaktet, dass es mindestens dreimal schneller als der Boden ist, was sehr kritisch war für unsere Anwendung. Nehmen Sie es mit einem Körnchen Salz, testen Sie es auf Ihrem System usw., aber es lohnt sich, IMHO in Betracht zu ziehen.

brice rebsamen
quelle
"Ich habe es so getaktet, dass es mindestens dreimal schneller als der Boden ist" -> OP verwendet float, nicht double- vielleicht doublewar Ihre Anwendung. Wenn in C, verwenden Sie unbedingt floorf()mit floats.
chux
@chux Ich denke, der einzige Grund, warum es einen Unterschied gibt, ist, dass die Besetzung eine Optimierung der Kompilierungszeit ermöglicht. Damit wurde die Konvertierung möglicherweise während der Ausführung vollständig entfernt.
ClydeTheGhost
9

SO 101, ändern Sie Ihre Frage nicht, nachdem die Leute auf Ihre Frage geantwortet haben, sondern schreiben Sie eine neue Frage.

Warum glauben Sie, werden sie das gleiche Ergebnis haben?

float foo = (int)(bar / 3.0) //will create an integer then assign it to a float

float foo = fabs(bar / 3.0 ) //will do the absolute value of a float division

bar = 1.0

foo1 = 0;
foo2 = 0.33333...
AndersK
quelle
1
Was meinst du damit fabs? Die Frage war ungefähr floor. Der Boden von 0.33333... ist 0.
Aaron Franke
2
@ AaronFranke Die ursprüngliche Frage wurde geändert. Es scheint, dass in 8 Jahren viel passieren kann
;-) Beachten Sie
4

BEARBEITEN: Weil die Frage möglicherweise aufgrund von Verwechslungen zwischen fabs()und geändert wurde floor().

Angesichts der ursprünglichen Frage Beispielzeilen:

1.  float foo = (int)(bar / 3.0);

2.  float foo = fabs(bar / 3.0);

Der Unterschied besteht darin, dass bei einem negativen Balken das Ergebnis beim ersten negativ, beim zweiten positiv ist. Der erste wird auf eine Ganzzahl abgeschnitten und der zweite gibt den vollständigen Dezimalwert einschließlich des Bruchteils zurück.

Amardeep AC9MF
quelle
3

Ja. fabsGibt den absoluten Wert seines Arguments zurück, und die Umwandlung in int führt zu einer Kürzung der Division (bis zum nächsten int), sodass die Ergebnisse fast immer unterschiedlich sind.

warrenm
quelle
2

Es gibt zwei Hauptunterschiede:

  1. Wie andere bereits betont haben, wird das Casting auf eine Ganzzahl gegen Null abgeschnitten, wohingegen floor()immer gegen negative Unendlichkeit abgeschnitten wird. Dies ist ein anderes Verhalten für einen negativen Operanden.

  2. Niemand (noch) scheint auf einen anderen Unterschied hingewiesen zu haben - wenn Ihr Argument größer oder gleich MAX_INT+1(oder kleiner als -MAX_INT-1) ist, führt das Casting auf a intdazu, dass die obersten Bits gelöscht werden (C, wahrscheinlich) oder undefiniertes Verhalten ( C ++ und möglicherweise C). Wenn Sie int32 Bit haben, haben Sie nur ein Vorzeichenbit plus 31 Datenbits. Wenn Sie dies also mit einem doublegroßen Gerät verwenden, werden unbeabsichtigte Ergebnisse erzielt.

abligh
quelle
2.a. Die genaue Bedingung für die Konvertierung in intÜberlauf ist, dass das Argument größer oder gleich INT_MAX+1 ist. Symmetrisch ist die Bedingung für den Unterlauf, dass das Argument kleiner oder gleich INT_MIN-1 ist.
Pascal Cuoq
1
2.b. Ein Überlauf bei der Konvertierung von Gleitkomma in Ganzzahl ist in C ++ ein undefiniertes Verhalten. Dies führt nicht dazu, dass die obersten Bits gelöscht werden. Siehe (obwohl es für C geschrieben ist): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq
0

(int) xist eine Anforderung, den ganzzahligen Teil von beizubehalten x(hier gibt es keine Rundung)

fabs(x)= | x | so dass es ist >= 0;

Bsp.: (int) -3.5Kehrt zurück -3; fabs(-3.5)kehrt zurück 3.5;

Im Allgemeinen fabs (x) >= xfür alle x;

x >= (int) x wenn x >= 0

x < (int) x wenn x < 0

Paul Hoang
quelle
x = -3 Fabs (-3) = 3 (int) -3 = -3; Ich denke, die letzten Ungleichungen gelten. Können Sie näher erläutern, warum dies falsch ist?
Paul Hoang
Entschuldigung, ich meinte -3,5, das Beispiel, das Sie gegeben haben. -3> -3,5
Dennis Zickefoose
3
Die letzte Anweisung sollte immer noch "x <= int (x) wenn x <0" und nicht "x <(int) x wenn x <0" sein: negative ganze Zahlen bleiben gleich.
Tomasz Gandor