Hrvatski

Vodič za JavaScript BigInt: prevladajte ograničenja brojeva i izvodite precizne izračune s velikim cijelim brojevima. Saznajte sve o njegovoj upotrebi i primjeni.

JavaScript BigInt: Ovladavanje aritmetikom velikih cijelih brojeva

Iako je svestran jezik, JavaScript ima ograničenja pri radu s vrlo velikim cijelim brojevima. Standardni `Number` tip može točno predstaviti cijele brojeve samo do određene granice, poznate kao `Number.MAX_SAFE_INTEGER`. Iznad te granice, izračuni postaju neprecizni, što dovodi do neočekivanih rezultata. Tu u pomoć priskače BigInt. Predstavljen u ECMAScript 2020, BigInt je ugrađeni objekt koji omogućuje predstavljanje i manipulaciju cijelim brojevima proizvoljne veličine, nadilazeći ograničenja standardnog `Number` tipa.

Razumijevanje potrebe za BigInt-om

Prije BigInt-a, JavaScript programeri morali su se oslanjati na biblioteke ili prilagođene implementacije za rukovanje izračunima s velikim cijelim brojevima. Ta rješenja često su donosila dodatno opterećenje na performanse i povećanu složenost. Uvođenje BigInt-a pružilo je nativan i učinkovit način rada s velikim cijelim brojevima, otvarajući mogućnosti za primjene u različitim domenama, uključujući:

Stvaranje BigInt vrijednosti

Postoje dva osnovna načina za stvaranje BigInt vrijednosti u JavaScriptu:

  1. Korištenjem `BigInt()` konstruktora: Ovaj konstruktor može pretvoriti broj, string ili logičku vrijednost u BigInt.
  2. Korištenjem sufiksa `n`: Dodavanje `n` na cjelobrojni literal stvara BigInt.

Primjeri:

Korištenjem `BigInt()` konstruktora:


const bigIntFromNumber = BigInt(12345678901234567890);
const bigIntFromString = BigInt("98765432109876543210");
const bigIntFromBoolean = BigInt(true); // Rezultat je 1n
const bigIntFromFalseBoolean = BigInt(false); // Rezultat je 0n

console.log(bigIntFromNumber); // Izlaz: 12345678901234567890n
console.log(bigIntFromString); // Izlaz: 98765432109876543210n
console.log(bigIntFromBoolean); // Izlaz: 1n
console.log(bigIntFromFalseBoolean); // Izlaz: 0n

Korištenjem sufiksa `n`:


const bigIntLiteral = 12345678901234567890n;
console.log(bigIntLiteral); // Izlaz: 12345678901234567890n

Važna napomena: Ne možete izravno miješati BigInt i Number vrijednosti u aritmetičkim operacijama. Morate ih eksplicitno pretvoriti u isti tip prije izvođenja izračuna. Pokušaj njihovog izravnog miješanja rezultirat će TypeError-om.

Aritmetičke operacije s BigInt-om

BigInt podržava većinu standardnih aritmetičkih operatora, uključujući:

Primjeri:


const a = 12345678901234567890n;
const b = 98765432109876543210n;

const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / 2n; // Napomena: Dijeljenje zaokružuje prema nuli
const remainder = a % 7n;
const power = a ** 3n; // Potenciranje radi kako se očekuje

console.log("Zbroj:", sum); // Izlaz: Zbroj: 111111111011111111100n
console.log("Razlika:", difference); // Izlaz: Razlika: -86419753208641975320n
console.log("Umnožak:", product); // Izlaz: Umnožak: 1219326311370217957951669538098765432100n
console.log("Kvocijent:", quotient); // Izlaz: Kvocijent: 6172839450617283945n
console.log("Ostatak:", remainder); // Izlaz: Ostatak: 5n
console.log("Potencija:", power); // Izlaz: Potencija: 187641281029182300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n

Važna razmatranja:

Operatori usporedbe

Možete koristiti standardne operatore usporedbe (`==`, `!=`, `<`, `>`, `<=`, `>=`) za usporedbu BigInt vrijednosti s drugim BigInt vrijednostima ili čak s Number vrijednostima. Međutim, budite svjesni mogućnosti prisilne pretvorbe tipova (type coercion).

Primjeri:


const a = 10n;
const b = 20n;
const c = 10;

console.log(a == b);   // Izlaz: false
console.log(a != b);   // Izlaz: true
console.log(a < b);    // Izlaz: true
console.log(a > b);    // Izlaz: false
console.log(a <= b);   // Izlaz: true
console.log(a >= b);   // Izlaz: false

console.log(a == c);   // Izlaz: true (prisilna pretvorba tipa)
console.log(a === c);  // Izlaz: false (nema prisilne pretvorbe tipa)

Najbolja praksa: Koristite strogu jednakost (`===`) i strogu nejednakost (`!==`) kako biste izbjegli neočekivanu prisilnu pretvorbu tipova prilikom usporedbe BigInt i Number vrijednosti.

Pretvorba između BigInt-a i Number-a

Iako izravne aritmetičke operacije između BigInt-a i Number-a nisu dopuštene, možete pretvarati između ta dva tipa. Međutim, budite svjesni mogućeg gubitka preciznosti prilikom pretvaranja BigInt-a u Number ako BigInt vrijednost premašuje `Number.MAX_SAFE_INTEGER`.

Primjeri:


const bigIntValue = 9007199254740991n; // Number.MAX_SAFE_INTEGER
const numberValue = Number(bigIntValue); // Pretvaranje BigInt-a u Number
console.log(numberValue); // Izlaz: 9007199254740991

const largerBigIntValue = 9007199254740992n; // Premašuje Number.MAX_SAFE_INTEGER
const largerNumberValue = Number(largerBigIntValue);
console.log(largerNumberValue); // Izlaz: 9007199254740992 (može biti neprecizno)

const numberToBigInt = BigInt(12345); // Pretvaranje Number-a u BigInt
console.log(numberToBigInt); // Izlaz: 12345n

Slučajevi upotrebe i primjeri

Kriptografija

Kriptografski algoritmi se često oslanjaju na vrlo velike proste brojeve radi sigurnosti. BigInt pruža način za učinkovito predstavljanje i manipulaciju tim brojevima.


// Primjer: Generiranje jednostavnog (nesigurnog) para ključeva
function generateKeyPair() {
  const p = 281n; // Prosti broj
  const q = 283n; // Drugi prosti broj
  const n = p * q; // Modul
  const totient = (p - 1n) * (q - 1n); // Eulerova totient funkcija

  // Odaberite e (javni eksponent) takav da je 1 < e < totient i gcd(e, totient) = 1
  const e = 17n;

  // Izračunajte d (privatni eksponent) takav da je (d * e) % totient = 1
  let d = 0n;
  for (let i = 1n; i < totient; i++) {
    if ((i * e) % totient === 1n) {
      d = i;
      break;
    }
  }

  return {
    publicKey: { n, e },
    privateKey: { n, d },
  };
}

const keyPair = generateKeyPair();
console.log("Javni ključ:", keyPair.publicKey);
console.log("Privatni ključ:", keyPair.privateKey);

Napomena: Ovo je pojednostavljeni primjer samo u svrhu demonstracije. Kriptografija u stvarnom svijetu koristi mnogo veće proste brojeve i sofisticiranije algoritme.

Financijski izračuni

Prilikom rada s velikim svotama novca, posebno u međunarodnim transakcijama, preciznost je ključna. BigInt može spriječiti pogreške pri zaokruživanju i osigurati točne izračune.


// Primjer: Izračun složenih kamata
function calculateCompoundInterest(principal, rate, time) {
  const principalBigInt = BigInt(principal * 100); // Pretvorite u cente
  const rateBigInt = BigInt(rate * 10000);       // Pretvorite u desettisućinke postotka
  const timeBigInt = BigInt(time);

  let amount = principalBigInt;
  for (let i = 0n; i < timeBigInt; i++) {
    amount = amount * (10000n + rateBigInt) / 10000n;
  }

  const amountInDollars = Number(amount) / 100;
  return amountInDollars;
}

const principal = 1000000; // 1.000.000 $
const rate = 0.05;    // 5% kamatna stopa
const time = 10;     // 10 godina

const finalAmount = calculateCompoundInterest(principal, rate, time);
console.log("Konačni iznos:", finalAmount); // Izlaz: Konačni iznos: 1628894.6267774413 (približno)

U ovom primjeru, pretvaramo glavnicu i stopu u BigInt vrijednosti kako bismo izbjegli pogreške pri zaokruživanju tijekom izračuna. Rezultat se zatim pretvara natrag u Number za prikaz.

Rad s velikim ID-ovima

U distribuiranim sustavima, generiranje jedinstvenih ID-ova na više poslužitelja može biti izazovno. Korištenje BigInt-a omogućuje vam stvaranje vrlo velikih ID-ova za koje je malo vjerojatno da će doći do kolizije.


// Primjer: Generiranje jedinstvenog ID-a na temelju vremenske oznake i ID-a poslužitelja
function generateUniqueId(serverId) {
  const timestamp = BigInt(Date.now());
  const serverIdBigInt = BigInt(serverId);
  const random = BigInt(Math.floor(Math.random() * 1000)); // Dodajte malo nasumičnosti

  // Kombinirajte vrijednosti kako biste stvorili jedinstveni ID
  const uniqueId = (timestamp << 20n) + (serverIdBigInt << 10n) + random;
  return uniqueId.toString(); // Vratite kao string radi lakšeg rukovanja
}

const serverId = 123; // Primjer ID-a poslužitelja
const id1 = generateUniqueId(serverId);
const id2 = generateUniqueId(serverId);

console.log("Jedinstveni ID 1:", id1);
console.log("Jedinstveni ID 2:", id2);

BigInt i JSON

BigInt vrijednosti nisu nativno podržane od strane JSON-a. Pokušaj serijalizacije JavaScript objekta koji sadrži BigInt pomoću `JSON.stringify()` rezultirat će TypeError-om. Za rukovanje BigInt vrijednostima pri radu s JSON-om, imate nekoliko opcija:

  1. Pretvorba u string: Pretvorite BigInt u string prije serijalizacije. Ovo je najčešći i najjednostavniji pristup.
  2. Prilagođena serijalizacija/deserijalizacija: Koristite prilagođenu funkciju za serijalizaciju/deserijalizaciju za rukovanje BigInt vrijednostima.

Primjeri:

Pretvaranje u string:


const data = {
  id: 12345678901234567890n,
  name: "Primjer podataka",
};

// Pretvorite BigInt u string prije serijalizacije
data.id = data.id.toString();

const jsonData = JSON.stringify(data);
console.log(jsonData); // Izlaz: {"id":"12345678901234567890","name":"Primjer podataka"}

// Prilikom deserijalizacije, morat ćete pretvoriti string natrag u BigInt
const parsedData = JSON.parse(jsonData, (key, value) => {
  if (key === "id") {
    return BigInt(value);
  }
  return value;
});

console.log(parsedData.id); // Izlaz: 12345678901234567890n

Prilagođena serijalizacija/deserijalizacija (pomoću `replacer`-a i `reviver`-a):


const data = {
  id: 12345678901234567890n,
  name: "Primjer podataka",
};

// Prilagođena serijalizacija
const jsonData = JSON.stringify(data, (key, value) => {
  if (typeof value === 'bigint') {
    return value.toString();
  } else {
    return value;
  }
});

console.log(jsonData);

// Prilagođena deserijalizacija
const parsedData = JSON.parse(jsonData, (key, value) => {
    if (typeof value === 'string' && /^[0-9]+$/.test(value)) { // provjerite je li to broj i string
      try {
        return BigInt(value);
      } catch(e) {
          return value;
      }
    }
    return value;
});

console.log(parsedData.id);

Kompatibilnost s preglednicima

BigInt je široko podržan u modernim preglednicima. Međutim, ključno je provjeriti kompatibilnost za starije preglednike ili okruženja. Možete koristiti alat kao što je Can I use za provjeru podrške u preglednicima. Ako trebate podržati starije preglednike, mogli biste razmisliti o korištenju polyfilla, ali budite svjesni da polyfillovi mogu utjecati na performanse.

Razmatranja o performansama

Iako BigInt pruža moćan način za rad s velikim cijelim brojevima, važno je biti svjestan mogućih implikacija na performanse.

Stoga, koristite BigInt samo kada je to nužno i optimizirajte svoj kod za performanse ako izvodite veliki broj BigInt operacija.

Zaključak

BigInt je vrijedan dodatak JavaScriptu, omogućavajući programerima da s preciznošću rukuju aritmetikom velikih cijelih brojeva. Razumijevanjem njegovih značajki, ograničenja i slučajeva upotrebe, možete iskoristiti BigInt za izgradnju robusnih i točnih aplikacija u različitim domenama, uključujući kriptografiju, financijske izračune i znanstveno računanje. Ne zaboravite uzeti u obzir kompatibilnost s preglednicima i implikacije na performanse kada koristite BigInt u svojim projektima.

Daljnje istraživanje

Ovaj vodič pruža sveobuhvatan pregled BigInt-a u JavaScriptu. Istražite povezane resurse za detaljnije informacije i napredne tehnike.