Gdzie się kończą granice, a jednak nadal mają swój ciąg - tam zaczyna się nieskończoność!
Ale żeby dokładniej wiedzieć, z czym mamy do czynienia, użyjmy operatora typeof, aby dowiedzieć się z jakim typem danych mamy do czynienia!
typeof Infinity // "number"
Przyjrzyjmy się pierwszemu przypadkowi Infinity
1 / 0 //Infinity
1 / -0 //-Infinity
Dlaczego tak się dzieje?
To wynika z matematycznej koncepcji granic:
$$\lim_{x \to 0^+} \frac{1}{x} = +\infty$$$$\lim_{x \to 0^-} \frac{1}{x} = -\infty$$Gdy dzielimy przez liczbę coraz bliższą zeru od strony dodatniej ($0^+$), wynik rośnie do $+\infty$.
Gdy dzielimy przez liczbę coraz bliższą zeru od strony ujemnej ($0^-$), wynik maleje do $-\infty$.
JavaScript rozróżnia +0 i -0, dlatego 1/0 daje Infinity, a 1/-0 daje -Infinity.
Jak widać - nie trzeba było się zbytnio natrudzić, aby zobaczyć ten przypadek w akcji.
Spróbujmy jej zatem poszukać :)
let value = 1;
while (value !== Infinity) {
let next = value * 2;
if (next === Infinity) {
console.log('Ostatnia wartość:', value.toExponential());
console.log('Następna wartość:', next);
break;
}
value = next;
}
Output:
Ostatnia wartość: 8.98846567431158e+307
Następna wartość: Infinity
Jak widać - znalezienie nieskończoności nie jest takie trudne - JavaScript nam to znacznie ułatwia podając na tacy wartość maksymalną przed wkroczeniem w Infinity zamiast żmudnego i niewydajnego iterowania:
Number.MAX_VALUE
Output:
1.7976931348623157e+308
Co 1.7976931348623157e+308 przed nieskończonością (Infinity) reprezentuje?
179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
000,000,000,000,000
To niewyobrażalnie wielka liczba, większa niż liczba atomów we wszechświecie $\sim 10^{80}$ czy liczba możliwych partii szachowych $\sim 10^{120}$.
Dlaczego zatem taka wartość? W czasach definiowania standardu w 1985 roku pamięć RAM była droga, a wybór 64 bitów dla double to świadoma decyzja projektowa.
Ta wartość wystarczy do obliczeń inżynierskich, większości symulacji fizycznych, astronomii i w finansach.
Tak więc to był wystarczający kompromis dla dobrej precyzji (15-17 cyfr), efektywnej dla sprzętu i uniwersalnej (wspieranej przez każdy procesor).
Standard IEEE 754 jako regulator Infinity
W standardzie IEEE 754 zostały zdefiniowane zarówno NaN, jak i Infinity, więc to nie jest tylko feature JavaScript, ale również innych języków programowania!
#include <iostream>
#include <limits>
int main()
{
double max = std::numeric_limits<double>::max();
double inf = std::numeric_limits<double>::infinity();
if (inf > max)
std::cout << inf << " is greater than " << max << '\n';
}
Output:
inf is greater than 1.79769e+308
Dlaczego zamiast liczby został wypisany inf?
Infinity to wartość, którą da się przedstawić bitowo, ale która nie reprezentuje żadnej konkretnej wartości liczbowej - zamiast tego reprezentuje koncepcję matematycznej nieskończoności. Zatem jeśli ktoś by chciał wypisać surowe bity to w odpowiedzi otrzymałby
+Infinity = 0x7FF0000000000000
-Infinity = 0xFFF0000000000000
inf jest po prostu czytelniejsze i wygodniejsze od reprezentacji bitowej, tak samo jak Infinity w JavaScript.
Po co więc ten koncept został wprowadzony w standardzie IEEE 754?
Zamiast przerywać działanie programu przy dzieleniu przez zero lub overflow, IEEE 754 daje wartość, z którą można dalej pracować:
const result = calculate_something();
if (result === Infinity) {
console.error("Wartość za duża!");
return Number.MAX_VALUE;
}
Bez Infinity - crash lub losowe zachowanie.
Również dzięki Infinity zachowujemy matematyczną poprawność
1 / Infinity === 0 // lim(1/x) gdy x→∞
Infinity + 5 === Infinity // ∞ + c = ∞
Infinity * Infinity // ∞ × ∞ = ∞
Ale uwaga - niektóre operacje z Infinity dają NaN (nieokreślone):
Infinity - Infinity // NaN (∞ - ∞ jest nieokreślone)
Infinity * 0 // NaN (∞ × 0 jest nieokreślone)
Infinity / Infinity // NaN (∞ / ∞ jest nieokreślone)
Przykładowe zastosowania
Wyłączenie timeout:
const config = {
timeout: debugMode ? Infinity : 5000 // brak timeout w debug
};
setTimeout(() => {
console.log('To się nigdy nie wykona');
}, config.timeout);
Uwaga: Niektóre przeglądarki limitują timeout do 32-bit int (~24 dni max).
Infinitymoże zostać przekonwertowane do tej wartości.
Sortowanie:
const items = [
{ name: 'Alice', priority: 1 },
{ name: 'Bob', priority: 2 },
{ name: 'System', priority: Infinity } // Zawsze na końcu
];
items.sort((a, b) => a.priority - b.priority);
Links:
