Skrzynka z narzędziami: metody statyczne
java.lang.Math to klasa pełna gotowych funkcji matematycznych: potęgi, pierwiastki, wartości bezwzględne, zaokrąglanie, trygonometria, logarytmy i liczby losowe. Dwie rzeczy sprawiają, że łatwo jej używać:
- Znajduje się w
java.lang, który każdy plik Javy importuje automatycznie. Nie trzeba pisać żadnej liniiimport. - Każda metoda jest
static. Wywołujesz ją na nazwie klasy,Math.sqrt(25), i nigdy nie tworzysz obiektuMath. Strona o składowych statycznych wyjaśnia, co oznaczastatic.
Zwróć uwagę, że niektóre wyniki są wypisywane z .0, a inne nie. Każda metoda Math ma stały typ zwracany i jego znajomość to większość tego, czego trzeba się nauczyć o tej klasie.
| Metoda | Co robi | Zwraca |
|---|---|---|
Math.pow(a, b) | a do potęgi b | double |
Math.sqrt(x) | pierwiastek kwadratowy | double |
Math.cbrt(x) | pierwiastek sześcienny | double |
Math.abs(x) | wartość bezwzględna | ten sam typ co x |
Math.max(a, b) / Math.min(a, b) | większa / mniejsza z dwóch | szerszy z dwóch typów |
Math.round(x) | najbliższa liczba całkowita | long dla double, int dla float |
Math.floor(x) / Math.ceil(x) | zaokrąglenie w dół / w górę | double |
Math.random() | liczba losowa od 0.0 do 1.0 | double |
Math.PI, Math.E | stałe π i e | double |
Math.pow: potęgi
Math.pow(base, exponent) podnosi liczbę do potęgi. Przyjmuje dwa parametry double i zwraca double, nawet gdy przekazujesz liczby całkowite:
Aby zapisać wynik w int, zrzutuj go przez (int). Dla małych potęg całkowitych wynik double jest dokładny, więc rzutowanie daje poprawną odpowiedź. Problem pojawia się przy dużych wynikach: double większy niż Integer.MAX_VALUE (2 147 483 647) po rzutowaniu daje dokładnie Integer.MAX_VALUE, więc (int) Math.pow(2, 40) daje 2147483647. Przy większych potęgach rzutuj na long i pamiętaj, że powyżej 2⁵³ double nie potrafi dokładnie przedstawić każdej liczby całkowitej. Strona o rzutowaniu typów opisuje, co rzutowanie robi z wartością.
Java nie ma operatora potęgowania. 2 ^ 3 się kompiluje, ale ^ to bitowy XOR, a wynik to 1, nie 8. To jeden z najczęstszych błędów początkujących w kodzie matematycznym w Javie.
double równy dziesięć milionów lub więcej wypisuje się w notacji naukowej, co zaskakuje przy pierwszym wypisaniu potęgi dziesięciu:
1.0E7 oznacza 1.0 × 10⁷. Wartość jest ta sama, zmienia się tylko sposób wypisania. Aby wypisać ją jako zwykłe cyfry, zrzutuj ją na long albo sformatuj przez String.format("%.0f", value).
Math.sqrt i Math.cbrt: pierwiastki
Math.sqrt(x) zwraca pierwiastek kwadratowy z x jako double. Math.cbrt(x) zwraca pierwiastek sześcienny.
Pierwiastek kwadratowy z liczby ujemnej nie jest liczbą rzeczywistą, więc Math.sqrt(-4) zwraca NaN ("not a number", czyli "nie liczba") zamiast rzucać wyjątek. NaN rozprzestrzenia się na każde działanie, którego dotknie, więc jeśli możliwe są wartości ujemne, sprawdzaj dane przed liczeniem pierwiastka. Math.hypot(a, b) liczy bezpośrednio sqrt(a*a + b*b), co jest popularnym sposobem na odległość między dwoma punktami.
Math.abs: wartość bezwzględna
Math.abs(x) usuwa znak. W odróżnieniu od pow i sqrt zwraca ten sam typ, który dostaje: int dla int, double dla double.
Typowe zastosowanie to różnica, w której liczy się wielkość, a nie kierunek, np. odległość między dwiema pozycjami.
Math.max i Math.min
Math.max(a, b) zwraca większą z dwóch wartości, a Math.min(a, b) mniejszą. Przyjmują dokładnie dwa argumenty. Dla trzech lub więcej zagnieżdżaj wywołania:
Gdy dwa argumenty mają różne typy, węższy jest najpierw rozszerzany. Math.max(3, 7.5) porównuje dwie wartości double i zwraca double. Ostatni przykład ogranicza wartość do zakresu od 0 do 100: Math.min przycina ją do 100, a Math.max nie pozwala jej spaść poniżej 0.
Zaokrąglanie: round, floor, ceil
Java ma trzy metody zaokrąglania i różnią się zarówno kierunkiem, jak i typem zwracanym:
Math.roundzaokrągla do najbliższej liczby całkowitej. Wartość dokładnie w połowie zaokrągla się w górę, w stronę plus nieskończoności, więc2.5daje3, a-2.5daje-2. Dla argumentudoublezwracalong(a dlafloatzwracaint).Math.floorzawsze zaokrągla w dół, w stronę minus nieskończoności, i zwracadouble.Math.ceilzawsze zaokrągla w górę, w stronę plus nieskończoności, i zwracadouble.- Rzutowanie
(int)w ogóle nie jest zaokrąglaniem: odcina część ułamkową, co przesuwa liczby dodatnie w dół, a ujemne w górę.
Ponieważ Math.round(double) zwraca long, przypisanie wyniku do int bez rzutowania się nie kompiluje:
int n = Math.round(2.6); // error: incompatible types: possible lossy conversion from long to int
int m = (int) Math.round(2.6); // OK, m wynosi 3
long k = Math.round(2.6); // OK
Aby zaokrąglić do określonej liczby miejsc po przecinku, pomnóż, zaokrąglij i podziel z powrotem. Dzielenie przez 100.0 (double) zamiast przez 100 zachowuje część dziesiętną:
Druga linia dzieli long przez int, czyli wykonuje dzielenie całkowite, więc część dziesiętna przepada. Jeśli zaokrągloną liczbę trzeba tylko wyświetlić, String.format("%.2f", value) jest prostsze i nie zmienia przechowywanej wartości.
Math.random: liczby losowe
Math.random() zwraca double, który jest co najmniej 0.0 i mniejszy niż 1.0. Przy każdym wywołaniu wartość jest inna, więc wynik programów w tej sekcji zmienia się po każdym kliknięciu Run.
Aby dostać liczbę całkowitą z zakresu, rozciągnij tę wartość, zrzutuj ją i przesuń. Dla liczby całkowitej od min do max, oba końce włącznie:
int value = (int) (Math.random() * (max - min + 1)) + min;
Tak to działa dla kostki, gdzie min to 1, a max to 6:
Math.random() * 6dajedoubleod0.0do6.0, bez samego6.0.(int)odcina część ułamkową, co daje jedną z wartości0, 1, 2, 3, 4, 5.+ 1przesuwa ją do1, 2, 3, 4, 5, 6.
Pierwsza linia pokazuje pięć losowych rzutów. Druga sprawdza dziesięć tysięcy rzutów i w praktyce zawsze wypisuje lowest: 1, highest: 6: wzór dochodzi do obu końców zakresu i nigdy ich nie przekracza.
Nawiasy wokół Math.random() * (max - min + 1) mają znaczenie. Rzutowanie dotyczy wartości tuż po nim, więc (int) Math.random() * 6 najpierw rzutuje Math.random(). To zawsze daje 0, a 0 * 6 to 0, więc każdy "rzut" wychodzi taki sam.
Math.random() wystarcza do gier i ćwiczeń. W innych przypadkach klasa java.util.Random i ThreadLocalRandom.current().nextInt(min, max + 1) (w java.util.concurrent) zwracają liczby całkowite bezpośrednio, a Random może przyjąć ziarno (seed), aby w testach powtarzać tę samą sekwencję. Żadna z nich nie nadaje się do haseł ani tokenów bezpieczeństwa; do tego służy java.security.SecureRandom.
Math.PI i Math.E
Math.PI (π) i Math.E (liczba Eulera e) to stałe static final double:
Używaj ich zamiast wpisywać 3.14. Są tak dokładne, jak pozwala double, a nazwa mówi czytelnikowi, czym jest liczba.
Wyniki całkowite a wyniki double
Większość metod Math przyjmuje i zwraca double. Gdy podajesz im wartości int, Java automatycznie rozszerza argumenty do double, ale działania zapisane przed wywołaniem nadal wykonują się na int. Stąd bierze się większość błędnych wyników:
items / perBox to 7 / 2, a dzielenie dwóch wartości int odrzuca resztę, więc wynik to 3, zanim Math.ceil w ogóle go zobaczy. Math.ceil(3.0) to 3.0. Zamień jeden z operandów na double, rzutowaniem albo literałem takim jak 4.0, aby dzielenie zachowało część ułamkową. Strona o operatorach wyjaśnia dokładniej dzielenie całkowite.
Ogólna zasada: zdecyduj, jaki typ chcesz mieć na końcu, wykonuj dzielenie lub mnożenie na double, gdy liczą się ułamki, i rzutuj z powrotem na int albo long tylko raz, na samym końcu.
Inne przydatne metody
Kilka kolejnych metod z tej samej klasy, wywoływanych w ten sam sposób:
Math.logto logarytm naturalny;Math.log10to logarytm dziesiętny.Math.floorMod(a, b)daje resztę ze znakiemb, czyli to, czego potrzebujesz przy zawijaniu w obrębie zakresu, np. dni tygodnia. Operator%zachowuje znaka.- Metody trygonometryczne (
sin,cos,tan) przyjmują radiany. Stopnie najpierw zamień przezMath.toRadians. Math.addExact,Math.multiplyExacti pokrewne rzucająArithmeticExceptionprzy przepełnieniu, zamiast po cichu przeskoczyć do liczby ujemnej.
Najczęściej zadawane pytania
Jak używać Math.pow w Javie?
Math.pow(base, exponent) zwraca base podniesione do potęgi exponent jako double, więc Math.pow(2, 3) to 8.0. Aby zapisać wynik w int, zrzutuj go: int n = (int) Math.pow(2, 10); daje 1024. Java nie ma operatora potęgowania ^; ^ to bitowy XOR.
Jak wylosować liczbę z zakresu za pomocą Math.random?
Math.random() zwraca double od 0.0 do 1.0, bez samego 1.0. Aby dostać liczbę całkowitą od min do max włącznie, użyj (int) (Math.random() * (max - min + 1)) + min. Rzut kostką to (int) (Math.random() * 6) + 1.
Czy trzeba importować klasę Math w Javie?
Nie. Math należy do pakietu java.lang, który każdy plik Javy importuje automatycznie. Wszystkie jej metody są static, więc wywołujesz je na nazwie klasy, np. Math.sqrt(16), bez tworzenia obiektu.
Dlaczego Math.round zwraca long w Javie?
Math.round(double) zwraca long, bo double może przechowywać wartości dużo większe niż int. Przypisanie wyniku do int wymaga rzutowania: int n = (int) Math.round(2.6);. Math.round(float) zwraca int.
Czym różnią się Math.floor, Math.ceil i Math.round?
Math.floor zaokrągla w dół (2.7 daje 2.0, -2.3 daje -3.0), Math.ceil zaokrągla w górę (2.1 daje 3.0), a Math.round do najbliższej liczby całkowitej, przy czym połówki idą w górę (2.5 daje 3). floor i ceil zwracają double; round zwraca long.