Trasmetti a int vs floor


120

C'è qualche differenza tra questi:

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

Da quanto ho capito entrambi i casi hanno lo stesso risultato. C'è qualche differenza nel codice compilato?


1
un po 'meglio con floor, ma attenzione che questo è per doublenon per float. C99 ha anche floorfper float.
Jens Gustedt

2
Quindi hanno lo stesso risultato finché la barra è positiva
Zac

1
(nota: in C ++ si prega di #include<cmath>utilizzare std::floor)
user202729

Che tipo è bar?
chux - Ripristina Monica il

@chux Non importa, dividere per 3.0 diventerà il doppio comunque
kaalus

Risposte:


193

Il cast a un int verrà troncato verso zero. floor()troncerà verso infinito negativo. Questo ti darà valori diversi se barfosse negativo.


15
Penso che tu abbia colpito nel segno qui. Un'altra differenza, se floor()è l'intento, è se il valore di barè troppo grande per entrare in un file int.
Fred Larson

Hai qualche fonte per quella dichiarazione?
Ciao Arrivederci

1
Anche quando il risultato è positivo non è garantito. Vedi questo e questo .
user202729

27

Come si è detto prima, per i numeri positivi sono gli stessi, ma differiscono per i numeri negativi. La regola è che int arrotonda verso 0, mentre floor arrotonda verso l'infinito negativo.

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

Detto questo, c'è anche una differenza nel tempo di esecuzione. Sul mio sistema, ho calcolato che il lancio è almeno 3 volte più veloce del pavimento.

Ho un codice che richiede il funzionamento al piano di un intervallo limitato di valori, inclusi i numeri negativi. E deve essere molto efficiente, quindi usiamo la seguente funzione per questo:

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

Ovviamente questo fallirà per valori molto grandi di x (si verificheranno alcuni problemi di overflow) e per valori negativi inferiori a -100000, ecc. per la nostra applicazione. Prendilo con le pinze, provalo sul tuo sistema, ecc.Ma vale la pena considerare IMHO.


"L'ho fatto essere almeno 3 volte più veloce del floor" -> OP sta usando float, no double- forse doubleera la tua applicazione. Se in C, assicurati di usare floorf()con floats.
chux - Ripristina Monica

@chux Penso che l'unica ragione per cui ci sia qualche differenza è che il cast consente un'ottimizzazione in fase di compilazione. In modo che la conversione possa effettivamente essere stata completamente rimossa durante l'esecuzione.
ClydeTheGhost

9

COSÌ 101, non modificare la tua domanda dopo che le persone hanno risposto alla tua domanda, scrivi invece una nuova domanda.

Perché pensi che avranno lo stesso risultato?

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...

1
Cosa intendi con fabs? La domanda riguardava floor. Il pavimento di 0.33333... è 0.
Aaron Franke

2
@AaronFranke la domanda originale è stata modificata. sembra che molte cose possano accadere in 8 anni ;-) nota che altre risposte hanno la stessa premessa
AndersK

4

EDIT: Perché la domanda potrebbe essere stata modificata a causa della confusione tra fabs()e floor().

Date le righe dell'esempio di domanda originale:

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

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

La differenza è che se la barra è negativa il risultato sarà negativo con la prima ma positivo con la seconda. Il primo verrà troncato a un numero intero e il secondo restituirà il valore decimale completo inclusa la parte frazionaria.


3

Sì. fabsrestituisce il valore assoluto del suo argomento e il cast su int causa il troncamento della divisione (fino all'int più vicino), quindi i risultati saranno quasi sempre diversi.


2

Esistono due differenze principali:

  1. Come altri hanno sottolineato, il casting a un intero troncerà verso zero, mentre floor()troncerà sempre verso l'infinito negativo; questo è un comportamento diverso per un operando negativo.

  2. Nessuno (ancora) sembra aver evidenziato un'altra differenza: se il tuo argomento è maggiore o uguale a MAX_INT+1(o minore di -MAX_INT-1), il casting su an intcomporterà l'eliminazione dei bit più in alto (C, probabilmente) o un comportamento indefinito ( C ++ e possibilmente C). Ad esempio, se il tuo intè a 32 bit, avrai solo un bit di segno più 31 bit di dati. Quindi l'utilizzo di questo con un doubleche è di grandi dimensioni produrrà risultati imprevisti.


2.a. La condizione esatta per la conversione in intoverflow è che l'argomento sia maggiore o uguale a INT_MAX+1. Simmetricamente, la condizione per l'underflow è che l'argomento sia minore o uguale a INT_MIN-1.
Pascal Cuoq

1
2.b. L'overflow nella conversione da virgola mobile a intero è un comportamento indefinito in C ++. Non "provoca l'eliminazione dei bit più in alto". Vedi (anche se è scritto per C): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq

0

(int) xè una richiesta per mantenere la parte intera di x(non c'è arrotondamento qui)

fabs(x)= | x | in modo che sia >= 0;

Es: (int) -3.5resi -3; fabs(-3.5)ritorni 3.5;

In generale, fabs (x) >= xper tutti x;

x >= (int) x Se x >= 0

x < (int) x Se x < 0


x = -3 fabs (-3) = 3 (int) -3 = -3; Penso che le ultime disuguaglianze valgano. Puoi approfondire di più sul motivo per cui è sbagliato?
Paul Hoang

Scusa, volevo dire -3,5, l'esempio che hai fornito. -3> -3.5
Dennis Zickefoose

3
L'ultima istruzione dovrebbe essere ancora "x <= int (x) if x <0" e non "x <(int) x if x <0": gli interi negativi rimangono gli stessi.
Tomasz Gandor
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.