← Quay lại blog

Bản chất toán học đằng sau sai số dấu phẩy động: Số học nhị phân IEEE 754 trong các Web Engine

PetexSpace

Hiếm có hiện tượng khác thường nào trong khoa học máy tính lại gây ra nhiều sự bối rối cho các lập trình viên web như biểu thức nổi tiếng 0.1 + 0.2 !== 0.3. Trong môi trường runtime JavaScript, việc tính toán 0.1 + 0.2 sẽ trả về 0.30000000000000004.

Dù thường bị hiểu nhầm là một lỗi của ngôn ngữ, hành vi này thực chất là hệ quả trực tiếp và hoàn toàn có thể dự đoán được về mặt toán học từ Tiêu chuẩn Số học Dấu phẩy động IEEE 754 (IEEE 754 Standard for Floating-Point Arithmetic). Các JavaScript engine (như V8, JavaScriptCore và SpiderMonkey) đều triển khai tiêu chuẩn IEEE 754 cho mọi giá trị thuộc kiểu dữ liệu nguyên thủy number.

Việc thấu hiểu cấu trúc nhị phân chuẩn xác của số dấu phẩy động 64-bit sẽ làm sáng tỏ lý do tại sao các phân số thập phân cơ số 10 không thể kết thúc hữu hạn trong hệ nhị phân, cách các chế độ làm tròn tạo ra sai số nhỏ nhưng tích tụ dần, nguyên nhân khiến triệt tiêu thảm họa (catastrophic cancellation) phá hủy độ chính xác trong tính toán khoa học, và phương pháp xây dựng các engine toán học độ chính xác tùy ý sử dụng các bộ tính toán phía client-side.

1. Cấu trúc giải phẫu của một số IEEE 754 độ chính xác kép (Float64)

Đặc tả ECMAScript quy định rằng mọi giá trị number tiêu chuẩn trong JavaScript đều được lưu trữ dưới dạng giá trị dấu phẩy động nhị phân 64-bit độ chính xác kép theo chuẩn IEEE 754 (binary64).

Một thanh ghi dấu phẩy động 64-bit được chia thành ba trường bit (bitfield) chức năng: bit dấu (sign bit), số mũ phân vị (biased exponent), và phần định trị (significand, thường được gọi là fraction hoặc mantissa).

+-----------------------------------------------------------------------+
|              IEEE 754 Double-Precision (64-bit) Register              |
+-----------------------------------------------------------------------+
| Bit 63          Bits 62 - 52 (11 bits)      Bits 51 - 0 (52 bits)     |
| [ Sign (S) ]    [ Biased Exponent (E) ]     [ Fraction / Mantissa (M) ]|
|  1 bit           11 bits                     52 bits                  |
+-----------------------------------------------------------------------+

Phân tích chi tiết trường bit và giới hạn

  1. Bit dấu (SS): 1 bit (Bit 63). Xác định dấu toán học của giá trị. S=0S = 0 biểu diễn số dương, trong khi S=1S = 1 biểu diễn số âm.
  2. Số mũ phân vị (EE): 11 bits (Bit 62 đến 52). Mã hóa hệ số tỷ lệ theo lũy thừa của 2. Với 11 bit không dấu, E∈[0,2047]E \in [0, 2047]. Một độ lệch (bias) là 1023 (211−1−12^{11-1} - 1) được áp dụng, ánh xạ dải số mũ thực tế từ −1022-1022 đến +1023+1023. Các giá trị cực trị E=0E = 0 và E=2047E = 2047 được dành riêng cho các biểu diễn đặc biệt (số 0, subnormal, vô cực và NaN).
  3. Phần định trị / Mantissa (MM): 52 bits (Bit 51 đến 0). Mã hóa các chữ số thập phân phân số của phần định trị đã chuẩn hóa. Vì các số đã chuẩn hóa luôn có chữ số nhị phân dẫn đầu là 1 (1.b1b2b3…1.b_1 b_2 b_3 \dots), bit 1 dẫn đầu này là bit ngầm định ("hidden bit") và không cần lưu trong bộ nhớ, mang lại độ chính xác hiệu dụng lên tới 53 bit nhị phân.

Công thức giải mã giá trị toán học

Đối với các số dấu phẩy động đã chuẩn hóa (1≤E≤20461 \le E \le 2046), giá trị số thực VV được mã hóa bởi mẫu bit được xác định bởi:

V=(−1)S×(1+∑i=152b52−i⋅2−i)×2E−1023V = (-1)^S \times \left(1 + \sum_{i=1}^{52} b_{52-i} \cdot 2^{-i}\right) \times 2^{E - 1023}

Trong đó bk∈{0,1}b_k \in \{0, 1\} đại diện cho giá trị bit tại chỉ số phân số kk.

Công thức này đem lại độ chính xác tương đương khoảng 15.95 chữ số thập phân:

log⁡10(253)≈53⋅0.30103≈15.9546\log_{10}(2^{53}) \approx 53 \cdot 0.30103 \approx 15.9546

Bất kỳ phép tính thập phân nào yêu cầu độ chính xác vượt quá 15 đến 17 chữ số thập phân có nghĩa đều vượt quá giới hạn lưu trữ vật lý của một thanh ghi IEEE 64-bit.

2. Nghịch lý chuyển đổi phân số nhị phân: Tại sao 0.1 không thể biểu diễn hữu hạn

Để hiểu tại sao 0.1 + 0.2 !== 0.3, chúng ta phải truy nguyên quá trình các số phân số cơ số 10 được chuyển đổi sang phân số nhị phân cơ số 2.

Trong cơ số 10, một phân số có thể biểu diễn hữu hạn khi và chỉ khi các thừa số nguyên tố của mẫu số là ước của cơ số. Vì 10=2×510 = 2 \times 5, các phân số như 1/2=0.51/2 = 0.5, 1/4=0.251/4 = 0.25 và 1/5=0.21/5 = 0.2 kết thúc hữu hạn, trong khi 1/3=0.3333…1/3 = 0.3333\dots và 1/7=0.142857…1/7 = 0.142857\dots lặp vô hạn tuần hoàn.

Trong cơ số 2 (nhị phân), thừa số nguyên tố duy nhất là 2. Do đó, một phân số kết thúc hữu hạn khi và chỉ khi mẫu số của nó là lũy thừa của 2 (1/2,1/4,1/8,1/16,…1/2, 1/4, 1/8, 1/16, \dots). Những phân số có mẫu số chứa các thừa số nguyên tố khác ngoài 2 sẽ tuần hoàn vô hạn trong hệ nhị phân.

Chuyển đổi số thập phân 0.1 sang nhị phân

Việc chuyển đổi 0.1100.1_{10} sang nhị phân được thực hiện bằng cách nhân liên tiếp với 2, trích xuất phần nguyên ở mỗi bước:

0.1 * 2 = 0.2  ->  0 (integer)  remainder 0.2
0.2 * 2 = 0.4  ->  0 (integer)  remainder 0.4
0.4 * 2 = 0.8  ->  0 (integer)  remainder 0.8
0.8 * 2 = 1.6  ->  1 (integer)  remainder 0.6
0.6 * 2 = 1.2  ->  1 (integer)  remainder 0.2  <-- Loop begins here
0.2 * 2 = 0.4  ->  0 (integer)  remainder 0.4
0.4 * 2 = 0.8  ->  0 (integer)  remainder 0.8
0.8 * 2 = 1.6  ->  1 (integer)  remainder 0.6
0.6 * 2 = 1.2  ->  1 (integer)  remainder 0.2

Dãy số rơi vào một chu kỳ lặp tuần hoàn vô hạn:

0.110=0.00011001100110011001100110011…2=0.00011‾20.1_{10} = 0.00011001100110011001100110011\dots_2 = 0.0\overline{0011}_2

Khi chuẩn hóa sang ký hiệu khoa học với bit 1 ngầm định ở đầu, ta được:

1.1001100110011001100110011001100110011001100110011001…2×2−41.1001100110011001100110011001100110011001100110011001\dots_2 \times 2^{-4}
+-----------------------------------------------------------------------+
|               Truncation of Decimal 0.1 at 53 Bits                    |
+-----------------------------------------------------------------------+
| Stored Mantissa (52 bits + 1 hidden bit):                             |
| 1 . 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 |
|                                                                       |
| Next bits discarded during rounding: 10011...                         |
| Because bit 54 is 1 followed by non-zero bits, the value rounds UP:   |
|                                                                       |
| Resulting 64-bit IEEE representation of 0.1:                          |
| 0.1000000000000000055511151231257827021181583404541015625            |
+-----------------------------------------------------------------------+

Bởi vì thanh ghi chỉ chứa được 53 bit độ chính xác, chuỗi vô hạn này buộc phải được làm tròn. Theo quy tắc chuẩn làm tròn đến số gần nhất với trường hợp hòa hướng về số chẵn (round-to-nearest-ties-to-even) của IEEE 754, các bit phía sau buộc giá trị phải làm tròn lên.

Phép cộng số học: Từng bước tính (0.1 + 0.2)

Thực hiện phép cộng nhị phân đòi hỏi phải căn chỉnh số mũ của cả hai toán hạng:

Decimal 0.1 in float64:
Exponent: 2^-4 (biased E = 1019)
Mantissa: 1.1001100110011001100110011001100110011001100110011010_2

Decimal 0.2 in float64:
Exponent: 2^-3 (biased E = 1020)
Mantissa: 1.1001100110011001100110011001100110011001100110011010_2

Shift 0.1 mantissa right by 1 bit to match exponent 2^-3:
  0.1100110011001100110011001100110011001100110011001101 (0) * 2^-3
+ 1.1001100110011001100110011001100110011001100110011010     * 2^-3
----------------------------------------------------------------------
= 10.0100110011001100110011001100110011001100110011001111     * 2^-3

Normalize sum: Shift right 1 bit and increment exponent to 2^-2:
= 1.0010011001100110011001100110011001100110011001100111 (1) * 2^-2

Bit thứ 54 mang giá trị 1, khiến bit thấp nhất phải làm tròn lên:

Result=1.00100110011001100110011001100110011001100110011010002×2−2\text{Result} = 1.0010011001100110011001100110011001100110011001101000_2 \times 2^{-2}

Khi chuyển đổi ngược lại sang số thập phân, giá trị nhị phân này tương đương:

0.30000000000000004440892098500626161694526672363281250.3000000000000000444089209850062616169452667236328125

Trong khi đó, giá trị thập phân lý tưởng 0.3 khi làm tròn lại có dạng:

0.2999999999999999888977697537484345957636833190917968750.299999999999999988897769753748434595763683319091796875

Vì hai giá trị xấp xỉ riêng biệt này chiếm các mẫu bit khác nhau trong bộ nhớ, biểu thức so sánh 0.1 + 0.2 === 0.3 cho kết quả chính xác là false.

3. Các giá trị biên đặc biệt: Số Subnormal, Số 0 có dấu, Vô cực và NaN

Đặc tả IEEE 754 định nghĩa các mẫu số mũ dành riêng để biểu diễn các trạng thái biên, hiện tượng tràn dưới dần dần (gradual underflow), các vô cực toán học và các giá trị bất định.

+-----------------------------------------------------------------------+
|                    IEEE 754 Special Value Encoding                    |
+-----------------------------------------------------------------------+
| Exponent (E)    Fraction (M)        Interpreted Value                 |
|-----------------------------------------------------------------------|
| 00000000000_2   All Zeros (0)       Signed Zero (+0 or -0)            |
| 00000000000_2   Non-Zero            Subnormal (Denormalized) Number   |
| 00000000001_2   Any                 Normalized Value                  |
| ...             Any                 Normalized Value                  |
| 11111111110_2   Any                 Normalized Value                  |
| 11111111111_2   All Zeros (0)       Signed Infinity (+Infinity / -Inf)|
| 11111111111_2   Non-Zero (MSB = 1)  Quiet NaN (qNaN)                  |
| 11111111111_2   Non-Zero (MSB = 0)  Signaling NaN (sNaN)              |
+-----------------------------------------------------------------------+

Số Subnormal: Hiện tượng tràn dưới dần dần

Khi các phép tính tạo ra các giá trị nhỏ hơn số dấu phẩy động dương đã chuẩn hóa nhỏ nhất (2−1022≈2.225×10−3082^{-1022} \approx 2.225 \times 10^{-308}), một triển khai đơn giản sẽ lập tức ép giá trị về 0 (flush-to-zero). Điều này gây ra sự mất mát độ chính xác đột ngột khi trừ hai số nhỏ gần bằng nhau.

IEEE 754 giải quyết vấn đề này thông qua các số subnormal (số phi chuẩn) khi E=0E = 0. Ở trạng thái này, bit dẫn đầu ngầm định chuyển từ 1 thành 0:

V=(−1)S×(0+∑i=152b52−i⋅2−i)×2−1022V = (-1)^S \times \left(0 + \sum_{i=1}^{52} b_{52-i} \cdot 2^{-i}\right) \times 2^{-1022}

Các số subnormal cho phép tràn dưới từ từ xuống đến Number.MIN_VALUE (2−1074≈5×10−3242^{-1074} \approx 5 \times 10^{-324}), dù việc xử lý các phép toán subnormal trên một số pipeline phần cứng có thể làm giảm hiệu năng.

Ý nghĩa vật lý của số 0 có dấu

Do IEEE 754 dành riêng một bit cho dấu, trong bộ nhớ tồn tại hai số không riêng biệt: số 0 dương (+0) và số 0 âm (-0).

Mặc dù ECMAScript định nghĩa +0 === -0 là true, hành vi của chúng lại khác nhau khi thực hiện phép chia:

console.log(1 / +0); // +Infinity
console.log(1 / -0); // -Infinity
console.log(Object.is(+0, -0)); // false

Số không có dấu đóng vai trò thiết yếu trong vật lý ứng dụng và giải tích phức, nơi việc tiếp cận một đường tiệm cận hoặc một nhánh cắt từ phía âm bắt buộc phải bảo toàn thông tin về pha.

Quiet NaN so với Signaling NaN

Khi một phép toán tạo ra kết quả toán học không xác định (chẳng hạn như 0/00 / 0 hoặc −1\sqrt{-1}), IEEE 754 sẽ trả về NaN (Not-a-Number).

Một giá trị NaN được mã hóa với toàn bộ các bit số mũ bằng 1 (E=2047E = 2047) cùng phần định trị khác không. Nếu bit phân số có trọng số cao nhất (MSB) là 1, nó đại diện cho một Quiet NaN (qNaN), giá trị này lan truyền thầm lặng qua các biểu thức mà không kích hoạt ngắt phần cứng. Nếu bit đó là 0, nó đại diện cho một Signaling NaN (sNaN), được thiết kế để kích hoạt các bẫy ngắt phần cứng (hardware traps).

Bởi vì IEEE 754 quy định rằng NaN không bằng bất kỳ thứ gì, tính chất phản xạ của phép so sánh bằng sẽ thất bại:

const x = NaN;
console.log(x === x); // false
console.log(Number.isNaN(x)); // true

4. Các sự cố trong thực tế: Trôi dạt tài chính và sai số tích lũy do làm tròn

Những sai lệch nhỏ trong số dấu phẩy động có thể tích tụ thành những sai số vận hành và tài chính nghiêm trọng khi mã nguồn phụ thuộc vào các kiểu dữ liệu nguyên thủy number tích hợp sẵn cho việc hạch toán kế toán hoặc các mô phỏng vật lý có số vòng lặp lớn.

+-----------------------------------------------------------------------+
|                    Financial Precision Drift Over Time                |
+-----------------------------------------------------------------------+
|  Transaction Loop (Adding $0.10 cents across 10,000,000 orders)      |
|                                                                       |
|  Expected Balance:  $1,000,000.00                                     |
|  Actual float64:    $1,000,000.000133288...                           |
|                                                                       |
|  Accumulated Drift: +$0.133 (Systemic accounting ledger imbalance)    |
+-----------------------------------------------------------------------+

Hiện tượng triệt tiêu thảm họa (Catastrophic Cancellation)

Hiện tượng triệt tiêu thảm họa xảy ra khi trừ hai số dấu phẩy động gần bằng nhau. Nếu cả hai toán hạng có chung 45 bit đầu tiên về độ chính xác, phép trừ sẽ triệt tiêu các bit dẫn đầu đó, đẩy các sai số làm tròn trước đây ở các bit đuôi trở thành những chữ số có nghĩa quan trọng nhất của kết quả.

Hãy xem xét việc tính giá trị f(x)=x+1−xf(x) = \sqrt{x + 1} - \sqrt{x} với giá trị lớn x=1014x = 10^{14}:

function naiveDifference(x) {
  return Math.sqrt(x + 1) - Math.sqrt(x);
}

console.log(naiveDifference(1e14)); // 5.000000413701855e-8
// True mathematical result:         5.000000000000001e-8
// Severe cancellation error:        ~8.2% relative error

Biến đổi lại biểu thức theo phương pháp đại số để tránh phép trừ sẽ loại bỏ hoàn toàn hiện tượng triệt tiêu:

f(x)=(x+1−x)(x+1+x)x+1+x=1x+1+xf(x) = \frac{(\sqrt{x+1} - \sqrt{x})(\sqrt{x+1} + \sqrt{x})}{\sqrt{x+1} + \sqrt{x}} = \frac{1}{\sqrt{x+1} + \sqrt{x}}
function stableDifference(x) {
  return 1 / (Math.sqrt(x + 1) + Math.sqrt(x));
}

console.log(stableDifference(1e14)); // 5.000000000000001e-8 (Exact)

Ranh giới số nguyên an toàn (Safe Integer Boundary)

Các số nguyên trong JavaScript được biểu diễn trong cùng phạm vi phân số 53 bit. Ranh giới mà tại đó các số nguyên liên tiếp không còn có thể được biểu diễn một cách duy nhất là:

Number.MAX_SAFE_INTEGER=253−1=9,007,199,254,740,991\text{Number.MAX\_SAFE\_INTEGER} = 2^{53} - 1 = 9,007,199,254,740,991

Vượt qua giá trị này, khoảng cách giữa các số nguyên có thể biểu diễn được sẽ tăng gấp đôi lên 2, 4, 8, và xa hơn nữa:

const maxSafe = Number.MAX_SAFE_INTEGER;
console.log(maxSafe + 1 === maxSafe + 2); // true! Both evaluate to 9007199254740992

Các hệ thống xử lý mã định danh cơ sở dữ liệu 64-bit hoặc các giao dịch khối lượng lớn tuyệt đối không được deserialize các giá trị này thành kiểu number mặc định của JavaScript.

5. Thiết kế kiến trúc toán học chính xác trên trình duyệt: Engine PetexSpace

Để loại bỏ hoàn toàn hiện tượng thiếu chính xác của số dấu phẩy động, engine máy tính với độ chính xác tùy ý của PetexSpace bỏ qua các biểu diễn xấp xỉ nhị phân IEEE 754. Bạn cũng có thể kiểm tra các cấu trúc dữ liệu số để phân tích trực tiếp các trường bit thô ngay trong trình duyệt của mình.

+-----------------------------------------------------------------------+
|               PetexSpace Rational Arithmetic Engine                   |
+-----------------------------------------------------------------------+
|  User Math Expression: "0.1 + 0.2 * 3.5"                              |
|       |                                                               |
|       v                                                               |
|  [ Shunting-Yard Lexer & Tokenizer ]                                  |
|       |                                                               |
|       v                                                               |
|  [ Abstract Syntax Tree (AST) ]                                       |
|       |                                                               |
|       v                                                               |
|  [ Rational Number Evaluation Pipeline ]                              |
|    - Every number stored as Fraction: { n: BigInt, d: BigInt }        |
|    - 0.1  --> Fraction(1n, 10n)                                       |
|    - 0.2  --> Fraction(2n, 10n) = Fraction(1n, 5n)                    |
|    - 3.5  --> Fraction(35n, 10n) = Fraction(7n, 2n)                  |
|       |                                                               |
|       v                                                               |
|  [ Exact Algebraic Operations ]                                       |
|    Addition:       (a/b) + (c/d) = (a*d + b*c) / (b*d)                |
|    Multiplication: (a/b) * (c/d) = (a*c) / (b*d)                      |
|    Simplification: Divide by Greatest Common Divisor (Euclid GCD)    |
|       |                                                               |
|       v                                                               |
|  Output: Exact Fraction -> Exact Decimal String (Zero Rounding Error) |
+-----------------------------------------------------------------------+

Biểu diễn phân số hữu tỉ

Thay vì chuyển đổi số thập phân thành các xấp xỉ nhị phân cơ số 2, PetexSpace mô hình hóa mọi giá trị số dưới dạng một phân số hữu tỉ chính xác tuyệt đối gồm hai số nguyên BigInt có độ dài tùy ý: một tử số (nn) và một mẫu số (dd).

// Pure TypeScript implementation of arbitrary-precision rational arithmetic
export class Rational {
  public readonly n: bigint; // Numerator
  public readonly d: bigint; // Denominator

  constructor(numerator: bigint, denominator: bigint = 1n) {
    if (denominator === 0n) {
      throw new RangeError('Division by zero in Rational fraction');
    }

    // Preserve sign exclusively on numerator
    const sign = (denominator < 0n) ? -1n : 1n;
    const absD = denominator < 0n ? -denominator : denominator;
    const absN = numerator < 0n ? -numerator : numerator;
    const gcdValue = Rational.gcd(absN, absD);

    this.n = (numerator * sign) / gcdValue;
    this.d = absD / gcdValue;
  }

  // Euclidean algorithm for Greatest Common Divisor
  private static gcd(a: bigint, b: bigint): bigint {
    while (b !== 0n) {
      const temp = b;
      b = a % b;
      a = temp;
    }
    return a;
  }

  // Parse decimal literal string into exact rational fraction
  public static fromDecimalString(val: string): Rational {
    const trimmed = val.trim();
    const parts = trimmed.split('.');

    if (parts.length === 1) {
      return new Rational(BigInt(parts[0]), 1n);
    }

    const integerPart = parts[0];
    const fractionPart = parts[1];
    const denominator = 10n ** BigInt(fractionPart.length);
    const numerator = BigInt(integerPart) * denominator + BigInt(fractionPart);

    return new Rational(numerator, denominator);
  }

  public add(other: Rational): Rational {
    // (a/b) + (c/d) = (a*d + b*c) / (b*d)
    const num = this.n * other.d + other.n * this.d;
    const den = this.d * other.d;
    return new Rational(num, den);
  }

  public multiply(other: Rational): Rational {
    // (a/b) * (c/d) = (a*c) / (b*d)
    return new Rational(this.n * other.n, this.d * other.d);
  }

  public toString(decimalPlaces: number = 20): string {
    const integerPart = this.n / this.d;
    let remainder = this.n % this.d;

    if (remainder === 0n) {
      return integerPart.toString();
    }

    let result = `${integerPart.toString()}.`;
    remainder = remainder < 0n ? -remainder : remainder;

    for (let i = 0; i < decimalPlaces && remainder !== 0n; i++) {
      remainder *= 10n;
      result += (remainder / this.d).toString();
      remainder %= this.d;
    }

    return result;
  }
}

Tính toán 0.1 + 0.2 với độ chính xác tuyệt đối

Khi người dùng nhập 0.1 + 0.2, engine sẽ thực thi:

const a = Rational.fromDecimalString("0.1"); // 1/10
const b = Rational.fromDecimalString("0.2"); // 2/10 -> simplified to 1/5
const sum = a.add(b);                         // (1*5 + 1*10)/(50) = 15/50 -> 3/10

console.log(sum.toString()); // Exactly "0.3"

Bởi vì các phép tính được thực thi bằng số học số nguyên thuần túy trên các cấu trúc BigInt có độ dài tùy ý, hiện tượng sai số làm tròn, cắt cụt định trị và độ lệch số mũ hoàn toàn không thể phát sinh.

Việc vận hành các engine toán học ngay tại client-side trang bị cho các công cụ khoa học và tài chính độ chính xác toán học tuyệt đối, loại bỏ hoàn toàn độ trễ truyền tải qua server, đồng thời đảm bảo sự riêng tư trọn vẹn cho các phép tính nhạy cảm.

CryptographyXác thựcSecurity

Kiến trúc của Mật khẩu Một lần Dựa trên Thời gian: Khám phá RFC 6238 và Cơ chế Tạo HMAC

Phân tích toán học và giao thức toàn diện về Mật khẩu Một lần Dựa trên Thời gian (TOTP) theo chuẩn RFC 6238, khám phá kỹ thuật dynamic truncation, bộ đếm bước HMAC-SHA1, xử lý lệch đồng hồ và thực thi an toàn ngay trên trình duyệt.

PetexSpace
CryptographyData EncodingMã QR

Giải phẫu mã QR: Cơ chế sửa lỗi Reed-Solomon và mã hóa ma trận

Khám phá chuyên sâu về mặt toán học của mã QR chuẩn ISO/IEC 18004, phân tích chi tiết số học trường Galois GF(2^8), đa thức sinh, cơ chế sửa lỗi Reed-Solomon và kỹ thuật kết xuất ma trận ngay trên trình duyệt.

PetexSpace
CryptographyWeb CryptoSecurity

Tính ngẫu nhiên mật mã học trong trình duyệt: Math.random so với crypto.getRandomValues

Nghiên cứu chuyên sâu về kiến trúc giữa bộ tạo số giả ngẫu nhiên (PRNG) và bộ tạo số giả ngẫu nhiên an toàn về mặt mật mã (CSPRNG) trong môi trường runtime trình duyệt, phân tích chi tiết xorshift128+, các cuộc tấn công tái tạo trạng thái và Web Cryptography API.

PetexSpace
CryptographyData EncodingBase32

So sánh Base32 và Base64: Khác biệt cấu trúc, quy tắc đệm và ứng dụng mật mã học

Đặc tả kỹ thuật chuyên sâu về các chuẩn mã hóa nhị phân sang văn bản theo RFC 4648, đối chiếu cơ chế đóng gói bitwise, ma trận đệm (padding), tính công thái học của bảng chữ cái và quá trình thực thi trực tiếp trên trình duyệt giữa Base32 và Base64.

PetexSpace