16

A menudo necesito plantar o celar un CGFloat a un int, para el cálculo de un índice de matriz.Cómo colocar o cementar con seguridad un CGFloat a int?

El problema que veo permanentemente con floorf(theCGFloat) o ceilf(theCGFloat) es que puede haber problemas con las imprecisiones de coma flotante.

Entonces, ¿qué ocurre si mi CGFloat es pero internamente se representa como 1.999999999999f o algo así. Hago floorf y obtengo 1.0f, que es un flotador nuevamente. Y, sin embargo, debo lanzar esta bestia a int, que puede presentar otro problema.

¿Hay una mejor práctica cómo suelo o CEIL un float a un int tal que algo así como 2.0 nunca accidentalmente caen con piso de 1 y algo así como 2.0 nunca accidentalmente caen artesonadas a 2?

+4

Esta pregunta no se puede responder correctamente hasta que se proporcionen especificaciones que describe el error en el valor de entrada y cuáles son las consecuencias de los valores que son demasiado volver alto o muy bajo Hay compensaciones entre la devolución de un valor que es demasiado alto porque el error de redondeo anterior hizo que el valor sea demasiado alto y devuelva un valor demasiado bajo porque el valor se ajustó artificialmente para compensar el error anterior, y viceversa. Sin una explicación del contexto, no hay una única respuesta correcta. –

Respuesta

19

Hay un par de conceptos erróneos en su pregunta.

lo que si mi CGFloat es 2.0f pero internamente se representa como 1.999999999999f

no puede suceder; 2.0, como todos los enteros razonablemente pequeños, tiene una representación exacta en coma flotante. Si su CGFloat es 2.0f, entonces realmente es 2.0.

algo así como 2.0 nunca accidentalmente caen artesonadas a 2

El techo de 2.0 es 2; ¿Qué más podría ser?


Creo que la pregunta que usted está pidiendo realmente es "supongo que hago un cálculo que produce un resultado inexacto, que matemáticamente debe ser exactamente 2,0, pero en realidad es un poco menos; cuando aplico a floor ese valor, obtengo 1.0 en lugar de 2.0 - ¿cómo lo evito?"

que en realidad es una pregunta bastante sutil que no tiene una única 'respuesta correcta'. ¿Cómo se ha calculado el valor de entrada? ¿Qué vas a hacer con el resultado?

1

EDITAR - leer los comentarios de razones por las que esta respuesta no está bien :)

Al lanzar un float a un int es una implícita floorf decir (int)5.9 es 5. Si no te importa eso, simplemente echa :)

Si quieres redondear, solo echa el resultado de un ceilf - el casting después del redondeo no debe introducir ningún error en absoluto (o, si quieres, agrega uno antes del lanzamiento, es decir `(int) (5.9 + 1) 'es' 6 '- lo mismo que redondear hacia arriba).

redondear al más cercano, simplemente se añaden 0,5 - (int)(5.9+0.5) es 6(int)(5.4+0.5) pero es 5. Aunque solo usaría roundf(5.9) :)

+8

Fundición flotante a int no es un piso implícito. Es, en C y en otros lenguajes comunes, un truncamiento (hacia cero). El piso está redondeando al entero más cercano en la dirección del infinito negativo. La conversión de -3.5 a enteros produce -3, pero el piso (-3.5) es -4. –

+0

OK, ese es un punto justo - me simplifiqué demasiado hasta el punto de estar equivocado :) – deanWombourne

18

respuesta suplementaria Swift

añado esto como una respuesta complementaria para aquellos que vienen aquí en busca cómo utilizar floor y ceil con un CGFloat (como yo).

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

Y si se necesita Int, se puede convertir en uno.

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

actualización

No hay necesidad de utilizar el C floor y ceil funciones más. Puede usar Swift round() con rounding rules.

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

Si no desea modificar las variables originales, a continuación, utilizar rounded().

Notas

  • sirve para las arquitecturas de 32 y 64 bits.

Ver también