How to safely floor or ceil a CGFloat to int?

前端 未结 3 1337
面向向阳花
面向向阳花 2021-02-01 19:01

I often need to floor or ceil a CGFloat to an int, for calculation of an array index.

The problem I permanently see with floorf(theCGFloa

相关标签:
3条回答
  • 2021-02-01 19:43

    There are a couple misconceptions in your question.

    what if my CGFloat is 2.0f but internally it is represented as 1.999999999999f

    can't happen; 2.0, like all reasonably small integers, has an exact representation in floating-point. If your CGFloat is 2.0f, then it really is 2.0.

    something like 2.0 would never accidentally get ceiled to 2

    The ceiling of 2.0 is 2; what else would it possibly be?


    I think the question that you're really asking is "suppose I do a calculation that produces an inexact result, which mathematically should be exactly 2.0, but is actually slightly less; when I apply floor to that value, I get 1.0 instead of 2.0--how do I prevent this?"

    That's actually a fairly subtle question that doesn't have a single "right" answer. How have you computed the input value? What are you going to do with the result?

    0 讨论(0)
  • 2021-02-01 20:01

    EDIT - read the comments for reasons why this answer isn't right :)

    Casting a float to an int is an implicit floorf i.e. (int)5.9 is 5. If you don't mind that then just cast :)

    If you want to round up then just cast the result of a ceilf - casting after rounding shouldn't introduce any errors at all (or, if you want, add one before casting i.e. `(int)(5.9+1)' is '6' - same as rounding up).

    To round to the nearest, just add 0.5 - (int)(5.9+0.5) is 6 but (int)(5.4+0.5) is 5. Though I would just use roundf(5.9) :)

    0 讨论(0)
  • 2021-02-01 20:02

    Swift supplemental answer

    I am adding this as a supplemental answer for those who come here looking how to use floor and ceil with a CGFloat (like I did).

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

    And if an Int is needed, then it can be cast to one.

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

    Update

    There is no need to use the C floor and ceil functions anymore. You can use the Swift round() with rounding rules.

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

    If you don't wish to modify the original variables, then use rounded().

    Notes

    • Works with both 32 and 64 bit architectures.

    See also

    • How to round CGFloat
    0 讨论(0)
提交回复
热议问题