Õppige selgeks JavaScripti BigInt täpseks ja laiaulatuslikuks täisarvudega arvutamiseks. Uurige süntaksit, kasutusjuhtumeid krüptograafias ja rahanduses ning vältige levinud lõkse nagu JSON-serialiseerimine.
JavaScript BigInt: põhjalik juhend suurte arvudega arvutamiseks
Aastaid seisid JavaScripti arendajad silmitsi vaikse, kuid olulise piiranguga: keele kaasasündinud võimega numbreid käsitleda. Kuigi igapäevasteks arvutusteks sobis see suurepäraselt, jäi JavaScripti Number
-tüüp hätta tõeliselt massiivsete täisarvudega, mida on vaja sellistes valdkondades nagu krüptograafia, teadusarvutused ja kaasaegsed andmesüsteemid. See viis ajutiste lahenduste, kolmandate osapoolte teekide ja peente, raskesti silutavate täpsusvigade maailma.
See ajastu on möödas. BigInt-i kasutuselevõtt JavaScripti kaasasündinud primitiivtüübina on muutnud pöördeliselt meie tööd suurte arvudega. See pakub robustset, ergonoomilist ja tõhusat viisi suvalise täpsusega täisarvude aritmeetika teostamiseks otse keele sees.
See põhjalik juhend on mõeldud arendajatele üle kogu maailma. Sukeldume sügavale BigInt-i "miks, mis ja kuidas" küsimustesse. Olenemata sellest, kas te ehitate finantsrakendust, suhtlete plokiahelaga või üritate lihtsalt mõista, miks teie API-st saadud suur unikaalne ID käitub kummaliselt, varustab see artikkel teid teadmistega BigInt-i valdamiseks.
Probleem: JavaScripti Number-tĂĽĂĽbi piirid
Enne kui saame lahendust hinnata, peame probleemi täielikult mõistma. JavaScriptil on suurema osa oma ajaloost olnud ainult üks arvutüüp: Number
-tüüp. Kapoti all esitatakse seda IEEE 754 topelttäpsusega 64-bitise ujukomaarvuna. See formaat on suurepärane laia väärtuste hulga, sealhulgas kümnendmurdude, esitamiseks, kuid sellel on täisarvude osas kriitiline piirang.
Saage tuttavaks: MAX_SAFE_INTEGER
Oma ujukoma esituse tõttu on olemas piir, kui suurt täisarvu saab täiusliku täpsusega esitada. See piir on avaldatud konstandi kaudu: Number.MAX_SAFE_INTEGER
.
Selle väärtus on 253 - 1, mis on 9,007,199,254,740,991. Kutsume seda lühidalt üheksaks kvadriljoniks.
Iga täisarvu vahemikus -Number.MAX_SAFE_INTEGER
kuni +Number.MAX_SAFE_INTEGER
peetakse "turvaliseks täisarvuks". See tähendab, et seda saab täpselt esitada ja õigesti võrrelda. Aga mis juhtub, kui me astume sellest vahemikust välja?
Vaatame seda tegevuses:
const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe); // 9007199254740991
// Lisame sellele 1
console.log(maxSafe + 1); // 9007199254740992 - See tundub õige
// Lisame veel 1
console.log(maxSafe + 2); // 9007199254740992 - Oih. Vale tulemus.
// Läheb hullemaks
console.log(maxSafe + 3); // 9007199254740994 - Oot, mida?
console.log(maxSafe + 4); // 9007199254740996 - See jätab numbreid vahele!
// Ka võrdsuse kontroll ebaõnnestub
console.log(maxSafe + 1 === maxSafe + 2); // true - See on matemaatiliselt vale!
Nagu näete, kui ületame Number.MAX_SAFE_INTEGER
-i, ei suuda JavaScript enam meie arvutuste täpsust tagada. Arvude esituses hakkavad tekkima lüngad, mis põhjustavad ümardamisvigu ja valesid tulemusi. See on õudusunenägu rakendustele, mis nõuavad suurte täisarvudega täpsust.
Vanad ajutised lahendused
Aastaid tugines ülemaailmne arendajate kogukond selle probleemi lahendamiseks välistele teekidele. Teegid nagu bignumber.js
, decimal.js
ja long.js
muutusid standardseteks tööriistadeks. Need töötasid, esitades suuri arve sõnede või numbrite massiividena ja rakendades aritmeetilisi tehteid tarkvaraliselt.
Kuigi need olid tõhusad, kaasnesid nende teekidega kompromissid:
- Jõudluse lisakulu: Tehted olid oluliselt aeglasemad kui kaasasündinud arvudega arvutamine.
- Paketi suurus: Need lisasid rakenduse pakettidele kaalu, mis on veebi jõudluse seisukohalt murettekitav.
- Erinev sĂĽntaks: Arendajad pidid kasutama objektide meetodeid (nt
a.add(b)
) standardsete aritmeetiliste operaatorite (a + b
) asemel, mis muutis koodi vähem intuitiivseks.
Tutvustame BigInt-i: kaasasĂĽndinud lahendus
BigInt võeti kasutusele ES2020-s, et see probleem lahendada kaasasündinud viisil. BigInt
on uus primitiivtüüp JavaScriptis, mis pakub viisi esitada täisarve, mis on suuremad kui 253 - 1.
BigInt-i põhiline omadus on see, et selle suurus ei ole fikseeritud. See suudab esitada suvaliselt suuri täisarve, mida piirab ainult host-süsteemis saadaolev mälu. See kõrvaldab täielikult täpsusprobleemid, mida nägime Number
-tĂĽĂĽbiga.
Kuidas luua BigInt-i
BigInt-i loomiseks on kaks peamist viisi:
- Lisades `n` täisarvu literaalile: See on kõige lihtsam ja levinum meetod.
- Kasutades
BigInt()
konstruktorfunktsiooni: See on kasulik, kui teisendatakse väärtust teisest tüübist, näiteks sõnest või arvust.
Koodis näevad need välja nii:
// 1. Kasutades 'n' järelliidet
const myFirstBigInt = 900719925474099199n;
const anotherBigInt = 123456789012345678901234567890n;
// 2. Kasutades BigInt() konstruktorit
const fromString = BigInt("98765432109876543210");
const fromNumber = BigInt(100);
// Saate tĂĽĂĽpi kontrollida
console.log(typeof myFirstBigInt); // "bigint"
console.log(typeof 100); // "number"
BigInt-iga töötab meie eelnev ebaõnnestunud arvutus nüüd suurepäraselt:
const maxSafePlusOne = BigInt(Number.MAX_SAFE_INTEGER) + 1n;
const maxSafePlusTwo = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
console.log(maxSafePlusOne.toString()); // "9007199254740992"
console.log(maxSafePlusTwo.toString()); // "9007199254740993"
// Võrdsus töötab ootuspäraselt
console.log(maxSafePlusOne === maxSafePlusTwo); // false
Töötamine BigInt-iga: süntaks ja operatsioonid
BigInt-id käituvad suures osas nagu tavalised arvud, kuid mõne olulise erinevusega, mida iga arendaja peab vigade vältimiseks mõistma.
Aritmeetilised tehted
Kõik standardsed aritmeetilised operaatorid töötavad BigInt-idega:
- Liitmine:
+
- Lahutamine:
-
- Korrutamine:
*
- Astendamine:
**
- Moodul (jääk):
%
Üks operaator, mis käitub erinevalt, on jagamine (`/`).
const a = 10n;
const b = 3n;
console.log(a + b); // 13n
console.log(a - b); // 7n
console.log(a * b); // 30n
console.log(a ** b); // 1000n
console.log(a % b); // 1n
Jagamise eripära
Kuna BigInt-id saavad esitada ainult täisarve, kärbitakse jagamise tulemus alati (murdosa jäetakse ära). See ei ümarda.
const a = 10n;
const b = 3n;
console.log(a / b); // 3n (mitte 3.333...n)
const c = 9n;
const d = 10n;
console.log(c / d); // 0n
See on kriitiline erisus. Kui teil on vaja teha arvutusi kümnendmurdudega, ei ole BigInt õige tööriist. Peaksite jätkama Number
-tüübi või spetsiaalse kümnendmurdude teegi kasutamist.
Võrdlus ja võrdsus
Võrdlusoperaatorid nagu >
, <
, >=
ja <=
töötavad sujuvalt BigInt-ide vahel ja isegi BigInt-i ja Number-i vahel.
console.log(10n > 5); // true
console.log(10n < 20); // true
console.log(10n > 20n); // false
Võrdsus on aga nüansirikkam ja on tavaline segaduse allikas.
- Nõrk võrdsus (`==`): See operaator teostab tüübi teisenduse. See peab sama matemaatilise väärtusega BigInt-i ja Number-it võrdseks.
- Range võrdsus (`===`): See operaator ei teosta tüübi teisendust. Kuna BigInt ja Number on erinevad tüübid, tagastab see neid võrreldes alati
false
.
console.log(10n == 10); // true - Olge sellega ettevaatlik!
console.log(10n === 10); // false - Selguse huvides soovitatav.
console.log(0n == 0); // true
console.log(0n === 0); // false
Parim praktika: Peente vigade vältimiseks kasutage alati ranget võrdsust (`===`) ja olge võrreldavate tüüpide osas selgesõnaline. Kui teil on vaja võrrelda BigInt-i ja Number-it, on sageli selgem teisendada üks teiseks, pidades silmas potentsiaalset täpsuse kadu.
TĂĽĂĽpide sobimatus: range eraldatus
JavaScript rakendab ranget reeglit: te ei saa segada BigInt ja Number operande enamikus aritmeetilistes tehetes.
Selle katse tulemuseks on TypeError
. See on tahtlik disainivalik, et vältida arendajatel kogemata täpsuse kaotamist.
const myBigInt = 100n;
const myNumber = 50;
try {
const result = myBigInt + myNumber; // See viskab vea
} catch (error) {
console.log(error); // TypeError: Cannot mix BigInt and other types, use explicit conversions
}
Õige lähenemine: selgesõnaline teisendamine
BigInt-i ja Number-i vahelise tehte sooritamiseks peate ühe neist selgesõnaliselt teisendama.
const myBigInt = 100n;
const myNumber = 50;
// Teisenda Number BigInt-iks (turvaline)
const result1 = myBigInt + BigInt(myNumber);
console.log(result1); // 150n
// Teisenda BigInt Number-iks (potentsiaalselt ohtlik!)
const veryLargeBigInt = 900719925474099199n;
// See kaotab täpsuse!
const unsafeNumber = Number(veryLargeBigInt);
console.log(unsafeNumber); // 900719925474099200 - Väärtus on ümardatud!
const safeResult = Number(100n) + myNumber;
console.log(safeResult); // 150
Kriitiline reegel: Teisendage BigInt Number-iks ainult siis, kui olete täiesti kindel, et see mahub turvaliste täisarvude vahemikku. Vastasel juhul teisendage täpsuse säilitamiseks alati Number BigInt-iks.
BigInt-i praktilised kasutusjuhud globaalses kontekstis
Vajadus BigInt-i järele ei ole abstraktne akadeemiline probleem. See lahendab reaalseid väljakutseid, millega arendajad erinevates rahvusvahelistes valdkondades silmitsi seisavad.
1. Ülitäpsed ajatemplid
JavaScripti `Date.now()` tagastab millisekundite arvu alates Unixi ajastu algusest. Kuigi see on paljude veebirakenduste jaoks piisav, ei ole see piisavalt detailne suure jõudlusega süsteemide jaoks. Paljud hajutatud süsteemid, andmebaasid ja logimisraamistikud üle kogu maailma kasutavad sündmuste täpseks järjestamiseks nanosekundi täpsusega ajatempleid. Neid ajatempleid esitatakse sageli 64-bitiste täisarvudena, mis on Number
-tĂĽĂĽbi jaoks liiga suured.
// Kõrge eraldusvõimega süsteemi ajatempel (nt nanosekundites)
const nanoTimestampStr = "1670000000123456789";
// Number-i kasutamine põhjustab täpsuse kao
const lostPrecision = Number(nanoTimestampStr);
console.log(lostPrecision); // 1670000000123456800 - Vale!
// BigInt-i kasutamine säilitab selle ideaalselt
const correctTimestamp = BigInt(nanoTimestampStr);
console.log(correctTimestamp.toString()); // "1670000000123456789"
// Nüüd saame teha täpseid arvutusi
const oneSecondInNanos = 1_000_000_000n;
const nextSecond = correctTimestamp + oneSecondInNanos;
console.log(nextSecond.toString()); // "1670001000123456789"
2. Unikaalsed identifikaatorid (ID-d) API-dest
Väga levinud stsenaarium on suhtlemine API-dega, mis kasutavad unikaalsete objektide ID-de jaoks 64-bitiseid täisarve. See on muster, mida kasutavad suured ülemaailmsed platvormid nagu Twitter (Snowflake ID-d) ja paljud andmebaasisüsteemid (nt BIGINT
-tĂĽĂĽp SQL-is).
Kui te sellisest API-st andmeid hangite, võib teie veebilehitseja või Node.js-i keskkonna JSON-i parser proovida seda suurt ID-d parsida kui Number
-it, mis viib andmete rikkumiseni juba enne, kui teil on võimalus nendega töötada.
// TĂĽĂĽpiline JSON vastus API-lt
// Märkus: ID on suur number, mitte sõne.
const jsonResponse = '{"id": 1367874743838343168, "text": "Hello, world!"}';
// Standardne JSON.parse rikub ID
const parsedData = JSON.parse(jsonResponse);
console.log(parsedData.id); // 1367874743838343200 - Vale ID!
// Lahendus: Veenduge, et API saadaks suured ID-d sõnedena.
const safeJsonResponse = '{"id": "1367874743838343168", "text": "Hello, world!"}';
const safeParsedData = JSON.parse(safeJsonResponse);
const userId = BigInt(safeParsedData.id);
console.log(userId); // 1367874743838343168n - Õige!
Seetõttu on ülemaailmselt laialt aktsepteeritud parim praktika, et API-d serialiseeriksid suured täisarvude ID-d JSON-i laadungites sõnedena, et tagada ühilduvus kõigi klientidega.
3. KrĂĽptograafia
Kaasaegne krüptograafia põhineb matemaatikal, mis hõlmab äärmiselt suuri täisarve. Algoritmid nagu RSA tuginevad tehetele arvudega, mis on sadu või isegi tuhandeid bitte pikad. BigInt võimaldab neid arvutusi teha JavaScriptis kaasasündinud viisil, mis on hädavajalik veebipõhiste krüptograafiliste rakenduste jaoks, näiteks need, mis kasutavad Web Crypto API-t või rakendavad protokolle Node.js-is.
Kuigi täielik krüptograafiline näide on keeruline, näeme kontseptuaalset demonstratsiooni:
// Kaks väga suurt algarvu (ainult demonstratsiooni eesmärgil)
const p = 1143400375533529n;
const q = 982451653n; // Näite jaoks väiksem
// RSA-s korrutatakse need mooduli saamiseks
const n = p * q;
console.log(n.toString()); // "1123281328905333100311297"
// See arvutus oleks Number-tüübiga võimatu.
// BigInt saab sellega vaevata hakkama.
4. Finants- ja plokiahela rakendused
Finantsidega, eriti krüptovaluutade kontekstis, on täpsus esmatähtis. Paljud krüptovaluutad, nagu Bitcoin, mõõdavad väärtust oma väikseimas ühikus (nt satoshid). Nende ühikute kogupakkumine võib kergesti ületada Number.MAX_SAFE_INTEGER
-i. BigInt on ideaalne tööriist nende suurte ja täpsete koguste käsitlemiseks ilma ujukomaaritmeetikata, mis on altid ümardamisvigadele.
// 1 Bitcoin = 100 000 000 satoshit
const satoshisPerBTC = 100_000_000n;
// Bitcoini kogupakkumine on 21 miljonit
const totalBTCSupply = 21_000_000n;
// Arvuta satoshide koguarv
const totalSatoshis = totalBTCSupply * satoshisPerBTC;
// 2,100,000,000,000,000 - See on 2,1 kvadriljonit
console.log(totalSatoshis.toString());
// See väärtus on suurem kui Number.MAX_SAFE_INTEGER
console.log(totalSatoshis > BigInt(Number.MAX_SAFE_INTEGER)); // true
Edasijõudnute teemad ja levinud lõksud
Serialiseerimine ja JSON.stringify()
Ăśks levinumaid probleeme, millega arendajad silmitsi seisavad, on BigInt-e sisaldavate objektide serialiseerimine. Vaikimisi ei tea JSON.stringify()
, kuidas bigint
-tüüpi käsitleda ja viskab TypeError
-i.
const data = {
id: 12345678901234567890n,
user: 'alex'
};
try {
JSON.stringify(data);
} catch (error) {
console.log(error); // TypeError: Do not know how to serialize a BigInt
}
Lahendus 1: Rakendage toJSON
meetod
Saate öelda JSON.stringify
-le, kuidas BigInt-e käsitleda, lisades toJSON
meetodi BigInt.prototype
-i. See lähenemine paigab globaalset prototüüpi, mis ei pruugi mõnes jagatud keskkonnas olla soovitav, kuid see on väga tõhus.
// Globaalne paik. Kasutage kaalutletult.
BigInt.prototype.toJSON = function() {
return this.toString();
};
const data = { id: 12345678901234567890n, user: 'alex' };
const jsonString = JSON.stringify(data);
console.log(jsonString); // '{"id":"12345678901234567890","user":"alex"}'
Lahendus 2: Kasutage asendusfunktsiooni (replacer)
Turvalisem ja lokaliseeritum lähenemine on kasutada replacer
-argumenti JSON.stringify
-s. Seda funktsiooni kutsutakse iga võtme/väärtuse paari jaoks ja see võimaldab teil väärtust enne serialiseerimist teisendada.
const data = { id: 12345678901234567890n, user: 'alex' };
const replacer = (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
}
return value;
};
const jsonString = JSON.stringify(data, replacer);
console.log(jsonString); // '{"id":"12345678901234567890","user":"alex"}'
Bitioperatsioonid
BigInt toetab kõiki bitioperaatoreid, millega olete tuttav Number
-tĂĽĂĽbist: &
(AND), |
(OR), ^
(XOR), ~
(NOT), <<
(nihe vasakule) ja >>
(märki säilitav nihe paremale). Need on eriti kasulikud madala taseme andmevormingute, lubade või teatud tüüpi algoritmidega töötamisel.
const permissions = 5n; // 0101 binaarselt
const READ_PERMISSION = 4n; // 0100
const WRITE_PERMISSION = 2n; // 0010
// Kontrolli, kas lugemisluba on seatud
console.log((permissions & READ_PERMISSION) > 0n); // true
// Kontrolli, kas kirjutamisluba on seatud
console.log((permissions & WRITE_PERMISSION) > 0n); // false
// Lisa kirjutamisluba
const newPermissions = permissions | WRITE_PERMISSION;
console.log(newPermissions); // 7n (mis on 0111)
Jõudlusega seotud kaalutlused
Kuigi BigInt on uskumatult võimas, on oluline mõista selle jõudlusomadusi:
- Number vs. BigInt: Turvalises vahemikus olevate täisarvude puhul on standardsed
Number
-tehted oluliselt kiiremad. See on sellepärast, et need saavad sageli otse vastenduda masinataseme käskudele, mida töötleb arvuti protsessor. BigInt-tehted, olles suvalise suurusega, nõuavad keerukamaid tarkvarapõhiseid algoritme. - BigInt vs. teegid: Kaasasündinud
BigInt
on üldiselt palju kiirem kui JavaScriptis põhinevad suurte arvude teegid. Implementatsioon on osa JavaScripti mootorist (nagu V8 või SpiderMonkey) ja on kirjutatud madalama taseme keeles nagu C++, mis annab sellele märkimisväärse jõudluseelise.
Kuldreegel: Kasutage Number
-it kõikide arvuliste arvutuste jaoks, välja arvatud juhul, kui teil on konkreetne põhjus uskuda, et väärtused võivad ületada Number.MAX_SAFE_INTEGER
-i. Kasutage BigInt
-i siis, kui vajate selle võimekust, mitte kõigi arvude vaikeasendajana.
Veebilehitsejate ja keskkondade ĂĽhilduvus
BigInt on kaasaegne JavaScripti funktsioon, kuid selle tugi on nüüdseks laialt levinud kogu globaalses ökosüsteemis.
- Veebilehitsejad: Toetatud kõikides suurtes kaasaegsetes brauserites (Chrome 67+, Firefox 68+, Safari 14+, Edge 79+).
- Node.js: Toetatud alates versioonist 10.4.0.
Projektide jaoks, mis peavad toetama väga vanu keskkondi, võib transpileerimine tööriistadega nagu Babel olla valikuvõimalus, kuid sellega kaasneb jõudluse langus. Arvestades tänapäeva laialdast tuge, saavad enamik uusi projekte kasutada BigInt-i kaasasündinud kujul muretult.
Kokkuvõte ja parimad praktikad
BigInt on võimas ja hädavajalik täiendus JavaScripti keelele. See pakub kaasasündinud, tõhusat ja ergonoomilist lahendust pikaajalisele suurte täisarvude aritmeetika probleemile, võimaldades ehitada JavaScriptiga uut klassi rakendusi, alates krüptograafiast kuni ülitäpse andmetöötluseni.
Selle tõhusaks kasutamiseks ja levinud lõksude vältimiseks pidage meeles neid parimaid praktikaid:
- Kasutage `n` järelliidet: Eelistage BigInt-ide loomiseks literaalsüntaksit
123n
. See on selge, lühike ja väldib potentsiaalset täpsuse kadu loomisel. - Ärge segage tüüpe: Pidage meeles, et te ei saa segada BigInt-i ja Number-it aritmeetilistes tehetes. Olge oma teisendustega selgesõnaline:
BigInt()
võiNumber()
. - Eelistage täpsust: Tüüpide vahel teisendades eelistage alati
Number
-i teisendamistBigInt
-iks, et vältida juhuslikku täpsuse kadu. - Kasutage ranget võrdsust: Kasutage võrdlusteks
===
asemel==
, et vältida tüübi teisendusest põhjustatud segadust tekitavat käitumist. - Käsitlege JSON-i serialiseerimist: Planeerige BigInt-ide serialiseerimist. Kasutage turvalise, mitteglobaalse lahenduse jaoks kohandatud
replacer
-funktsiooniJSON.stringify
-s. - Valige õige tööriist: Kasutage
Number
-it üldotstarbeliseks matemaatikaks turvalise täisarvude vahemikus parema jõudluse saavutamiseks. KasutageBigInt
-i ainult siis, kui teil on tõesti vaja selle suvalise täpsuse võimekust.
Võttes omaks BigInt-i ja mõistes selle reegleid, saate kirjutada robustsemaid, täpsemaid ja võimsamaid JavaScripti rakendusi, mis on võimelised lahendama mis tahes mastaabiga numbrilisi väljakutseid.