CodeGym /Kursy /JAVA 25 SELF /Wprowadzenie do liczb zmiennoprzecinkowych i typu double

Wprowadzenie do liczb zmiennoprzecinkowych i typu double

JAVA 25 SELF
Poziom 6, Lekcja 2
Dostępny

1. Liczby zmiennoprzecinkowe

Załóżmy, że postanowiłeś napisać najprostszy kalkulator. Albo dowolny inny program, w którym potrzebne są obliczenia (od banalnego liczenia pieniędzy po złożoną fizykę). Nie wszystko w prawdziwym życiu to liczby całkowite — i nic na to nie poradzimy!

Zatem uzbrójmy się w nowy typ danych!

W programowaniu liczby ułamkowe nazywa się też rzeczywistymi lub liczbami zmiennoprzecinkowymi (floating-point). W Javie, podobnie jak w większości języków, służą one do przechowywania nie tylko liczb całkowitych, ale też „ułamkowych” wartości: różnych 3.14, -28.57, 2.718281828...

Liczby zmiennoprzecinkowe występują w dwóch podstawowych typach:

Typ Przechowuje Zakres wartości (w przybliżeniu) Precyzja Typowy rozmiar
float
Liczby ±1.5 × 10-45 ... ±3.4 × 1038 ~7 cyfr po przecinku 4 bajty
double
Liczby ±5.0 × 10-324 ... ±1.7 × 10308 ~15–16 cyfr po przecinku 8 bajtów

Typ float

Typ float wziął nazwę od floating-point number — liczby zmiennoprzecinkowej. Liczby rzeczywiste to pojęcie z matematyki, mają określone własności. Komputer ma jednak wiele ograniczeń. Dlatego nie do końca poprawnie jest nazywać liczby ułamkowe w Javie rzeczywistymi. Używa się określenia „liczby zmiennoprzecinkowe”.

Typ float zwykle przechowuje 7 cyfr znaczących (np. 0.1234567), wykładnik dziesiątki i zajmuje 4 bajty pamięci. To bardzo mało do dokładnych obliczeń, dlatego szybko przeszło się na liczby o podwójnej precyzji.

Typ double

Typ double zawdzięcza nazwę podwójnej (double) precyzji. Zajmuje w pamięci 8 bajtów (2 razy więcej niż float) i może przechowywać do 15 cyfr znaczących: 0.123456789012345. To w zupełności wystarcza dla większości obliczeń na liczbach ułamkowych, dlatego double jest podstawowym typem do przechowywania liczb zmiennoprzecinkowych w Javie.

W tym wykładzie główny akcent położymy na typie double: domyślnie jest on polecany dla wszystkich „zwykłych” liczb ułamkowych. Dalej omówimy też typ float.

2. Deklaracja i inicjalizacja zmiennych typu double

Wszystko jak z int — tylko teraz używamy double.

// Deklarujemy zmienną i przypisujemy jej wartość Pi
double pi = 3.1415926;

// Można zadeklarować także bez inicjalizacji
double averageSalary;
averageSalary = 91234.56;

// Można wykonywać obliczenia!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (a nie 2)

Cechy składni:

  • Jako separator dziesiętny używa się kropki (3.14). Jeśli użyjesz przecinka — dostaniesz błąd kompilacji!
  • Ściśle rzecz biorąc, zapisując double d = 3;, nie otrzymasz błędu — typy zostaną automatycznie dopasowane (liczba całkowita zamienia się na „zmiennoprzecinkową” bez strat).

3. Wejście i wyjście liczb zmiennoprzecinkowych za pomocą Scanner

Najpierw spróbujmy wypisać liczbę ułamkową:

double amount = 42.75;
System.out.println(amount); // Wypisze: 42.75

Wszystko w porządku! A jeśli dodamy tekst:

System.out.println("Na twoim koncie: " + amount + " euro."); // Na twoim koncie: 42.75 euro.

Wprowadzanie z klawiatury

Do wczytania double należy użyć specjalnej metody klasy Scanner: console.nextDouble().

Scanner console = new Scanner(System.in);

System.out.println("Podaj temperaturę na zewnątrz:");
double temperature = console.nextDouble(); // Od razu wczytujemy double

System.out.println("Na zewnątrz jest: " + temperature + " stopni.");

4. Typ double w działaniu: arytmetyka

Wszystkie standardowe operacje (+, -, *, /) działają tak samo jak dla int:

double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25

System.out.println("Średnia prędkość: " + speed); // Średnia prędkość: 50.25

I to cała arytmetyka. Jedyna różnica: wynik dzielenia — zawsze liczba ułamkowa, jeśli przynajmniej jeden z operandów to double.

Porównanie z int

int a = 5, b = 2;
System.out.println(a / b); // 2 (reszta jest odrzucana)

double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5

5. Typowe błędy i osobliwości przy pracy z double

Błąd konwersji wejścia

Klasyczna sytuacja: użytkownik wpisuje 3,14 — a program oczekuje 3.14. W Javie metoda Scanner.nextDouble() kieruje się bieżącą lokalizacją: w lokalizacji rosyjskiej/niemieckiej przecinek jest dopuszczalny, w angielskiej potrzebna jest kropka. W razie potrzeby ustaw Scanner na odpowiednią lokalizację lub wczytaj ciąg i sparsuj ręcznie.

// To spowoduje problem w Locale.US, jeśli wpisano "3,14"
double value = console.nextDouble();

Błąd „niedokładności” liczb w komputerze

Tu zwykle pojawia się lekkie zdziwienie:

double x = 0.1 + 0.2;
System.out.println(x); // Hm... 0.30000000000000004

Gratulacje, zetknąłeś się z „magią” reprezentacji liczb ułamkowych wewnątrz komputera. Chodzi o to, że wielu liczb nie da się dokładnie przedstawić w systemie binarnym. Zwykle nie jest to krytyczne dla większości aplikacji, ale ma znaczenie w finansach i naukach ścisłych.

6. Ważne: double i int — konwersja automatyczna i jawna

Zdarza się, że dodajesz liczbę całkowitą i ułamkową albo przypisujesz int do zmiennej double — błędów nie będzie:

int i = 2;
double d = i; // Wszystko ok!
System.out.println(d); // 2

double dd = 3.7;
int ii = (int) dd; // Trzeba jawnie rzutować typ double na typ int!
System.out.println(ii); // 3, część ułamkowa została odcięta

Często to zaskakuje — dlaczego po rzutowaniu część ułamkowa zniknęła? Po prostu dlatego, że typ int nie potrafi przechowywać ułamków (wszystko, co po kropce, znika na zawsze).

Więcej o konwersji double do int i operatorze (int) w następnej lekcji.

7. Formatowane wyjście: ładnie wypisujemy double

Często domyślnie double jest wypisywane z masą zbędnych zer. Można sformatować wyjście:

double temp = 23.56789;
System.out.println(temp); // 23.56789

// 2 miejsca po przecinku
System.out.println(String.format("%.2f", temp)); // 23.57

// 1 miejsce po przecinku
System.out.println(String.format("%.1f%n", temp)); // 23.6
Format Wynik Opis
"%.2f"
23.57 liczba z 2 miejscami po przecinku
"%.1f"
23.6 liczba z 1 miejscem po przecinku

8. Typowe błędy przy pracy z float i double

Błąd nr 1: niejawna konwersja double do float

float f = 1.23; // Błąd!

Kompilator będzie niezadowolony: „Próbujesz włożyć double do float — to może prowadzić do utraty precyzji!” Zawsze dodawaj sufiks f.

Błąd nr 2: zapomniano, że dzielenie dwóch int daje wynik typu int

int a = 7, b = 2;
double result = a / b; // 3.0, a nie 3.5

Aby uzyskać część ułamkową, jawnie skonwertuj przynajmniej jeden operand:

double result = (double) a / b; // 3.5

Błąd nr 3: porównywanie liczb ułamkowych

Nie porównuj liczb zmiennoprzecinkowych na równość operatorem ==. Używaj porównania z niewielką tolerancją (epsilon).

Błąd nr 4: utrata precyzji w float

Nie przechowuj dużych liczb ani bardzo dokładnych wartości w float — mogą się „zepsuć” lub utracić istotne cyfry.

1
Zadanie
JAVA 25 SELF, poziom 6, lekcja 2
Niedostępne
Obliczanie średniej prędkości statku kosmicznego 🚀
Obliczanie średniej prędkości statku kosmicznego 🚀
1
Zadanie
JAVA 25 SELF, poziom 6, lekcja 2
Niedostępne
Przyjmowanie płatności w inteligentnym automacie vendingowym 💰
Przyjmowanie płatności w inteligentnym automacie vendingowym 💰
1
Zadanie
JAVA 25 SELF, poziom 6, lekcja 2
Niedostępne
Formatowanie cen na witrynie sklepu internetowego 🛍️
Formatowanie cen na witrynie sklepu internetowego 🛍️
1
Zadanie
JAVA 25 SELF, poziom 6, lekcja 2
Niedostępne
Dzielenie magicznych jabłek między przyjaciółmi-poszukiwaczami przygód 🍎
Dzielenie magicznych jabłek między przyjaciółmi-poszukiwaczami przygód 🍎
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION