Number i Math

Ostatnia aktualizacja: 29 sierpnia 2020

Number - czyli typ danych pozwalający pracować na liczbach.

W większości przypadków będziemy zapisywać liczby normalnie - tak jak się przyzwyczailiśmy:


const nr1 = 102;
const nr2 = 1.25;

Jeżeli chcemy zapisać liczbę z większą liczbą zer, możemy to zrobić normalnie powtarzając kolejne zera, ale też możemy zastosować zapis z literą e, po której podajemy liczbę zer. Dzięki temu ciężej zrobić błąd:


const nr1 = 1e6; //1 * 1000000
const nr2 = 2e5; //2 * 100000
const nr3 = 1.3e4; //1.3 * 10000

Podobną techniką możemy zapisywać liczby bardzo małe:


const nr1 = 1e-5; //5 zer na lewo od liczby => 0.00001
const nr2 = 2e-3; //3 zera na lewo 0.002
const nr3 = 2.1e-4; //4 zera na lewo 0.00021

Kolejnym sposobem zapisu liczb jest system dwójkowy, hexadecymalny oraz ósemkowy. Nie są to zapisy często używane, ale w skrajnych sytuacjach może się pojawić:


//szesnastkowy - znany z kolorów CSS
console.log( 0xFF ); //255
console.log( 0x66 ); //102

//ósemkowy
const nr1 = 0o377; //255

//dwójkowy
const nr2 = 0b11111111; //255

console.log( 0xFF === 0o377 === 0b11111111); //true

Funkcja toString()

Każdy (prawie) typ danych w Javascript może korzystać z funkcji toString(), która zamienia go na zapis tekstowy. W przypadku typu Number, metoda ta pozwala podać w nawiasach podstawę/system (z zakresu 1-36), która zostanie użyta do reprezentacji danej liczby:


const nr = 150;
console.log(nr.toString(16)); //"96"
console.log(nr.toString(10)); //"150"
console.log(nr.toString(2)); //"10010110"
console.log(nr.toString()); //"150" - domyślnie dziesiętny

Niedokładne liczenie

Rozważmy proste równanie:


console.log( 0.1 + 0.2 ); //0.30000000000000004

Z czego wynika tak dziwny wynik?

Komputery to twory, które przechowują dane w formie bitów, czyli zapisie zer i jedynek (tak zwany system dwójkowy).

Część liczb niestety nie jest możliwa do przedstawienia w tym systemie.

Można to przyrównać do używanego na co dzień systemu dziesiętnego.

Przykładowo ułamek ½ możemy w systemie dziesiętnym zapisać jako 0.5. Podobnie ułamek ¼ zapiszemy jako 0.25.

Gdybyśmy podobnie chcieli zapisać ułamek ⅓, okazało by się, że nie jesteśmy tego w 100% zrobić, ponieważ nigdy nie osiągniemy pełnej precyzji 0.33333...

Podobnie w systemie dwójkowym niektórych liczb nie jesteśmy w stanie zapisać.

Problem ten tyczy się wszystkich obecnych komputerów i spotykany jest w wielu językach (np. Perl. C++, Java, PHP) ale też i w grach.

W przypadku Javascript do zapisu liczb w pamięci wykorzystywany jest używany powszechnie standard IEEE_754, który charakteryzuje się tym, że przy operacjach na liczbach o bardzo małej precyzji, zaokrąglane są one do najbliższej możliwej do zapisu w systemie dwójkowym liczby.


console.log( 0.1.toFixed(20) ); // 0.10000000000000000555
console.log( 9999999999999999 ); //10000000000000000 - podobna rzecz, ale w drugą stronę

W 99.99% przypadków nie będzie to miało dla nas znaczenia i prawdopodobnie przy normalnej pracy nigdy się z nim nie zetkniesz. Jeżeli jednak kiedyś na swojej drodze spotkasz się z zadaniem zrobienia sklepu, który operuje na bilionach krypto monet, pewnie będziesz musiał skorzystać ze specjalnych algorytmów, które służą do redukcji takich "przesunięć". Na co dzień jednak nie ma co się tym przejmować.

Jeżeli chcesz zobaczyć jak takie dziwactwa wyglądają w innych językach, przejdź na stronę pod znamiennym adresem https://0.30000000000000004.com/...

Math

JavaScript udostępnia nam obiekt Math, który ułatwia nam przeprowadzanie matematycznych operacji.

Poniżej zamieszczam jego najczęściej używane metody. Tak naprawdę nie musisz wszystkich wkuwać na pamięć. Jeżeli zapomnisz jak coś się zapisywało, zawsze możesz sobie ten obiekt wypisać w konsoli debugera poprzez:


console.log(Math);

Po czym rozwinąć go i zbadać co oferuje. Później wystarczy odwiedzić stronę MDN by doczytać.

Metody

Math.abs(liczba) - zwraca wartość bezwzględną (absolutną) liczby
Math.ceil(liczba) - zwraca najmniejszą liczbę całkowitą, większą lub równą podanej liczbie
Math.floor(liczba) - zwraca największą liczbę całkowitą mniejszą lub równą podanej liczbie
Math.max(liczba1, liczba2, liczba3...) - zwraca największą przekazaną liczbę
Math.min(liczba1, liczba2, liczba3...) - zwraca najmniejszą przekazaną liczbę
Math.pow(liczba1, liczba2) - zwraca wartość liczby1 podniesionej do potęgi liczby2
Math.random() - zwraca wartość pseudolosową z przedziału 0 - 1
Math.round(liczba) - zwraca zaokrąglenie danej liczby do najbliższej liczby całkowitej
Math.sin(liczba) - zwraca sinus liczby (podanej w radianach)
Math.sqrt(liczba) - zwraca pierwiastek kwadratowy liczby

Kilka przykładów zastosowania Obiektu Math (zobacz też w konsoli debugera):


const var1 = 56.5;
const var2 = 74.3;

Math.min(var1, var2) //56.5
Math.max(var1, var2) //74.3
Math.max(1,3,6,2) //6

Math.abs(-1) //1

Math.round(var1) //56
Math.round(20.52) //21
Math.round(-10.21) //-10
Math.round(-11.82) //-12

Math.floor(var1) //56
Math.floor(20.52) //20
Math.floor(-10.21) //-11
Math.floor(-11.82) //-12

Math.ceil(var1) //57
Math.ceil(20.52) //21
Math.ceil(-10.21) //-10
Math.ceil(-11.82) //-11

Losowa liczba z przedziału

Aby wygenerować liczbę losową z przedziału np. 3-7 skorzystaj z poniższego wzoru:


const min = 3;
const max = 7;

const result =  Math.floor(Math.random() * (max-min+1) + min);

Losowy kolor

Wzór podpatrzony w internecie, ale ciekawie pokazuje zastosowanie powyższych informacji. Aby wygenerować losowy kolor możemy skorzystać z wielu sposobów.


function randomColor() {
    const letters = "0123456789ABCDEF";
    let color = "#";

    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }

    return color;
}

console.log( randomColor() );
console.log( randomColor() );
console.log( randomColor() );

Inna ciekawa sztuczka:


const color =  "#" + Math.random().toString(16).substr(2,6);

/*
Powyższe równanie możemy rozpisać na kroki:

1)
Math.random() - zwraca liczbę z przedziału 0-1
0.0264363764209139

2)
Number.toString(16) - zapisuje liczbę w danym systemie jako string
0.0264363764209139.toString(16) da nam "0.06c488cc270ee"

3)
"0.06c488cc270ee".subStr(2,6) - wycinamy litery od 3 do 7
czyli w wyniku uzyskamy "06c488"

4)
Dodajemy # i mamy kolor
"#" + "06c488" === "#06c488"
*/
Powyższe sztuczki generują kolory w mojej opinii nieco bure. Aby generować bardziej żywe kolory wystarczy skorzystać z innego formatu czyli hsl:

function randomColor() {
    const deg = Math.random() * 360;
    return `hsl(${deg}, 60%, 50%)`;
}

const color = randomColor();

Trening czyni mistrza

Jeżeli chcesz sobie potrenować zdobytą wiedzę z tego działu, to zadania znajdują się w repozytorium pod adresem: https://github.com/kartofelek007/zadania-podstawy

W repozytorium jest branch "solutions". Tam znajdziesz przykładowe rozwiązania.

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem. Aha - i ta strona korzysta z ciasteczek.

Menu