Java Academy · Oppitunti

Kokonaislukulaskenta ja ylivuoto

Ymmärrä kokonaislukujen jakolasku, jakojäännös, ylivuodon toiminta ja sen havaitseminen.

Oppitunti 2/413 vaihetta

Kokonaislukulaskenta ja ylivuoto on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Kokonaislukuaritmetiikka ja ylivuoto

Java-kokonaisluvuilla on kiinteä koko. Kun laskutoimituksen tulos ylittää suurimman tai pienimmän mahdollisen arvon, se kiertyy hiljaisesti ympäri — poikkeusta ei heitetä. Tämän ymmärtäminen auttaa estämään vaikeasti havaittavia virheitä.

Kokonaislukujen arvoalueet

Jokaisella kokonaislukutyypillä on bittileveyden määrittämä rajattu arvoalue:

  • byte: -128–127
  • short: -32,768–32,767
  • int: -2,147,483,648–2,147,483,647
  • long: -9.2 × 10^18–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

Ylivuoto: hiljainen kiertyminen

Kun arvoon Integer.MAX_VALUE lisätään 1, tulokseksi tulee Integer.MIN_VALUE. Tämä on kahden komplementin aritmetiikkaa — Java ei ilmoita siitä eikä heitä poikkeusta.

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!

Ylivuodon havaitseminen Math.addExact-metodilla

Java 8:ssa ja sitä uudemmissa versioissa esiteltiin Math.addExact()-, multiplyExact()- ja subtractExact()-metodit. Ne heittävät ArithmeticException-poikkeuksen ylivuodon sattuessa sen sijaan, että arvo kiertyisi hiljaisesti.

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");
}

Kokonaislukujako ja jakojäännös

Kokonaislukujako katkaisee tuloksen kohti nollaa. %-operaattori antaa jakojäännöksen, jolla on jakajan sijaan jaettavan luvun etumerkki. Varo jakamista nollalla — se heittää ArithmeticException-poikkeuksen.

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

Suurten lukujen laskeminen long-tyypillä

Käyttäkää long-tyyppiä, kun arvot voivat ylittää int-tyypin arvoalueen. Lisätkää aina L long-literaaleihin, jotta ylivuoto estetään ennen sijoittamista.

// 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

Bittisiirto-operaattorit

Bittisiirto-operaattorit ovat nopea tapa kertoa tai jakaa kahden potensseilla:

  • n << k — vasemmalle siirto: kertominen luvulla 2^k
  • n >> k — etumerkillinen oikealle siirto: jakaminen luvulla 2^k
  • n >>> k — etumerkitön oikealle siirto: täyttää vasemmalta 0-biteillä
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

Bittikohtainen AND, OR ja XOR

Bittikohtaiset operaattorit käsittelevät yksittäisiä bittejä, ja niitä käytetään käyttöoikeuksissa, lipuissa ja matalan tason protokollissa.

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

Alaviivat numeerisissa literaaleissa

Java 7:stä alkaen numeerisissa literaaleissa voi käyttää alaviivoja luettavuuden parantamiseksi. Kääntäjä jättää ne huomiotta.

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 mielivaltaista tarkkuutta varten

Kun arvot ylittävät long-tyypin alueen, käyttäkää BigInteger-tyyppiä. Se ei aiheuta ylivuotoa, mutta on primitiivityyppejä hitaampi. Käyttäkää sitä salausavaimiin, kertomiin ja tähtitieteellisen suuriin lukuihin.

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

Käytännössä: ylivuototurvallinen laskuri

Malli sellaisen laskurin toteuttamiseen, joka käsittelee ylivuodot turvallisesti käyttämällä Math.addExact-menetelmää ja palaamalla tarvittaessa arvoon 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

Pikatarkistus

Mikä on seuraavan lausekkeen arvo?

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

Kertaus: kokonaislukulaskenta ja ylivuoto

Keskeiset opit:

  • Kokonaislukujen ylivuoto kiertyy huomaamatta – poikkeusta ei oletusarvoisesti heitetä
  • Ylivuodon havaitsemiseen käyttäkää Math.addExact-, multiplyExact- ja subtractExact-menetelmiä
  • Kokonaislukujako katkaisee tuloksen kohti nollaa; %-operaattorin merkki määräytyy jaettavan luvun mukaan
  • Käyttäkää long-vakioita (L-pääte), kun välitulokset voivat aiheuttaa int-tyypin ylivuodon
  • BigInteger käsittelee mielivaltaisen suuria arvoja ilman ylivuotoa
  • Bittisiirto-operaattorit ovat nopeita vaihtoehtoja kahden potenssilla kertomiselle ja jakamiselle
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Kokonaislukulaskenta ja ylivuoto” ilmainen?

Kyllä – oppitunnin ”Kokonaislukulaskenta ja ylivuoto” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Kokonaislukulaskenta ja ylivuoto”?

Ymmärrä kokonaislukujen jakolasku, jakojäännös, ylivuodon toiminta ja sen havaitseminen. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Kokonaislukulaskenta ja ylivuoto”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Math-luokan perusteet
  2. Kokonaislukulaskenta ja ylivuoto
  3. BigDecimal talouslaskennassa
  4. NumberFormat ja printf
← Takaisin: Java Academy