Fri
09
May 2008
Mieliśmy właśnie przed chwilą na IRC-u dyskusję o zasadach, według jakich działa zaokrąglanie/obcinanie liczb zmiennoprzecinkowych przez funkcje floor, ceil i rzutowanie na int. Przypomniałem sobie, że to temat, z którym nieraz się już spotkałem i pomyślałem, że warto to usystematyzować:
x -2.9 -2.2 2.2 2.9 --------------------------------- (int)x -2 -2 2 2 floor(x) -3.0 -3.0 2.0 2.0 ceil(x) -2.0 -2.0 3.0 3.0 round(x) -3.0 -2.0 2.0 3.0
Problem w tym, że funkcji zaokrąglającej round w C++ nie ma, trzeba ją sobie napisać. Podobnie brakuje funkcji zostawiającej samą część ułamkową 0..1, a jest ona bardzo potrzebna np. do robienia funkcji okresowych i występuje np. w języku HLSL jako frac.
inline int round(float x) {
return (int)(x+0.5f);
}
inline float frac(float x) {
return x - (float)(int)(x);
}
Nie jestem tylko pewny, czy rzutowanie na int faktycznie zawsze obcina część ułamkową. Na moim Visual C++, Windows XP i procesorze Intel Core2Duo 32bit tak jest, ale nie zaglądałem do standardu C++, więc nie wiem czy tak samo jest wszędzie. Wkrótce jakiś językoznawca powinien wyjaśnić tą kwestię w tym wątku forum. Gdyby się jednak okazało, że nie można polegać na tym rzutowaniu, funkcję obcinającą część ułamkową można sobie napisać samemu:
inline float trunc(float x) {
return (x < 0.0f) ? ceilf(x) : floorf(x);
}
Takich niby prostych (prostych dla tego co już je zna) sztuczek matematycznych jest bardzo dużo. Przydałoby się je kiedyś porządnie spisać :) Na przykład ta nasza dyskusja IRC-owa zaczęła się od pytania, jak obciąć liczbę do 2 miejsc po przecinku. Rozwiązaniem jest:
y = (float)(int)(x * 100.0f) / 100.0f;
Comments | #c++ #math #algorithms Share