Diffuser vers int vs sol


120

Y a-t-il une différence entre ceux-ci:

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

Si je comprends bien, les deux cas ont le même résultat. Y a-t-il une différence dans le code compilé?


1
un peu mieux avec floor, mais attention que ce n'est doublepas pour float. C99 a également floorfpour float.
Jens Gustedt

2
Donc, ils ont le même résultat tant que la barre est positive
Zac

1
(note: en C ++ s'il vous plaît #include<cmath>et utilisez std::floor)
user202729

Quel type est bar?
chux - Réintégrer Monica

@chux Peu importe, diviser par 3,0 le fera quand même doubler
kaalus

Réponses:


194

La conversion en un entier tronquera vers zéro. floor()tronquera vers l'infini négatif. Cela vous donnera des valeurs différentes si elles barétaient négatives.


15
Je pense que vous avez frappé dans le mille ici. Une autre différence, si floor()c'est l'intention, est si la valeur de barest trop grande pour tenir dans un int.
Fred Larson

Avez-vous une source pour cette déclaration?
HelloGoodbye

1
Même lorsque le résultat est positif, ce n'est pas garanti. Voyez ceci et cela .
user202729

27

Comme cela a été dit précédemment, pour les nombres positifs, ils sont identiques, mais ils diffèrent pour les nombres négatifs. La règle est que int arrondit vers 0, tandis que le plancher arrondit vers l'infini négatif.

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

Cela étant dit, il existe également une différence de temps d'exécution. Sur mon système, j'ai chronométré que le casting est au moins 3 fois plus rapide que le sol.

J'ai du code qui nécessite le fonctionnement au sol d'une plage limitée de valeurs, y compris des nombres négatifs. Et il doit être très efficace, nous utilisons donc la fonction suivante pour cela:

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

Bien sûr, cela échouera pour de très grandes valeurs de x (vous rencontrerez des problèmes de dépassement de capacité) et pour des valeurs négatives inférieures à -100000, etc. pour notre application. Prenez-le avec un grain de sel, testez-le sur votre système, etc. mais cela vaut la peine d'être considéré à mon humble avis.


"Je l'ai chronométré pour être au moins 3 fois plus rapide que le sol" -> OP utilise float, non double- peut-être doubleétait votre application. Si en C, veillez à utiliser floorf()avec floats.
chux

@chux Je pense que la seule raison pour laquelle il y a une différence est que la distribution permet une optimisation au moment de la compilation. Cette conversion peut donc avoir été complètement supprimée lors de l'exécution.
ClydeTheGhost

9

SO 101, ne changez pas votre question une fois que les gens ont répondu à votre question, écrivez plutôt une nouvelle question.

Pourquoi pensez-vous qu'ils auront le même résultat?

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
Que voulez-vous dire fabs? La question portait sur floor. Le sol de 0.33333... est 0.
Aaron Franke

2
@AaronFranke la question d'origine a été modifiée. semble que beaucoup de choses peuvent se passer dans 8 ans ;-) remarquez que d'autres réponses ont le même principe
AndersK

4

EDIT: Parce que la question peut avoir été modifiée en raison de la confusion entre fabs()et floor().

Compte tenu des lignes d'exemple de question d'origine:

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

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

La différence est que si la barre est négative, le résultat sera négatif avec le premier mais positif avec le second. Le premier sera tronqué à un entier et le second renverra la valeur décimale complète, y compris la partie fractionnaire.


3

Oui. fabsrenvoie la valeur absolue de son argument, et le transtypage en int provoque la troncature de la division (jusqu'à l'entier le plus proche), de sorte que les résultats seront presque toujours différents.


2

Il existe deux différences principales:

  1. Comme d'autres l'ont souligné, la conversion en un entier tronquera vers zéro, alors que floor()sera toujours tronquée vers l'infini négatif; c'est un comportement différent pour un opérande négatif.

  2. Personne (encore) ne semble avoir signalé une autre différence - si votre argument est supérieur ou égal à MAX_INT+1(ou inférieur à -MAX_INT-1), alors la conversion en un intentraînera la suppression des bits les plus hauts (C, probablement) ou un comportement indéfini ( C ++ et éventuellement C). EG si votre intest de 32 bits, vous n'aurez qu'un bit de signe plus 31 bits de données. Donc, utiliser ceci avec un doublequi est de grande taille va produire des résultats inattendus.


2.a. La condition exacte pour la conversion en intdébordement est que l'argument soit supérieur ou égal à INT_MAX+1. Symétriquement, la condition du dépassement inférieur est que l'argument soit inférieur ou égal à INT_MIN-1.
Pascal Cuoq

1
2.b. Le débordement dans la conversion de virgule flottante en nombre entier est un comportement non défini en C ++. Cela n'entraîne pas la suppression des bits les plus élevés. Voir (bien qu'il soit écrit pour C): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq

0

(int) xest une requête pour conserver la partie entière de x(il n'y a pas d'arrondi ici)

fabs(x)= | x | pour que ce soit >= 0;

Ex: (int) -3.5retourne -3; fabs(-3.5)retourne 3.5;

En général, fabs (x) >= xpour tout x;

x >= (int) x si x >= 0

x < (int) x si x < 0


x = -3 fabs (-3) = 3 (entier) -3 = -3; Je pense que les dernières inégalités tiennent. Pouvez-vous expliquer plus en détail pourquoi c'est faux?
Paul Hoang

Désolé, je voulais dire -3,5, l'exemple que vous avez donné. -3> -3,5
Dennis Zickefoose

3
La dernière instruction doit toujours être "x <= int (x) if x <0", et non "x <(int) x if x <0": les entiers négatifs restent les mêmes.
Tomasz Gandor
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.