J'ai souvent besoin de plancher ou de plafond un CGFloat
à un int
, pour le calcul d'un index de tableau.
Le problème que je vois en permanence avec floorf(theCGFloat)
ou ceilf(theCGFloat)
est qu'il peut y avoir des problèmes avec des inexactitudes en virgule flottante.
Et si mon CGFloat
est 2.0f
mais en interne, il est représenté par 1.999999999999f
ou quelque chose comme ça. Je fais floorf
et je reçois 1.0f
, qui est à nouveau un flotteur. Et pourtant je dois lancer cette bête en int qui peut introduire un autre problème.
Existe-t-il une meilleure pratique pour fixer le plancher ou le plafond d'un float
à un int
de telle sorte que quelque chose comme 2.0
ne serait jamais accidentellement condamné à 1
et quelque chose comme 2.0
ne serait jamais accidentellement plafonné à 2
?
Il y a quelques idées fausses dans votre question.
que faire si mon CGFloat est 2.0f mais en interne il est représenté par 1.999999999999f
ne peut pas arriver; 2.0, comme tous les entiers raisonnablement petits, a une représentation exacte en virgule flottante. Si votre CGFloat
est 2.0f
, alors c'est vraiment 2.0.
quelque chose comme 2.0 ne serait jamais accidentellement plafonné à 2
Le plafond de 2,0 est 2; que serait-ce d'autre?
Je pense que la question que vous posez vraiment est "supposons que je fasse un calcul qui produit un résultat inexact, qui mathématiquement devrait soit exactement 2.0, mais est en fait légèrement moins; lorsque j'applique floor
à cette valeur, j'obtiens 1.0 au lieu de 2.0 - comment puis-je éviter cela? "
C'est en fait une question assez subtile qui n'a pas une seule "bonne" réponse. Comment avez-vous calculé la valeur d'entrée? Qu'allez-vous faire du résultat?
Réponse supplémentaire rapide
J'ajoute cela comme une réponse supplémentaire pour ceux qui viennent ici en regardant comment utiliser floor
et ceil
avec un CGFloat
(comme je l'ai fait).
var myCGFloat: CGFloat = 3.001
floor(myCGFloat) // 3.0
ceil(myCGFloat) // 4.0
Et si un Int
est nécessaire, il peut être converti en un.
var myCGFloat: CGFloat = 3.001
Int(floor(myCGFloat)) // 3
Int(ceil(myCGFloat)) // 4
Mise à jour
Il n'est plus nécessaire d'utiliser les fonctions C floor
et ceil
. Vous pouvez utiliser le Swift round()
avec règles d'arrondi .
var myCGFloat: CGFloat = 3.001
myCGFloat.round(.down) // 3.0
myCGFloat.round(.up) // 4.0
Si vous ne souhaitez pas modifier les variables d'origine, utilisez alors rounded()
.
Notes
Voir aussi
EDIT - lisez les commentaires pour les raisons pour lesquelles cette réponse n'est pas correcte :)
La conversion d'un float
en int
est un floorf
implicite, c'est-à-dire que (int)5.9
Est 5
. Si cela ne vous dérange pas, lancez simplement :)
Si vous voulez arrondir, il vous suffit de lancer le résultat d'un ceilf
- un casting après l'arrondi ne devrait pas introduire d'erreurs du tout (ou, si vous le souhaitez, ajoutez-en un avant le cast, par exemple `(int) (5.9+ 1) 'est' 6 '- identique à l'arrondi).
Pour arrondir au plus proche, ajoutez simplement 0,5 - (int)(5.9+0.5)
Est 6
Mais (int)(5.4+0.5)
Est 5
. Bien que j'utiliserais simplement roundf(5.9)
:)