16

Spesso ho bisogno di eseguire il floor o il ceil a CGFloat su un int, per il calcolo di un indice di array.Come poggiare o gettare in sicurezza un CGFloat su int?

Il problema che vedo in modo permanente con floorf(theCGFloat) o ceilf(theCGFloat) è che ci possono essere problemi con imprecisioni in virgola mobile.

Quindi, se il mio CGFloat è 2.0f ma internamente è rappresentato come 1.999999999999f o qualcosa del genere. Faccio floorf e ottengo 1.0f, che è di nuovo un float. Eppure devo lanciare questa bestia su int che potrebbe introdurre un altro problema.

C'è una buona pratica come pavimento o ceil un float a un int tale che una cosa del genere non sarebbe mai 2.0 accidentalmente pavimentata a 1 e qualcosa come 2.0 sarebbe mai accidentalmente ceiled a 2?

+4

Questa domanda non si può rispondere in modo corretto fino a quando le specifiche sono forniti che descrive l'errore nel valore di ingresso e quali sono le conseguenze di valori che sono troppo ritorno alto o troppo basso. Ci sono dei compromessi tra la restituzione di un valore troppo alto perché il precedente errore di arrotondamento ha reso il valore troppo alto e restituendo un valore troppo basso perché il valore è stato regolato artificialmente per compensare l'errore precedente e viceversa. Senza spiegazione del contesto, non esiste un'unica risposta corretta. –

risposta

19

Ci sono un paio di idee sbagliate nella tua domanda.

cosa se il mio CGFloat è 2.0f ma internamente è rappresentato come 1.999999999999f

non può accadere; 2.0, come tutti gli interi ragionevolmente piccoli, ha una rappresentazione esatta in virgola mobile. Se il tuo CGFloat è 2.0f, allora è davvero 2.0.

qualcosa come 2.0 sarebbe mai accidentalmente ceiled a 2

Il soffitto di 2,0 è 2; cos'altro potrebbe essere?


Penso che la domanda che si sta realmente chiedendo è "Suppongo che faccio un calcolo che produce un risultato inesatto, che matematicamente dovrebbe essere esattamente 2.0, ma in realtà è un po 'meno, quando applico floor a quel valore, ottengo 1.0 invece di 2.0 - come posso evitare questo?"

che in realtà è una domanda abbastanza sottile, che non ha una sola 'risposta giusta'. Come hai calcolato il valore di ingresso? Che cosa hai intenzione di fare con il risultato?

1

EDIT - leggi i commenti relativi motivi per cui questa risposta non è giusto :)

Casting un float a un int è un implicito floorf cioè (int)5.9 è 5. Se non ti spiace, basta lanciare :)

Se vuoi arrotondare, basta lanciare il risultato di un ceilf - il lancio dopo l'arrotondamento non dovrebbe introdurre alcun errore (o, se vuoi, aggiungere uno prima di lanciare cioè `(int) (5.9 + 1) 'è' 6 '- come arrotondare per eccesso).

per arrotondare al più vicino, basta aggiungere 0,5-(int)(5.9+0.5) è 6 ma (int)(5.4+0.5) è 5. Anche se vorrei usare solo roundf(5.9) :)

+8

Il casting float su int non è un piano implicito. È, in C e in alcune altre lingue comuni, un troncamento (verso zero). Il piano è arrotondato al numero intero più vicino nella direzione dell'infinito negativo. Conversione da -3,5 a interi da -3, ma floor (-3,5) è -4. –

+0

OK, questo è un punto giusto - ho semplificato troppo al punto di essere solo sbagliato :) – deanWombourne

18

risposta supplementare Swift

sto aggiungendo questo come una risposta supplementare per coloro che vengono qui in cerca come utilizzare floor e ceil con un CGFloat (come ho fatto io).

var myCGFloat: CGFloat = 3.001 
floor(myCGFloat) // 3.0 
ceil(myCGFloat) // 4.0 

E se è necessario un Int, può essere lanciato su uno.

var myCGFloat: CGFloat = 3.001 
Int(floor(myCGFloat)) // 3 
Int(ceil(myCGFloat)) // 4 

Aggiornamento

Non v'è alcuna necessità di utilizzare il C floor e ceil funzioni più. È possibile utilizzare Swift round() con rounding rules.

var myCGFloat: CGFloat = 3.001 
myCGFloat.round(.down) // 3.0 
myCGFloat.round(.up) // 4.0 

Se non si desidera modificare le variabili originali, quindi utilizzare rounded().

Note

  • funziona sia con le architetture a 32 e 64 bit.

Vedi anche

Problemi correlati