Как безопасно надеть или погрузить CGFloat в int?
Мне часто нужно заполнить CGFloat
до int
для вычисления индекса массива.
Проблема, которую я постоянно вижу с помощью floorf(theCGFloat)
или ceilf(theCGFloat)
, заключается в том, что могут быть проблемы с неточностями с плавающей запятой.
Так что, если мой CGFloat
2.0f
, но внутри он представлен как 1.999999999999f
или что-то в этом роде. Я делаю floorf
и получаю 1.0f
, который снова является поплавком. И все же я должен бросить этого зверя в int, который может ввести еще одну проблему.
Есть ли наилучшая практика для того, как настил или поместить float
в int
так, чтобы что-то вроде 2.0
никогда не попадалось бы наподобие 1
, а что-то вроде 2.0
никогда не будет случайно закрыто 2
?
Ответы
Ответ 1
В вашем вопросе есть пара неправильных представлений.
что, если мой CGFloat 2.0f, но внутренне он представлен как 1.999999999999f
не может случиться; 2.0, как и все достаточно мелкие целые числа, имеет точное представление в плавающей запятой. Если ваш CGFloat
равен 2.0f
, тогда это действительно 2.0.
что-то вроде 2.0 никогда не будет случайно потеряно до 2
Потолок 2.0 равен 2; что еще может быть?
Я думаю, что вопрос, который вы действительно задаете, "предположим, что я делаю расчет, который дает неточный результат, который математически должен быть ровно 2.0, но на самом деле немного меньше, когда я применяю floor
к этому значению, я get 1.0 вместо 2.0 - как это предотвратить?"
Это действительно довольно тонкий вопрос, который не имеет ни одного "правильного" ответа. Как вы вычислили входное значение? Что вы собираетесь делать с результатом?
Ответ 2
Быстрый дополнительный ответ
Я добавляю это как дополнительный ответ для тех, кто приходит сюда, глядя, как использовать floor
и ceil
с помощью CGFloat
(как и я).
var myCGFloat: CGFloat = 3.001
floor(myCGFloat) // 3.0
ceil(myCGFloat) // 4.0
И если нужен Int
, он может быть добавлен к одному.
var myCGFloat: CGFloat = 3.001
Int(floor(myCGFloat)) // 3
Int(ceil(myCGFloat)) // 4
Обновление
Нет необходимости использовать функции C floor
и ceil
. Вы можете использовать правила Swift round()
с округления.
var myCGFloat: CGFloat = 3.001
myCGFloat.round(.down) // 3.0
myCGFloat.round(.up) // 4.0
Если вы не хотите изменять исходные переменные, используйте rounded()
.
Примечания
- Работает как с 32, так и с 64-разрядными архитектурами.
См. также
Ответ 3
EDIT - прочитайте комментарии по причинам, почему этот ответ неверен:)
Приведение a float
в int
является неявным floorf
i.e. (int)5.9
is 5
. Если вы не возражаете, тогда просто бросьте:)
Если вы хотите округлить, просто произведите результат ceilf
- casting после округления, не должны вводить никаких ошибок вообще (или, если хотите, добавить один перед литьем, т.е. `(int) (5.9+ 1) 'is' 6 '- то же, что и округление).
Чтобы округлить до ближайшего, просто добавьте 0.5 - (int)(5.9+0.5)
is 6
, но (int)(5.4+0.5)
- 5
. Хотя я бы просто использовал roundf(5.9)
:)