Warsztat » Forum

[C++] Rzutowanie na int i zaokrąglanie

Sep 14, 2004 | Xion |
13 wypowiedzi na 1 stronach:
1
Xion
Sep 14, 2004

Rzutowanie na int i zaokrąglanie

W C(++) mamy funkcje standardowe z math.h/cmath o nazwach floor() i ceil(), które zaokrąglają liczby zmiennoprzecinkowe w kierunku - odpowiednio - ujemnej i dodatniej nieskończoności. Używając floor() można też napisać round(), czyli zaokrąglanie w stronę najbliżej liczby całkowitej.

Tym czego jak sądzę brakuje, jest trunc() - obcinanie części ułamkowej. Z praktyki wynika, że można w tym celu użyć zwykłego rzutowania na int:
Kod: int trunc(float x) { return (int)x; }

(w C++ byłoby to rzutowanie static_cast). Ponieważ jednak w przypadku, gdy takie rzutowanie jest robione niejawnie, np:
Kod: int x = 1.0f; // warning

kompilatory ostrzegają o tym, mówiąc o "utracie danych", mam podejrzenia, że rzutowanie to nie przeprowadza żadnej ściśle zdefiniowanej konwersji (czyli np. obcięcia części ułamkowej) i wynik jest zależny od środowiska/kompilatora/sprzętu/itd.

Chciałbym więc zapytać, czy wynik rzutowania float -> int jest ustandaryzowany i czy wobec tego można go przenośnie używać do obcinania części ułamkowej liczb zmiennoprzecinkowych.
GLSL
Sep 14, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:
Tym czego jak sądzę brakuje, jest trunc() - obcinanie części ułamkowej.
A modf() tutaj sie nie nada ? http://www.cplusplus.com/reference/clibrary/cmath/modf.html
skoti
Sep 14, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:

W C(++) mamy funkcje standardowe z math.h/cmath o nazwach floor() i ceil(), które zaokrąglają liczby zmiennoprzecinkowe w kierunku - odpowiednio - ujemnej i dodatniej nieskończoności. Używając floor() można też napisać round(), czyli zaokrąglanie w stronę najbliżej liczby całkowitej.

Tym czego jak sądzę brakuje, jest trunc() - obcinanie części ułamkowej. Z praktyki wynika, że można w tym celu użyć zwykłego rzutowania na int:
Kod: int trunc(float x) { return (int)x; }

(w C++ byłoby to rzutowanie static_cast). Ponieważ jednak w przypadku, gdy takie rzutowanie jest robione niejawnie, np:
Kod: int x = 1.0f; // warning

kompilatory ostrzegają o tym, mówiąc o "utracie danych", mam podejrzenia, że rzutowanie to nie przeprowadza żadnej ściśle zdefiniowanej konwersji (czyli np. obcięcia części ułamkowej) i wynik jest zależny od środowiska/kompilatora/sprzętu/itd.

Chciałbym więc zapytać, czy wynik rzutowania float -> int jest ustandaryzowany i czy wobec tego można go przenośnie używać do obcinania części ułamkowej liczb zmiennoprzecinkowych.

pi = 3.14159265;
ulamek = modf (pi , &calkowita);
:)
GLSL
Sep 15, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:
pi = 3.14159265;
ulamek = modf (pi , &calkowita);
Skoti, a nie powinno to być tak: ulamek = modf (calkowita , &reszta) ?

EDIT: Sorki, jednak jest dobrze, coś mi sie poknociło :P
Krzysiek K.
Sep 17, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:
Chciałbym więc zapytać, czy wynik rzutowania float -> int jest ustandaryzowany

Tak - zawsze zaokrągla w kierunku zera.

Cytat:
i czy wobec tego można go przenośnie używać do obcinania części ułamkowej liczb zmiennoprzecinkowych.

Nie. Dużych liczb w ten sposób nie zaokrąglisz, bo się po prostu w incie nie zmieszczą.
Xion
Sep 17, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:

Cytat:
Chciałbym więc zapytać, czy wynik rzutowania float -> int jest ustandaryzowany

Tak - zawsze zaokrągla w kierunku zera.

Niezależnie od ustawionego aktualnie trybu zaokrąglania FPU/SSE/...?

Cytat:
Cytat:
i czy wobec tego można go przenośnie używać do obcinania części ułamkowej liczb zmiennoprzecinkowych.

Nie. Dużych liczb w ten sposób nie zaokrąglisz, bo się po prostu w incie nie zmieszczą.

Słuszna uwaga. I tutaj pomoże więc świeżo poznana przeze mnie - dzięki przedmówcom - funkcja modf() :)
yarpen
Sep 18, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:

Cytat:

Cytat:
Chciałbym więc zapytać, czy wynik rzutowania float -> int jest ustandaryzowany

Tak - zawsze zaokrągla w kierunku zera.

Niezależnie od ustawionego aktualnie trybu zaokrąglania FPU/SSE/...?

Oczywiscie. Standardowa konwersja i tak zawsze przestawia najpierw na chop.
DamorK
Sep 23, 2004

Odp: Rzutowanie na int i zaokrąglanie

W drugim tomie perełek piszą, że rzutowanie z float na int jest dosyć kosztowne i podają przy tym ciekawą sztuczkę do zamiany liczby ze zmiennoprzecinkowej na całkowitą.
I tu mam pytanie (jako, że perełki już mają parę lat), czy dla dzisiejszego sprzętu ma sens taka optymalizacja?
I
Sep 23, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:

W drugim tomie perełek piszą, że rzutowanie z float na int jest dosyć kosztowne i podają przy tym ciekawą sztuczkę do zamiany liczby ze zmiennoprzecinkowej na całkowitą.
I tu mam pytanie (jako, że perełki już mają parę lat), czy dla dzisiejszego sprzętu ma sens taka optymalizacja?

Generalnie ma, chociaż raczej w niewielu przypadkach (wąskich gardłach).
Xion
Sep 21, 2004

Odp: Rzutowanie na int i zaokrąglanie

Jeżeli chodzi o szybszą konwersję, to ładnie sprawdza się:
Kod: int round(float x)
{
   int res;
   __asm
   {
      fld x
      fistp res
      mov eax, res
   }
}

lecz wynik jest zależny od trybu zaokrąglania FPU (domyślnie w kierunku zera). Chcąc zawsze mieć obcinanie części ułamkowej, można użyć SSE:
Kod: int trunc(float x) { __asm cvttss2si eax, x; }


Cytat:
Oczywiscie. Standardowa konwersja i tak zawsze przestawia najpierw na chop.

I potem przestawia to z powrotem? Wobec tego ja nawet nie chcę myśleć, ile to trwa ;)
bies
Sep 22, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:

Cytat:
Oczywiscie. Standardowa konwersja i tak zawsze przestawia najpierw na chop.

I potem przestawia to z powrotem? Wobec tego ja nawet nie chcę myśleć, ile to trwa ;)

Najpierw sprawdź, język tylko wymaga aby domyślna konwersja była obcięciem części ułamka. Implementacja zależy od kompilatora:
Kod: int trunc_f(float from) {
    int to = (float)from;
    return to;
}

Cytat:
$ gcc -S -O2 b.c

Kod: trunc_f:
.LFB2:
        cvttss2si       %xmm0, %eax
        ret
Znajome, prawda. ;D

// edit
Dodam jeszcze, że moria to x86_64 więc SSE jest zawsze włączone w opcjach kompilatora.
Xion
Sep 22, 2004

Odp: Rzutowanie na int i zaokrąglanie

Więc jest przynajmniej jeden konkretny argument, żeby włączyć optymalizację SSE w swoim kompilatorze ;D
Krzysiek K.
Sep 23, 2004

Odp: Rzutowanie na int i zaokrąglanie

Cytat:
lecz wynik jest zależny od trybu zaokrąglania FPU (domyślnie w kierunku zera).

Domyślnie jest ustawione na zaokrąglanie "gdzie bliżej", a to dlatego, że ustawienie zaokrąglania ma wpływ na wszystkie operacje FPU, więc gdyby ustawić domyślnie zaokrąglanie w kierunku zera, to błędy obliczeń nawarstwiały by się w ekspresowym tempie.
Strony:
1