0Pricing
Java Academy · Lekcja

Arytmetyka liczb całkowitych i przepełnienie

Poznaj dzielenie całkowitoliczbowe, modulo, działanie przepełnienia oraz sposoby jego wykrywania.

Arytmetyka liczb całkowitych i przepełnienie to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Arytmetyka liczb całkowitych i przepełnienie

Liczby całkowite w Javie mają stały rozmiar. Gdy obliczenie przekroczy wartość maksymalną lub minimalną, następuje ciche zawinięcie zakresu — nie jest zgłaszany żaden wyjątek. Zrozumienie tego mechanizmu pomaga zapobiegać trudnym do wykrycia błędom.

Zakresy liczb całkowitych

Każdy typ całkowity ma ograniczony zakres określony przez szerokość bitową:

  • byte: od -128 do 127
  • short: od -32 768 do 32 767
  • int: od -2 147 483 648 do 2 147 483 647
  • long: od -9.2 × 10^18 do 9.2 × 10^18
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Long.MAX_VALUE);    // 9223372036854775807
System.out.println(Byte.MAX_VALUE);    // 127

Przepełnienie: ciche zawijanie zakresu

Dodanie 1 do Integer.MAX_VALUE powoduje zawinięcie wartości do Integer.MIN_VALUE. Jest to arytmetyka w kodzie uzupełnień do dwóch — Java nie daje żadnej gwarancji i nie zgłasza żadnego wyjątku.

int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648 (overflow!)

byte b = 127;
b++;  // wraps to -128
System.out.println(b); // -128

// Real bug: counting votes in a large election with int
int votes = Integer.MAX_VALUE;
votes += 100; // silently wrong
System.out.println(votes); // negative number!

Wykrywanie przepełnienia za pomocą Math.addExact

Java 8+ wprowadziła Math.addExact(), multiplyExact() i subtractExact(), które w przypadku przepełnienia zgłaszają ArithmeticException zamiast cicho zawijać wartość.

try {
    int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("Overflow detected!"); // prints this
}

try {
    long safe = Math.multiplyExact(100_000L, 100_000L);
    System.out.println(safe); // 10000000000
} catch (ArithmeticException e) {
    System.out.println("Multiply overflow");
}

Dzielenie całkowite i modulo

Dzielenie całkowite obcina część ułamkową w kierunku zera. Operator % zwraca resztę z dzielenia ze znakiem dzielnej. Należy uważać na dzielenie przez zero — powoduje ono zgłoszenie ArithmeticException.

System.out.println(10 / 3);    // 3 (not 3.33)
System.out.println(10 % 3);    // 1
System.out.println(-10 % 3);   // -1 (sign follows dividend)
System.out.println(-10 % -3);  // -1

try {
    int x = 5 / 0; // ArithmeticException: / by zero
} catch (ArithmeticException e) {
    System.out.println(e.getMessage()); // / by zero
}

// Float division by zero gives Infinity, not exception
System.out.println(5.0 / 0); // Infinity

Arytmetyka long dla dużych liczb

Należy używać typu long, gdy wartości mogą przekroczyć zakres typu int. Zawsze należy dodawać L do literałów typu long, aby zapobiec przepełnieniu przed przypisaniem wartości.

// Bug: multiplication done as int, then widened
long wrong = 1_000_000 * 1_000_000;   // overflows int!
System.out.println(wrong); // -727379968 (wrong!)

// Fix: one operand is long
long correct = 1_000_000L * 1_000_000L;
System.out.println(correct); // 1000000000000

// Or cast first
long alsOk = (long) 1_000_000 * 1_000_000;
System.out.println(alsOk); // 1000000000000

Operatory przesunięcia bitowego

Operatory przesunięcia bitowego to szybkie sposoby mnożenia i dzielenia przez potęgi liczby 2:

  • n << k — przesunięcie w lewo: mnożenie przez 2^k
  • n >> k — arytmetyczne przesunięcie w prawo: dzielenie przez 2^k
  • n >>> k — przesunięcie w prawo bez znaku: uzupełnianie zerami
int n = 8;
System.out.println(n << 1);  // 16 (8 * 2)
System.out.println(n << 2);  // 32 (8 * 4)
System.out.println(n >> 1);  // 4  (8 / 2)
System.out.println(n >> 2);  // 2  (8 / 4)

// Check if number is power of 2
boolean isPow2 = n > 0 && (n & (n - 1)) == 0;
System.out.println(isPow2); // true

Bitowe AND, OR i XOR

Operatory bitowe działają na pojedynczych bitach i są używane w uprawnieniach, flagach oraz protokołach niskopoziomowych.

int a = 0b1010; // 10
int b = 0b1100; // 12

System.out.println(Integer.toBinaryString(a & b)); // 1000 (AND = 8)
System.out.println(Integer.toBinaryString(a | b)); // 1110 (OR  = 14)
System.out.println(Integer.toBinaryString(a ^ b)); // 0110 (XOR = 6)
System.out.println(Integer.toBinaryString(~a));    // ...11110101 (NOT)

// Permission flags example
int READ  = 0b001;
int WRITE = 0b010;
int EXEC  = 0b100;
int perms = READ | WRITE; // user has read+write
System.out.println((perms & EXEC) != 0); // false — no exec

Podkreślenia w literałach liczbowych

Java 7+ pozwala używać podkreśleń w literałach liczbowych, aby poprawić ich czytelność. Kompilator je ignoruje.

int million = 1_000_000;
long creditCard = 4_111_1111_1111_1111L;
double pi = 3.141_592_653_589_793;
int hex = 0xFF_EC_D1_2E;
int binary = 0b0001_0101_0110;

System.out.println(million);   // 1000000
System.out.println(creditCard); // 4111111111111111

BigInteger dla dowolnej precyzji

Gdy wartości przekraczają zakres typu long, należy użyć BigInteger. Nie występuje w nim przepełnienie, ale jest wolniejszy od typów prymitywnych. Używaj go do kluczy kryptograficznych, silni i liczb astronomicznych.

import java.math.BigInteger;

BigInteger factorial100 = BigInteger.ONE;
for (int i = 2; i <= 100; i++) {
    factorial100 = factorial100.multiply(BigInteger.valueOf(i));
}
System.out.println(factorial100.toString().length() + " digits"); // 158 digits

BigInteger a = new BigInteger("999999999999999999999999999999");
BigInteger b = new BigInteger("1");
System.out.println(a.add(b)); // 1000000000000000000000000000000

Praktyka: licznik odporny na przepełnienie

Wzorzec implementowania licznika, który bezpiecznie obsługuje przepełnienie, korzystając z Math.addExact i w razie potrzeby przechodząc na Long.MAX_VALUE.

class SafeCounter {
    private long count = 0;

    public void increment() {
        try {
            count = Math.addExact(count, 1L);
        } catch (ArithmeticException e) {
            count = Long.MAX_VALUE; // cap at max
        }
    }

    public long get() { return count; }
}

SafeCounter sc = new SafeCounter();
sc.increment();
sc.increment();
System.out.println(sc.get()); // 2

Szybkie sprawdzenie

Jaka jest wartość poniższego wyrażenia?

long result = 1_000_000 * 1_000_000;
System.out.println(result);

Podsumowanie: arytmetyka całkowita i przepełnienie

Najważniejsze informacje:

  • Przepełnienie liczb całkowitych powoduje ciche zawijanie wartości — domyślnie nie jest zgłaszany wyjątek
  • Używaj Math.addExact/multiplyExact/subtractExact, aby wykrywać przepełnienie
  • Dzielenie całkowite obcina wynik w kierunku zera; znak operatora % jest zgodny ze znakiem dzielnej
  • Używaj literałów typu long (sufiks L), gdy wyniki pośrednie mogą spowodować przepełnienie typu int
  • BigInteger obsługuje dowolnie duże wartości bez przepełnienia
  • Operatory przesunięcia bitowego są szybką alternatywą dla mnożenia i dzielenia przez potęgę dwójki

Często zadawane pytania

Czy lekcja „Arytmetyka liczb całkowitych i przepełnienie” jest bezpłatna?

Tak — pełny tekst „Arytmetyka liczb całkowitych i przepełnienie” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Arytmetyka liczb całkowitych i przepełnienie”?

Poznaj dzielenie całkowitoliczbowe, modulo, działanie przepełnienia oraz sposoby jego wykrywania. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Arytmetyka liczb całkowitych i przepełnienie”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Najważniejsze elementy klasy Math
  2. Arytmetyka liczb całkowitych i przepełnienie
  3. BigDecimal w obliczeniach finansowych
  4. NumberFormat i printf
← Powrót do Java Academy