Põhjalik juhend JavaScripti BigInt primitiivi kohta. Õppige, kuidas käsitleda suurte arvude arvutusi, säilitada täpsust üle Number.MAX_SAFE_INTEGER piiri ja rakendada BigInti globaalsetes rakendustes nagu krüptograafia ja finantstehnoloogia.
JavaScripti BigInt-aritmeetika: süvitsiminek suurte arvude arvutustesse ja täpsuse haldamisse
Aastaid seisid JavaScripti arendajad silmitsi vaikse, kuid olulise piiranguga: võimetusega esitada suuri täisarve loomulikult ja täpselt. Kõiki JavaScripti arve esitati traditsiooniliselt IEEE 754 topelttäpsusega ujukomaarvudena, mis seab täisarvude täpsusele ülempiiri. Kui arvutused hõlmasid arve, mis olid suuremad kui turvaliselt hoitavad, pidid arendajad kasutama kolmandate osapoolte teeke. See muutus BigInt-i kasutuselevõtuga ECMAScript 2020-s (ES11) – revolutsiooniline funktsioon, mis tõi suvalise täpsusega täisarvud keele tuuma.
See põhjalik juhend on mõeldud ülemaailmsele arendajate kogukonnale. Uurime probleeme, mida BigInt lahendab, kuidas seda kasutada täpseks aritmeetikaks, selle reaalmaailma rakendusi sellistes valdkondades nagu krüptograafia ja rahandus ning levinumaid lõkse, mida vältida. Olenemata sellest, kas ehitate finantstehnoloogia platvormi, teaduslikku simulatsiooni või suhtlete süsteemidega, mis kasutavad 64-bitiseid identifikaatoreid, on BigInt-i mõistmine kaasaegse JavaScripti arenduse jaoks hädavajalik.
JavaScripti `Number`-tĂĽĂĽbi klaaslagi
Enne kui saame lahendust hinnata, peame esmalt mõistma probleemi. JavaScripti standardne Number-tüüp, olles küll mitmekülgne, omab põhimõttelist piirangut täisarvude täpsuse osas. See ei ole viga; see on otsene tagajärg selle disainist, mis põhineb IEEE 754 ujukoma-aritmeetika standardil.
`Number.MAX_SAFE_INTEGER`-i mõistmine
Number-tüüp suudab turvaliselt esitada täisarve ainult teatud väärtuseni. See lävi on kättesaadav staatilise omadusena: Number.MAX_SAFE_INTEGER.
Selle väärtus on 9 007 199 254 740 991 ehk 253 - 1. Miks just see number? Topelttäpsusega ujukomaarvu jaoks kasutatavast 64 bitist on 52 bitti pühendatud mantissile (olulised numbrid), üks bitt märgile ja 11 bitti eksponendile. See struktuur võimaldab väga suurt väärtuste vahemikku, kuid piirab täisarvude järjestikust, lünkadeta esitust.
Vaatame, mis juhtub, kui proovime seda piiri ĂĽletada:
const maxSafeInt = Number.MAX_SAFE_INTEGER;
console.log(maxSafeInt); // 9007199254740991
const oneMore = maxSafeInt + 1;
console.log(oneMore); // 9007199254740992
const twoMore = maxSafeInt + 2;
console.log(twoMore); // 9007199254740992 - Oi-oi!
console.log(oneMore === twoMore); // true
Nagu näete, kaotab arvusüsteem pärast läve ületamist võime esitada iga järjestikust täisarvu. maxSafeInt + 1 ja maxSafeInt + 2 annavad sama tulemuse. See vaikne täpsuse kadu võib põhjustada katastroofilisi vigu rakendustes, mis sõltuvad täpsest täisarvude aritmeetikast, näiteks finantsarvutustes või suurte andmebaasi ID-de käsitlemisel.
Millal see oluline on?
See piirang ei ole pelgalt teoreetiline kurioosum. Sellel on olulised reaalmaailma tagajärjed:
- Andmebaasi ID-d: Paljud kaasaegsed andmebaasisüsteemid, nagu PostgreSQL, kasutavad primaarvõtmete jaoks 64-bitist täisarvutüüpi (
BIGINT). Need ID-d võivad kergesti ületadaNumber.MAX_SAFE_INTEGER-i. Kui JavaScripti klient selle ID kätte saab, võidakse see valesti ümardada, mis viib andmete rikkumiseni või võimetuseni õiget kirjet kätte saada. - API integratsioonid: Teenused nagu Twitter (nüüd X) kasutavad säutsude ID-de jaoks 64-bitiseid täisarve nimega "Snowflakes". Nende ID-de korrektne käsitlemine JavaScripti esiküljel nõuab erilist hoolt.
- Krüptograafia: Krüptograafilised operatsioonid hõlmavad sageli aritmeetikat äärmiselt suurte algarvudega, mis ületavad kaugelt standardse
Number-tüübi võimekuse. - Kõrge täpsusega ajatemplid: Mõned süsteemid pakuvad nanosekundi täpsusega ajatempleid, mida sageli esitatakse 64-bitise täisarvuna epohhist alates. Selle salvestamine standardsesse
Number-tüüpi kärbiks selle täpsust.
Siin tuleb mängu BigInt: lahendus suvalise täpsusega täisarvudele
BigInt loodi spetsiaalselt selle probleemi lahendamiseks. See on JavaScriptis eraldiseisev numbriline primitiivtüüp, mis suudab esitada suvalise täpsusega täisarve. See tähendab, et BigInt ei ole piiratud kindla arvu bittidega; see võib kasvada või kahaneda vastavalt hoitavale väärtusele, olles piiratud ainult host-süsteemi vaba mäluga.
BigInt-i loomine
BigInt-väärtuse loomiseks on kaks peamist viisi:
- Täisarvu literaalile `n`-i lisamine: See on kõige lihtsam ja levinum meetod.
- `BigInt()` konstruktorfunktsiooni kasutamine: See on kasulik stringide või Number-tüüpi väärtuste teisendamiseks BigInt-ideks.
Siin on mõned näited:
// 'n' järelliite kasutamine
const aLargeNumber = 9007199254740991n;
const anEvenLargerNumber = 1234567890123456789012345678901234567890n;
// BigInt() konstruktori kasutamine
const fromString = BigInt("98765432109876543210");
const fromNumber = BigInt(100); // Loob 100n
// Kontrollime nende tĂĽĂĽpi
console.log(typeof aLargeNumber); // "bigint"
console.log(typeof fromString); // "bigint"
Oluline märkus: Te ei saa kasutada `new` operaatorit koos `BigInt()`-ga, kuna see on primitiivtüüp, mitte objekt. `new BigInt()` viskab `TypeError`-i.
Põhiline aritmeetika BigInt-iga
BigInt toetab teile tuttavaid standardseid aritmeetilisi operaatoreid, kuid need käituvad rangelt täisarvude maailmas.
Liitmine, lahutamine ja korrutamine
Need operaatorid töötavad täpselt nii, nagu ootaksite, kuid suudavad käsitleda tohutuid arve ilma täpsust kaotamata.
const num1 = 12345678901234567890n;
const num2 = 98765432109876543210n;
// Liitmine
console.log(num1 + num2); // 111111111011111111100n
// Lahutamine
console.log(num2 - num1); // 86419753208641975320n
// Korrutamine
console.log(num1 * 2n); // 24691357802469135780n
Jagamine (`/`)
See on koht, kus BigInt-i käitumine erineb oluliselt tavalisest Number-tüübi jagamisest. Kuna BigInt-id saavad esitada ainult täisarve, kärbitakse jagamise tulemus alati nulli suunas (murdoosa jäetakse ära).
const dividend = 10n;
const divisor = 3n;
console.log(dividend / divisor); // 3n (mitte 3.333...)
const negativeDividend = -10n;
console.log(negativeDividend / divisor); // -3n
// Võrdluseks Number-tüübi jagamisega
console.log(10 / 3); // 3.3333333333333335
See ainult täisarvudega jagamine on ülioluline. Kui peate tegema arvutusi, mis nõuavad komakohtade täpsust, ei ole BigInt õige tööriist. Peaksite kasutama teeke nagu `Decimal.js` või haldama komakohta käsitsi (näiteks töötades finantsarvutustes väikseima valuutaühikuga).
Jääk (`%`) ja astendamine (`**`)
Jäägioperaator (`%`) ja astendamisoperaator (`**`) töötavad samuti BigInt-väärtustega ootuspäraselt.
console.log(10n % 3n); // 1n
console.log(-10n % 3n); // -1n
// Astendamine võib luua tõeliselt massiivseid arve
const base = 2n;
const exponent = 100n;
const hugeNumber = base ** exponent;
console.log(hugeNumber); // 1267650600228229401496703205376n
Range reegel: `BigInt`-i ja `Number`-i ei tohi segada
Üks olulisemaid reegleid, mida BigInt-iga töötades meeles pidada, on see, et te ei saa segada `BigInt`-i ja `Number`-tüüpi operande enamikus aritmeetilistes tehetes. Selle katse tulemuseks on `TypeError`.
See disainivalik oli tahtlik. See takistab arendajatel kogemata täpsust kaotamast, kui BigInt teisendatakse kaudselt Number-tüübiks. Keel sunnib teid oma kavatsustes olema selgesõnaline.
const myBigInt = 100n;
const myNumber = 50;
try {
const result = myBigInt + myNumber; // See ebaõnnestub
} catch (error) {
console.error(error); // TypeError: Cannot mix BigInt and other types, use explicit conversions
}
Õige lähenemine: selgesõnaline teisendamine
Tehte sooritamiseks BigInt-i ja Number-tüübi vahel peate ühe neist selgesõnaliselt teise tüübiks teisendama.
const myBigInt = 100n;
const myNumber = 50;
// Teisenda Number BigInt-iks
const result1 = myBigInt + BigInt(myNumber);
console.log(result1); // 150n
// Teisenda BigInt Number-iks (kasuta ettevaatlikult!)
const result2 = Number(myBigInt) + myNumber;
console.log(result2); // 150
Hoiatus: BigInt-i teisendamine Number-tüübiks `Number()`-ga on ohtlik, kui BigInt-i väärtus on väljaspool turvalist täisarvude vahemikku. See võib uuesti tekitada just neid täpsusvigu, mida BigInt on loodud vältima.
const veryLargeBigInt = 9007199254740993n;
const convertedToNumber = Number(veryLargeBigInt);
console.log(veryLargeBigInt); // 9007199254740993n
console.log(convertedToNumber); // 9007199254740992 - Täpsus kadunud!
Üldreegel on: kui töötate potentsiaalselt suurte täisarvudega, püsige kõigi oma arvutuste puhul BigInt-i ökosüsteemis. Teisendage tagasi Number-tüübiks ainult siis, kui olete kindel, et väärtus on turvalises vahemikus.
Võrdlus- ja loogikaoperaatorid
Kuigi aritmeetilised operaatorid on tüüpide segamise osas ranged, on võrdlus- ja loogikaoperaatorid leebemad.
Suhtelised võrdlused (`>`, `<`, `>=`, `<=`)
Saate turvaliselt võrrelda BigInt-i Number-tüübiga. JavaScript käsitleb nende matemaatiliste väärtuste võrdlust korrektselt.
console.log(10n > 5); // true
console.log(10n < 20); // true
console.log(100n >= 100); // true
console.log(99n <= 100); // true
Võrdsus (`==` vs. `===`)
Erinevus lõdva võrdsuse (`==`) ja range võrdsuse (`===`) vahel on BigInt-i puhul väga oluline.
- Range võrdsus (`===`) kontrollib nii väärtust kui ka tüüpi. Kuna `BigInt` ja `Number` on erinevad tüübid, on `10n === 10` alati väär.
- Lõtv võrdsus (`==`) teostab tüübi teisenduse. See peab `10n == 10` tõeseks, kuna nende matemaatilised väärtused on samad.
console.log(10n == 10); // true
console.log(10n === 10); // false (erinevad tĂĽĂĽbid)
console.log(10n === 10n); // true (sama väärtus ja tüüp)
Selguse huvides ja ootamatu käitumise vältimiseks on sageli parim praktika kasutada ranget võrdsust ja tagada, et võrdlete sama tüüpi väärtusi.
Tõeväärtuskontekst
Sarnaselt Number-tüübile saab ka BigInt-e hinnata tõeväärtuskontekstis (nt `if`-lauses). Väärtust `0n` peetakse vääraks, samas kui kõiki teisi BigInt-väärtusi (positiivseid või negatiivseid) peetakse tõeseks.
if (0n) {
// See kood ei käivitu
} else {
console.log("0n on väär");
}
if (1n && -10n) {
console.log("Nullist erinevad BigInt-id on tõesed");
}
BigInt-i praktilised kasutusjuhud globaalses kontekstis
Nüüd, kui mõistame mehaanikat, uurime, kus BigInt särab reaalsetes, rahvusvahelistes rakendustes.
1. Finantstehnoloogia (FinTech)
Ujukoma-aritmeetika on finantsarvutustes kurikuulsalt problemaatiline ümardamisvigade tõttu. Levinud ülemaailmne praktika on esitada rahalised väärtused väikseima valuutaühiku täisarvudena (nt sendid USD jaoks, jeenid JPY jaoks, satoshid Bitcoini jaoks).
Kuigi standardsed Number-tüübid võivad väiksemate summade jaoks olla piisavad, muutub BigInt hindamatuks suurte tehingute, koondsummade või krüptovaluutadega tegelemisel, mis sageli hõlmavad väga suuri arve.
// Suure ülekande esitamine väikseimas ühikus (nt Wei Ethereumi jaoks)
const walletBalance = 1234567890123456789012345n; // Suur kogus Wei-d
const transactionAmount = 9876543210987654321n;
const newBalance = walletBalance - transactionAmount;
console.log(`Uus saldo: ${newBalance.toString()} Wei`);
// Uus saldo: 1224691346912369134691246 Wei
BigInt-i kasutamine tagab, et iga üksik ühik on arvesse võetud, kõrvaldades ümardamisvead, mis võiksid tekkida ujukoma-matemaatikaga.
2. KrĂĽptograafia
Kaasaegne krüptograafia, nagu RSA algoritm, mida kasutatakse TLS/SSL krüpteerimisel üle veebi, tugineb aritmeetikale äärmiselt suurte algarvudega. Need arvud on sageli 2048-bitised või suuremad, ületades kaugelt JavaScripti Number-tüübi võimekuse.
BigInt-iga saab krüptograafilisi algoritme nüüd implementeerida või polütäita otse JavaScriptis, avades uusi võimalusi brauserisisestele turvatööriistadele ja WebAssembly-põhistele rakendustele.
3. 64-bitiste identifikaatorite käsitlemine
Nagu varem mainitud, genereerivad paljud hajutatud süsteemid ja andmebaasid 64-bitiseid unikaalseid identifikaatoreid. See on levinud muster suurtes süsteemides, mida arendavad ettevõtted üle maailma.
Enne BigInt-i pidid JavaScripti rakendused, mis kasutasid neid ID-sid tagastavaid API-sid, käsitlema neid stringidena, et vältida täpsuse kadu. See oli kohmakas lahendus.
// API vastus 64-bitise kasutaja ID-ga
const apiResponse = '{"userId": "1143534363363377152", "username": "dev_user"}';
// Vana viis (parsimine stringina)
const userDataString = JSON.parse(apiResponse);
console.log(userDataString.userId); // "1143534363363377152"
// Igasugune matemaatika nõuaks teeki või stringidega manipuleerimist.
// Uus viis (kohandatud reviver-funktsiooni ja BigInt-iga)
const userDataBigInt = JSON.parse(apiResponse, (key, value) => {
// Lihtne kontroll potentsiaalsete ID-väljade teisendamiseks BigInt-iks
if (key === 'userId' && typeof value === 'string' && /^[0-9]+$/.test(value)) {
return BigInt(value);
}
return value;
});
console.log(userDataBigInt.userId); // 1143534363363377152n
console.log(typeof userDataBigInt.userId); // "bigint"
BigInt-iga saab neid ID-sid esitada nende õige numbrilise tüübina, mis võimaldab korrektset sorteerimist, võrdlemist ja salvestamist.
4. Teaduslik ja matemaatiline arvutamine
Valdkonnad nagu arvuteooria, kombinatoorika ja füüsikasimulatsioonid nõuavad sageli arvutusi, mis toodavad täisarve, mis on suuremad kui Number.MAX_SAFE_INTEGER. Näiteks suurte faktoriaalide või Fibonacci jada liikmete arvutamine on BigInt-iga lihtne.
function factorial(n) {
// Kasuta BigInt-e algusest peale
let result = 1n;
for (let i = 2n; i <= n; i++) {
result *= i;
}
return result;
}
// Arvuta 50 faktoriaal
const fact50 = factorial(50n);
console.log(fact50.toString());
// 30414093201713378043612608166064768844377641568960512000000000000n
Edasijõudnute teemad ja levinumad lõksud
Kuigi BigInt on võimas, on mitmeid nüansse ja potentsiaalseid probleeme, millest tuleb teadlik olla.
JSON-serialiseerimine: suur komistuskivi
Oluline väljakutse tekib, kui proovite serialiseerida BigInt-i sisaldavat objekti JSON-stringiks. Vaikimisi viskab `JSON.stringify()` `TypeError`-i, kui see kohtab BigInt-i.
const data = {
id: 12345678901234567890n,
status: "active"
};
try {
JSON.stringify(data);
} catch (error) {
console.error(error); // TypeError: Do not know how to serialize a BigInt
}
Põhjus on selles, et JSON-spetsifikatsioonil puudub andmetüüp suvaliselt suurte täisarvude jaoks ja vaikne teisendamine standardarvuks võib kaasa tuua täpsuse kao. Selle lahendamiseks peate pakkuma kohandatud serialiseerimisstrateegia.
Lahendus 1: implementeerige `toJSON`-meetod
Saate lisada `toJSON`-meetodi `BigInt.prototype`-ile. `JSON.stringify()` kutsub seda meetodit automaatselt välja.
// Lisa see oma rakenduse seadistusfaili
BigInt.prototype.toJSON = function() {
return this.toString();
};
const data = { id: 12345678901234567890n, status: "active" };
const jsonString = JSON.stringify(data);
console.log(jsonString); // "{"id":"12345678901234567890","status":"active"}"
Lahendus 2: kasutage `replacer`-funktsiooni
Kui te ei soovi globaalset prototĂĽĂĽpi muuta, saate `JSON.stringify()`-le edasi anda `replacer`-funktsiooni.
const replacer = (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
}
return value;
};
const data = { id: 12345678901234567890n, status: "active" };
const jsonString = JSON.stringify(data, replacer);
console.log(jsonString); // "{"id":"12345678901234567890","status":"active"}"
Pidage meeles, et vajate ka vastavat `reviver`-funktsiooni `JSON.parse()` kasutamisel, et teisendada string-esitus tagasi BigInt-iks, nagu näidati varem 64-bitise ID näites.
Bitikaupa tehtavad operatsioonid
BigInt toetab ka bitikaupa tehtavaid operatsioone (`&`, `|`, `^`, `~`, `<<`, `>>`), mis käsitlevad BigInt-i kui bittide jada kahendsüsteemi täiendkoodis. See on äärmiselt kasulik madala taseme andmetöötluseks, binaarprotokollide parsimiseks või teatud algoritmide implementeerimiseks.
const mask = 0b1111n; // 4-bitine mask
const value = 255n; // 0b11111111n
// Bitikaupa JA
console.log(value & mask); // 15n (mis on 0b1111n)
// Vasaknihe
console.log(1n << 64n); // 18446744073709551616n (2^64)
Pange tähele, et märgita paremnihke operaator (`>>>`) ei ole BigInt-i jaoks toetatud, kuna iga BigInt on märgiga.
Jõudlusega seotud kaalutlused
Kuigi BigInt on võimas tööriist, ei ole see Number-tüübi otsene asendaja. BigInt-idega tehtavad operatsioonid on üldiselt aeglasemad kui nende `Number`-vastandid, sest need nõuavad keerukamat, muutuva pikkusega mäluhaldust ja arvutusloogikat. Standardse aritmeetika jaoks, mis mahub mugavalt turvalisse täisarvude vahemikku, peaksite optimaalse jõudluse tagamiseks jätkama `Number`-tüübi kasutamist.
Rusikareegel on lihtne: kasutage vaikimisi Number-tüüpi. Minge üle BigInt-ile ainult siis, kui teate, et peate tegelema täisarvudega, mis võivad ületada `Number.MAX_SAFE_INTEGER`-i.
Brauseri- ja keskkonnatugi
BigInt on osa ES2020 standardist ja on laialdaselt toetatud kõigis kaasaegsetes veebibrauserites (Chrome, Firefox, Safari, Edge) ja serveripoolsetes keskkondades nagu Node.js (versioon 10.4.0 ja uuemad). Siiski ei ole see saadaval vanemates brauserites nagu Internet Explorer. Kui peate toetama vanemaid keskkondi, peate endiselt tuginema kolmandate osapoolte suurte arvude teekidele ja potentsiaalselt kasutama transpilerit nagu Babel, mis suudab pakkuda polütäidet.
Ülemaailmsele publikule on alati mõistlik kontrollida ühilduvusressurssi nagu "Can I Use...", et tagada, et teie sihtkasutajaskond saaks teie koodi probleemideta käitada.
Kokkuvõte: uus piir JavaScripti jaoks
BigInt-i kasutuselevõtt tähistab JavaScripti keele olulist küpsemist. See lahendab otse pikaajalise piirangu ja annab arendajatele võimaluse luua uut tüüpi rakendusi, mis nõuavad ülitäpset täisarvude aritmeetikat. Pakkudes loomulikku, sisseehitatud lahendust, kaotab BigInt paljude levinud kasutusjuhtude puhul vajaduse väliste teekide järele, mis viib puhtama, tõhusama ja turvalisema koodini.
Põhilised järeldused globaalsetele arendajatele:
- Kasutage BigInt-i täisarvude jaoks, mis ületavad 253 - 1: Alati, kui teie rakendus võib käsitleda täisarve, mis on suuremad kui `Number.MAX_SAFE_INTEGER`, kasutage täpsuse tagamiseks BigInt-i.
- Olge tüüpidega selgesõnaline: Pidage meeles, et te ei saa segada `BigInt`-i ja `Number`-tüüpi aritmeetilistes tehetes. Tehke alati selgesõnalisi teisendusi ja olge teadlik potentsiaalsest täpsuse kaost, kui teisendate suurt BigInt-i tagasi Number-tüübiks.
- Õppige selgeks JSON-i käsitlemine: Olge valmis `JSON.stringify()`-st tulevaks `TypeError`-iks. Implementeerige robustne serialiseerimis- ja deserialiseerimisstrateegia, kasutades `toJSON`-meetodit või `replacer`/`reviver`-paari.
- Valige töö jaoks õige tööriist: BigInt on mõeldud ainult täisarvudele. Suvalise täpsusega kümnendarvude aritmeetika jaoks jäävad sobivaks valikuks teegid nagu `Decimal.js`. Kasutage `Number`-tüüpi kõigi muude mitte-täisarvuliste või väikeste täisarvude arvutuste jaoks, et säilitada jõudlus.
BigInt-i omaks võttes saab rahvusvaheline JavaScripti kogukond nüüd enesekindlalt tegeleda väljakutsetega rahanduses, teaduses, andmete terviklikkuses ja krüptograafias, nihutades veebis ja mujal võimaliku piire.