Ignoruje mě: pojďme si to zapsat popořadě.
V této kapitole se budeme zabývat pouze prvním typem čísel: čísly typu číslo . Pojďme se hlouběji ponořit do toho, jak s nimi pracovat v JavaScriptu.
Způsoby psaní čísel
Představte si, že si potřebujeme zapsat číslo 1 miliarda. Nejviditelnější způsob:
let billion = 1000000000; Jako oddělovač můžeme také použít podtržítko _:
let billion = 1_000_000_000 Znak podtržítka _ je „syntaktický cukr“, díky kterému je číslo čitelnější. JavaScript engine jednoduše ignoruje _ mezi číslicemi, takže výše uvedený příklad skončí přesně stejnou miliardou jako první příklad.
V reálném životě se však obecně snažíme vyhnout psaní dlouhých sekvencí nul, protože je snadné udělat chybu. Zkrácená verze může vypadat jako „1 miliarda“ nebo „7.3 miliardy“ za 7 miliard 300 milionů. Tento princip funguje pro všechna velká čísla.
V JavaScriptu ke zkrácení čísla můžeme k němu připojit písmeno „e“ a zadat požadovaný počet nul:
let billion = 1e9; // 1 миллиард, буквально: 1 и 9 нулей alert( 7.3e9 ); // 7.3 миллиарда (7,300,000,000) Jinými slovy, „e“ násobí číslo 1 se zadaným počtem nul.
1e3 === 1 * 1000 // e3 означает *1000 1.23e6 === 1.23 * 1000000 // e6 означает *1000000 Nyní si zapišme něco velmi malého. Například 1 mikrosekunda (jedna miliontina sekundy):
let mcs = 0.000001; V tomto případě nám pomůže i „e“. Pokud se chceme vyhnout psaní dlouhé sekvence nul, můžeme to udělat takto:
let ms = 1e-6; // шесть нулей слева от 1 Pokud spočítáme počet nul v 0.000001 , bude jich 6. Přirozeně správné zadání je 1e-6 .
Jinými slovy, záporné číslo za „e“ znamená dělení 1 se zadaným počtem nul:
// 1 делится на 1 с 3 нулями 1e-3 === 1 / 1000 (=0.001) // 1.23 делится на 1 с 6 нулями 1.23e-6 === 1.23 / 1000000 (=0.00000123) Hexadecimální, binární a osmičková čísla
Hexadecimální čísla se v JavaScriptu široce používají k reprezentaci barev, kódování znaků a dalších. Samozřejmostí je krátký zápis: 0x , za kterým následuje číslo.
alert( 0xff ); // 255 alert( 0xFF ); // 255 (то же самое, регистр не имеет значения) Binární a osmičková čísla se nepoužívají tak často, ale jsou také podporovány: 0b pro binární a 0o pro osmičkové:
let a = 0b11111111; // двоичная (бинарная) форма записи числа 255 let b = 0o377; // восьмеричная форма записи числа 255 alert( a == b ); // true, с двух сторон число 255 Existují pouze 3 číselné systémy s takovou podporou. Pro jiné číselné soustavy doporučujeme použít funkci parseInt (probrána dále v této kapitole).
toString(základ)
Metoda num.toString(base) vrací řetězcovou reprezentaci čísla num v základním číselném systému.
let num = 255; alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111 základna se může pohybovat od 2 do 36 (výchozí je 10).
- základ = 16 — pro hexadecimální znázornění barvy, kódování znaků atd. mohou být čísla 0..9 nebo A..F .
- základ = 2 – obvykle se používá k ladění bitových operací, číslice 0 nebo 1 .
- základ = 36 — maximální základ, čísla mohou být 0..9 nebo A..Z. To znamená, že k reprezentaci čísla se používá celá latinská abeceda. Zajímavé je, že k získání krátké reprezentace velkého číselného identifikátoru můžete použít 36bitový číselný systém. Chcete-li například vytvořit krátký odkaz. Za tímto účelem jej jednoduše převedeme na 36bitový číselný systém:
alert( 123456..toString(36) ); // 2n9c Dvě tečky pro volání metody
Pozor! Dvě tečky v 123456..toString(36) nejsou překlep. Pokud potřebujeme zavolat metodu přímo na číslo, jako je toString v příkladu výše, musíme za číslo vložit dvě tečky ..
Pokud vložíme jednu tečku: 123456.toString(36), bude to chyba, protože syntaxe JavaScriptu předpokládá, že desetinná část začíná za první tečkou. A pokud vložíte dvě tečky, JavaScript pochopí, že chybí desetinná část, a metoda začíná.
Lze také zapsat jako (123456).toString(36) .
Zaokrouhlování
Jednou z často používaných operací při práci s čísly je zaokrouhlování.
JavaScript má několik vestavěných funkcí pro řešení zaokrouhlování:
Math.floor Zaokrouhlí dolů: 3.1 se změní na 3 a -1.1 na -2. Math.ceil Zaokrouhlení nahoru: 3.1 bude 4 a -1.1 bude -1. Math.round Zaokrouhlí na nejbližší celé číslo: 3.1 se stane 3 , 3.6 se stane 4 a -1.1 se stane -1 . Math.trunc (nepodporováno v aplikaci Internet Explorer) Provádí zlomkové zkrácení bez zaokrouhlování: 3.1 se změní na 3 a -1.1 na -1.
Níže je tabulka znázorňující rozdíly mezi funkcemi zaokrouhlování:
| Matematika.podlaha | Math.ceil | Math.kolo | Math.trunc | |
|---|---|---|---|---|
| 3.1 | 3 | 4 | 3 | 3 |
| 3.6 | 3 | 4 | 4 | 3 |
| -1.1 | -2 | -1 | -1 | -1 |
| -1.6 | -2 | -1 | -2 | -1 |
Tyto funkce pokrývají všechny možné způsoby zacházení s desetinnou částí. Co když potřebujeme zaokrouhlit číslo na n-tý počet číslic ve zlomkové části?
Například máme 1.2345 a chceme číslo zaokrouhlit na 2 desetinná místa, takže zůstane pouze 1.23 .
Existují dvě řešení:
- Násobte a rozdělte. Chcete-li například zaokrouhlit číslo na druhé desetinné místo, můžeme číslo vynásobit 100, zavolat funkci zaokrouhlení a vydělit zpět.
let num = 1.23456; alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 let num = 12.34; alert( num.toFixed(1) ); // "12.3" Zaokrouhlí hodnotu na nejbližší celé číslo, buď nahoru nebo dolů, podobně jako metoda Math.round:
let num = 12.36; alert( num.toFixed(1) ); // "12.4" Všimněte si, že výsledkem toFixed je řetězec. Pokud je desetinná část kratší, než je nutné, budou na konec řetězce přidány nuly:
let num = 12.34; alert( num.toFixed(5) ); // "12.34000", добавлены нули, чтобы получить 5 знаков после запятой Nepřesné výpočty
V JavaScriptu je číslo reprezentováno jako 64bitový formát IEEE-754. K uložení čísla se používá 64 bitů: 52 z nich se používá k uložení číslic, 11 k uložení pozice desetinné čárky a jeden bit k uložení znaménka.
Pokud je číslo příliš velké, přeteče 64bitové úložiště, JavaScript vrátí nekonečno:
alert( 1e500 ); // Infinity Nejčastější chybou při práci s čísly v JavaScriptu je ztráta přesnosti.
Podívejte se na toto (nesprávné!) srovnání:
alert( 0.1 + 0.2 == 0.3 ); // false Ano, ano, součet 0.1 a 0.2 se nerovná 0.3.
Zvláštní! Co pak, když ne 0.3?
alert( 0.1 + 0.2 ); // 0.30000000000000004 Ó! Je zde mnohem více důsledků než jen nesprávné srovnání. Představte si, že vytváříte internetový obchod a návštěvníci zadají objednávku na 2 položky za 0.10 USD a 0.20 USD. Konečná objednávka bude 0.30000000000000004 $. To bude překvapení pro všechny.
Ale proč se to děje?
Číslo je uloženo v paměti v binárním tvaru jako posloupnost bitů – jedniček a nul. Ale zlomky jako 0.1, 0.2, které vypadají v desítkové soustavě docela jednoduše, jsou ve skutečnosti nekonečné zlomky v binárním tvaru.
alert(0.1.toString(2)); // 0.0001100110011001100110011001100110011001100110011001101 alert(0.2.toString(2)); // 0.001100110011001100110011001100110011001100110011001101 alert((0.1 + 0.2).toString(2)); // 0.0100110011001100110011001100110011001100110011001101 Jinými slovy, kolik je 0.1? To je jedna dělená deseti – 1/10, jedna desetina. V desítkové soustavě jsou taková čísla snadno reprezentována ve srovnání s jednou třetinou: 1/3 , což se stane nekonečným zlomkem 0.33333(3) .
Dělení 10 zaručeně funguje dobře v desítkové soustavě, ale dělení 3 nikoliv. Ze stejného důvodu bude v binární soustavě vždy fungovat dělení 2 a 1/10 se stane nekonečným zlomkem.
JavaScript nemá žádný způsob, jak uložit přesné hodnoty 0.1 nebo 0.2 pomocí binárního systému, stejně jako nemá žádný způsob, jak uložit jednu třetinu v desítkové soustavě.
Formát čísel IEEE-754 řeší tento problém zaokrouhlením na nejbližší možné číslo. Pravidla zaokrouhlování nám obvykle brání vidět tuto „malou ztrátu přesnosti“, ale existuje.
alert( 0.1.toFixed(20) ); // 0.10000000000000000555 A když sečteme dvě čísla, sečtou se i jejich „nepřesnosti“.
Proto 0.1 + 0.2 není přesně 0.3.
Nejen v JavaScriptu
Abychom byli spravedliví, chyba přesnosti s plovoucí desetinnou čárkou přetrvává ve všech ostatních jazycích, které používají formát IEEE 754, včetně PHP, Java, C, Perl a Ruby.
Existuje způsob, jak tento problém obejít? Samozřejmě nejspolehlivějším způsobem je zaokrouhlit výsledek pomocí metody toFixed(n):
let sum = 0.1 + 0.2; alert( sum.toFixed(2) ); // "0.30" Pamatujte, že metoda toFixed vždy vrací řetězec. Tím je zajištěno, že výsledek bude mít zadaný počet číslic v desetinné části. Je to také výhodné pro formátování cen v internetovém obchodě 0.30 $. V ostatních případech můžete použít unární operátor + k převodu řetězce na číslo:
let sum = 0.1 + 0.2; alert( +sum.toFixed(2) ); // 0.3 Číslo můžete také dočasně vynásobit 100 (nebo více), abyste je dostali na celé číslo, provést výpočet a poté je vydělit zpět. Sečtením celých čísel chybu snížíme, ale stále se objevuje v konečném dělení:
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 Metoda násobení/dělení tedy chybu snižuje, ale zcela ji nevyřeší.
Někdy se můžete pokusit zlomky úplně odstranit. Například když v našem internetovém obchodě začneme používat centy místo dolarů. Co když ale uplatníme 30% slevu? Zlomku se v praxi nezbavíme úplně. Stačí v případě potřeby použít zaoblení k odříznutí „ocásků“.
Zkuste to provést:
// Привет! Я – число, растущее само по себе! alert( 9999999999999999 ); // покажет 10000000000000000 Důvod je stejný – ztráta přesnosti. Z 64 bitů přidělených číslu samotné číslice čísla zabírají až 52 bitů, zbylých 11 bitů ukládá pozici desetinné tečky a jeden bit – znaménko. Pokud tedy na čísla nestačí 52 bitů, pak se při zápisu ztratí nejméně významné číslice.
Interpret neukáže chybu, ale výsledkem bude „ne zcela správné číslo“, což vidíme v příkladu výše. Jak se říká: „Napsal jsem to, jak nejlépe jsem uměl.“
Dalším vtipným důsledkem vnitřní reprezentace čísel je přítomnost dvou nul: 0 a -0 .
Je to proto, že znaménko je reprezentováno samostatným bitem, takže libovolné číslo může být kladné nebo záporné, včetně nuly.
Ve většině případů je toto chování neviditelné, protože operátory JavaScriptu s nimi zacházejí stejně.
Zkontrolujte: isFinite a isNaN
Pamatujete si ty speciální číselné hodnoty?
- Nekonečno (a -Nekonečno ) je speciální číselná hodnota, která se chová přesně jako matematické nekonečno ∞.
- NaN představuje chybu.
Tyto číselné hodnoty jsou typu number , ale nejsou to „běžná“ čísla, takže existují funkce pro jejich kontrolu:
- isNaN(hodnota) převede hodnotu na číslo a zkontroluje, zda je to NaN :
alert( isNaN(NaN) ); // true alert( isNaN("str") ); // true Potřebujeme tuto funkci? Nemůžeme prostě porovnat === NaN ? Bohužel ne. Hodnota NaN je jedinečná v tom, že se nerovná ničemu jinému, dokonce ani sama sobě:
alert( NaN === NaN ); // false