16

Często potrzebuję do podłogi lub sufitu CGFloat do int, do obliczania indeksu tablicy.Jak bezpiecznie podłożyć podłogę lub sufit CGFloat do int?

Problem na stałe z floorf(theCGFloat) lub ceilf(theCGFloat) polega na tym, że mogą występować problemy z nieścisłościami zmiennoprzecinkowymi.

Co jeśli mój CGFloat jest 2.0f, ale wewnętrznie jest reprezentowany jako 1.999999999999f lub coś w tym stylu. Robię floorf i otrzymuję 1.0f, który znowu jest floatem. A jednak muszę rzucić tę bestię na int, co może wprowadzić inny problem.

Czy istnieje najlepszych praktyk, jak podłoga lub CEIL float do int takie, że coś 2.0 nigdy przypadkowo podłogi do 1 i coś podobnego 2.0 nigdy przypadkowo ceiled do 2?

+4

Na to pytanie nie można odpowiedzieć poprawnie dopóki specyfikacje są opisujący błąd w wartości wejściowej i jakie są konsekwencje zwrotu wartości, które są zbyt wysokie lub zbyt niskie. Występują kompromisy pomiędzy zwracaniem wartości, która jest zbyt wysoka, ponieważ poprzedni błąd zaokrąglenia spowodował, że wartość była zbyt wysoka, a zwracana wartość była zbyt niska, ponieważ wartość została sztucznie dostosowana, aby skompensować poprzedni błąd, i na odwrót. Bez wyjaśnienia kontekstu nie ma jednej prawidłowej odpowiedzi. –

Odpowiedz

19

W twoim pytaniu jest kilka nieporozumień.

co jeśli moja CGFloat jest 2.0f ale wewnętrznie jest ona reprezentowana jako 1.999999999999f

nie może się zdarzyć; 2.0, podobnie jak wszystkie stosunkowo małe liczby całkowite, ma dokładną reprezentację w zmiennoprzecinkowej. Jeśli twój CGFloat jest 2.0f, to naprawdę jest 2.0.

coś jak 2,0 nigdy przypadkowo ceiled do 2

Sufit 2,0 jest 2; co jeszcze by to mogło być?


Myślę, że pytanie, które tak naprawdę pytaniem jest „przypuszczam zrobić kalkulację, która produkuje takie Niedokładny wynik, który matematycznie powinny być dokładnie 2,0, ale w rzeczywistości jest nieco mniejsza, kiedy stosuje się do floor tej wartości, otrzymuję 1,0 zamiast 2.0 - jak mam temu zapobiec?"

To rzeczywiście dość subtelne wątpliwości, że nie ma jednej«właściwej»odpowiedzi. Jak ty obliczane wartości wejściowe? Co masz zamiar zrobić z wyniku?

1

EDIT - przeczytać komentarze z powodów, dlaczego ta odpowiedź nie jest w porządku :)

rzucając float do int jest niejawna floorf tj (int)5.9 jest 5. Jeśli nie masz nic przeciwko temu, to po prostu wyrzuć :)

Jeśli chcesz zaokrąglić w górę, a następnie rzucić wynik ceilf - rzut po zaokrągleniu nie powinien wprowadzać żadnych błędów (lub, jeśli chcesz, dodać jeden przed rzutem tj. `(int) (5.9 + 1) 'to' 6 '- taki sam jak zaokrąglanie w górę).

Aby zaokrąglić do najbliższej, po prostu dodaj 0.5 - (int)(5.9+0.5) jest 6, ale (int)(5.4+0.5) jest 5. Chociaż użyłbym tylko roundf(5.9) :)

+8

Przesyłanie zmiennoprzecinkowe na int nie jest ukrytą podłogą. Jest to, w C i kilku innych popularnych językach, obcięcie (w kierunku zera). Podłoga zaokrągla się do najbliższej liczby całkowitej w kierunku ujemnej nieskończoności. Konwersja -3,5 do liczby całkowitej daje -3, ale podłoga (-3,5) wynosi -4. –

+0

OK, to jest słuszne - zbytnio upraszczałem, aż się myliłem :) – deanWombourne

18

Swift odpowiedź miejski

dodaję to jako odpowiedź uzupełniające dla tych, którzy przyjeżdżają tu w poszukiwaniu sposobu korzystania floor i ceil z CGFloat (jak ja).

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

A jeśli wymagany jest Int, to można go rzutować na jeden.

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

Aktualizacja

Nie ma potrzeby używać C floor i ceil funkcje już. Możesz użyć Swift round() z rounding rules.

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

Jeśli nie chcesz modyfikować oryginalnych zmiennych, użyj rounded().

Uwagi

  • współpracuje zarówno z 32- i 64-bitowych architektur.

Zobacz także