En omfattende guide til JavaScripts BigInt-type, der dækker dens funktioner, brug og anvendelser til håndtering af stor heltalsaritmetik. Lær at overvinde JavaScripts begrænsninger og udføre komplekse beregninger med præcision.
JavaScript BigInt: Beherskelse af stor heltalsaritmetik
Selvom JavaScript er et alsidigt sprog, har det begrænsninger, når det kommer til at håndtere meget store heltal. Standarden `Number`-typen kan kun repræsentere heltal præcist op til en vis grænse, kendt som `Number.MAX_SAFE_INTEGER`. Ud over denne grænse bliver beregninger upræcise, hvilket fører til uventede resultater. Det er her, BigInt
kommer til undsætning. Introduceret i ECMAScript 2020 er BigInt
et indbygget objekt, der giver en måde at repræsentere og manipulere heltal af vilkårlig størrelse på, hvilket overskrider begrænsningerne for standard `Number`-typen.
Forståelsen af behovet for BigInt
Før BigInt
måtte JavaScript-udviklere stole på biblioteker eller brugerdefinerede implementeringer for at håndtere store heltalsberegninger. Disse løsninger medførte ofte et performancetab og øget kompleksitet. Introduktionen af BigInt
gav en native og effektiv måde at arbejde med store heltal på, hvilket åbnede op for muligheder for applikationer inden for forskellige domæner, herunder:
- Kryptografi: Sikker håndtering af store primtal er afgørende for kryptografiske algoritmer.
- Finansielle beregninger: Præcis repræsentation af store pengeværdier uden tab af præcision.
- Videnskabelig databehandling: Udførelse af komplekse beregninger, der involverer ekstremt store eller små tal.
- Tidsstempler med høj præcision: Repræsentation af tidsstempler med nanosekund-præcision.
- ID-generering: Oprettelse af unikke og meget store identifikatorer.
Oprettelse af BigInt-værdier
Der er to primære måder at oprette BigInt
-værdier på i JavaScript:
- Brug af `BigInt()`-konstruktøren: Denne konstruktør kan konvertere et tal, en streng eller en boolesk værdi til en
BigInt
. - Brug af `n`-suffikset: At tilføje `n` til en heltalsliteral opretter en
BigInt
.
Eksempler:
Brug af `BigInt()`-konstruktøren:
const bigIntFromNumber = BigInt(12345678901234567890);
const bigIntFromString = BigInt("98765432109876543210");
const bigIntFromBoolean = BigInt(true); // Resulterer i 1n
const bigIntFromFalseBoolean = BigInt(false); // Resulterer i 0n
console.log(bigIntFromNumber); // Output: 12345678901234567890n
console.log(bigIntFromString); // Output: 98765432109876543210n
console.log(bigIntFromBoolean); // Output: 1n
console.log(bigIntFromFalseBoolean); // Output: 0n
Brug af `n`-suffikset:
const bigIntLiteral = 12345678901234567890n;
console.log(bigIntLiteral); // Output: 12345678901234567890n
Vigtig bemærkning: Du kan ikke blande BigInt
- og Number
-værdier direkte i aritmetiske operationer. Du skal eksplicit konvertere dem til den samme type, før du udfører beregninger. Forsøg på at blande dem direkte vil resultere i en `TypeError`.
Aritmetiske operationer med BigInt
BigInt
understøtter de fleste af de almindelige aritmetiske operatorer, herunder:
- Addition (`+`)
- Subtraktion (`-`)
- Multiplikation (`*`)
- Division (`/`)
- Rest (`%`)
- Eksponentiering (`**`)
Eksempler:
const a = 12345678901234567890n;
const b = 98765432109876543210n;
const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / 2n; // Bemærk: Division afkorter mod nul
const remainder = a % 7n;
const power = a ** 3n; // Eksponentiering virker som forventet
console.log("Sum:", sum); // Output: Sum: 111111111011111111100n
console.log("Differens:", difference); // Output: Differens: -86419753208641975320n
console.log("Produkt:", product); // Output: Produkt: 1219326311370217957951669538098765432100n
console.log("Kvotient:", quotient); // Output: Kvotient: 6172839450617283945n
console.log("Rest:", remainder); // Output: Rest: 5n
console.log("Potens:", power); // Output: Potens: 187641281029182300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n
Vigtige overvejelser:
- Division: Division med
BigInt
-værdier afkorter mod nul. Det betyder, at decimaldelen af resultatet kasseres. Hvis du har brug for mere præcis division, kan du overveje at bruge biblioteker, der understøtter aritmetik med vilkårlig præcision. - Unær plus-operator (+): Den unære plus-operator (+) kan ikke bruges med
BigInt
-værdier, fordi det ville skabe konflikt med legacy asm.js-kode. Brug `Number()`-konverteringsfunktionen til at konvertere en BigInt til et Number, hvis du har brug for en numerisk repræsentation (med den forståelse, at du kan miste præcision). - Bitvise operatorer:
BigInt
understøtter også bitvise operatorer som `&`, `|`, `^`, `~`, `<<` og `>>`. Disse operatorer fungerer som forventet på den binære repræsentation afBigInt
-værdierne.
Sammenligningsoperatorer
Du kan bruge standard sammenligningsoperatorer (`==`, `!=`, `<`, `>`, `<=`, `>=`) til at sammenligne BigInt
-værdier med andre BigInt
-værdier eller endda med Number
-værdier. Vær dog opmærksom på potentialet for type coercion (automatisk typekonvertering).
Eksempler:
const a = 10n;
const b = 20n;
const c = 10;
console.log(a == b); // Output: false
console.log(a != b); // Output: true
console.log(a < b); // Output: true
console.log(a > b); // Output: false
console.log(a <= b); // Output: true
console.log(a >= b); // Output: false
console.log(a == c); // Output: true (type coercion)
console.log(a === c); // Output: false (no type coercion)
Bedste praksis: Brug streng lighed (`===`) og streng ulighed (`!==`) for at undgå uventet type coercion (automatisk typekonvertering), når du sammenligner BigInt
- og Number
-værdier.
Konvertering mellem BigInt og Number
Selvom direkte aritmetiske operationer mellem BigInt
og Number
ikke er tilladt, kan du konvertere mellem de to typer. Vær dog opmærksom på det potentielle tab af præcision, når du konverterer en BigInt
til et Number
, hvis BigInt
-værdien overstiger `Number.MAX_SAFE_INTEGER`.
Eksempler:
const bigIntValue = 9007199254740991n; // Number.MAX_SAFE_INTEGER
const numberValue = Number(bigIntValue); // Konvertering af BigInt til Number
console.log(numberValue); // Output: 9007199254740991
const largerBigIntValue = 9007199254740992n; // Overskrider Number.MAX_SAFE_INTEGER
const largerNumberValue = Number(largerBigIntValue);
console.log(largerNumberValue); // Output: 9007199254740992 (kan være upræcis)
const numberToBigInt = BigInt(12345); // Konvertering af Number til BigInt
console.log(numberToBigInt); // Output: 12345n
Anvendelsestilfælde og eksempler
Kryptografi
Kryptografiske algoritmer er ofte afhængige af meget store primtal for sikkerhedens skyld. BigInt
giver en måde at repræsentere og manipulere disse tal effektivt.
// Eksempel: Generering af et simpelt (usikkert) nøglepar
function generateKeyPair() {
const p = 281n; // Et primtal
const q = 283n; // Et andet primtal
const n = p * q; // Modulus
const totient = (p - 1n) * (q - 1n); // Eulers totientfunktion
// Vælg et e (offentlig eksponent), så 1 < e < totient og gcd(e, totient) = 1
const e = 17n;
// Beregn d (privat eksponent), så (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("Offentlig nøgle:", keyPair.publicKey);
console.log("Privat nøgle:", keyPair.privateKey);
Bemærk: Dette er et forenklet eksempel kun til demonstrationsformål. Kryptografi i den virkelige verden bruger meget større primtal og mere sofistikerede algoritmer.
Finansielle beregninger
Når man arbejder med store pengesummer, især i internationale transaktioner, er præcision afgørende. BigInt
kan forhindre afrundingsfejl og sikre nøjagtige beregninger.
// Eksempel: Beregning af rentesregning
function calculateCompoundInterest(principal, rate, time) {
const principalBigInt = BigInt(principal * 100); // Konverter til øre
const rateBigInt = BigInt(rate * 10000); // Konverter til ti-tusindedele af en procent
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% rentefod
const time = 10; // 10 år
const finalAmount = calculateCompoundInterest(principal, rate, time);
console.log("Endeligt beløb:", finalAmount); // Output: Endeligt beløb: 1628894.6267774413 (cirka)
I dette eksempel konverterer vi hovedstolen og renten til BigInt
-værdier for at undgå afrundingsfejl under beregningen. Resultatet konverteres derefter tilbage til et Number
til visning.
Arbejde med store ID'er
I distribuerede systemer kan det være en udfordring at generere unikke ID'er på tværs af flere servere. Brug af BigInt
giver dig mulighed for at oprette meget store ID'er, der med stor sandsynlighed ikke vil kollidere.
// Eksempel: Generering af et unikt ID baseret på tidsstempel og server-ID
function generateUniqueId(serverId) {
const timestamp = BigInt(Date.now());
const serverIdBigInt = BigInt(serverId);
const random = BigInt(Math.floor(Math.random() * 1000)); // Tilføj en smule tilfældighed
// Kombiner værdierne for at oprette et unikt ID
const uniqueId = (timestamp << 20n) + (serverIdBigInt << 10n) + random;
return uniqueId.toString(); // Returner som en streng for nem håndtering
}
const serverId = 123; // Eksempel på server-ID
const id1 = generateUniqueId(serverId);
const id2 = generateUniqueId(serverId);
console.log("Unikt ID 1:", id1);
console.log("Unikt ID 2:", id2);
BigInt og JSON
BigInt
-værdier understøttes ikke native af JSON. Forsøg på at serialisere et JavaScript-objekt, der indeholder en BigInt
, ved hjælp af `JSON.stringify()` vil resultere i en `TypeError`. For at håndtere BigInt
-værdier, når du arbejder med JSON, har du et par muligheder:
- Konverter til streng: Konverter
BigInt
til en streng før serialisering. Dette er den mest almindelige og ligetil tilgang. - Brugerdefineret serialisering/deserialisering: Brug en brugerdefineret serialiserings-/deserialiseringsfunktion til at håndtere
BigInt
-værdier.
Eksempler:
Konvertering til streng:
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Konverter BigInt til streng før serialisering
data.id = data.id.toString();
const jsonData = JSON.stringify(data);
console.log(jsonData); // Output: {"id":"12345678901234567890","name":"Example Data"}
// Ved deserialisering skal du konvertere strengen tilbage til en BigInt
const parsedData = JSON.parse(jsonData, (key, value) => {
if (key === "id") {
return BigInt(value);
}
return value;
});
console.log(parsedData.id); // Output: 12345678901234567890n
Brugerdefineret serialisering/deserialisering (ved hjælp af `replacer` og `reviver`):
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Brugerdefineret serialisering
const jsonData = JSON.stringify(data, (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
} else {
return value;
}
});
console.log(jsonData);
// Brugerdefineret deserialisering
const parsedData = JSON.parse(jsonData, (key, value) => {
if (typeof value === 'string' && /^[0-9]+$/.test(value)) { //tjek om det er et tal og en streng
try {
return BigInt(value);
} catch(e) {
return value;
}
}
return value;
});
console.log(parsedData.id);
Browserkompatibilitet
BigInt
understøttes bredt i moderne browsere. Det er dog vigtigt at tjekke kompatibiliteten for ældre browsere eller miljøer. Du kan bruge et værktøj som Can I use til at verificere browserunderstøttelse. Hvis du skal understøtte ældre browsere, kan du overveje at bruge en polyfill, men vær opmærksom på, at polyfills kan påvirke ydeevnen.
Overvejelser om ydeevne
Selvom BigInt
giver en kraftfuld måde at arbejde med store heltal på, er det vigtigt at være opmærksom på potentielle konsekvenser for ydeevnen.
BigInt
-operationer kan være langsommere end standardNumber
-operationer.- Konvertering mellem
BigInt
ogNumber
kan også medføre et overhead.
Brug derfor kun BigInt
, når det er nødvendigt, og optimer din kode for ydeevne, hvis du udfører et stort antal BigInt
-operationer.
Konklusion
BigInt
er en værdifuld tilføjelse til JavaScript, der gør det muligt for udviklere at håndtere stor heltalsaritmetik med præcision. Ved at forstå dens funktioner, begrænsninger og anvendelsestilfælde kan du udnytte BigInt
til at bygge robuste og nøjagtige applikationer inden for forskellige domæner, herunder kryptografi, finansielle beregninger og videnskabelig databehandling. Husk at overveje browserkompatibilitet og konsekvenser for ydeevnen, når du bruger BigInt
i dine projekter.
Yderligere udforskning
Denne guide giver et omfattende overblik over BigInt
i JavaScript. Udforsk de linkede ressourcer for mere dybdegående information og avancerede teknikker.