Primitive Types

Bool

| Type   | Size (bytes) | Alignment (bytes) | Range  |
|--------|--------------|-------------------|--------|
| bool  | 1            | 1                 | 0 or 1 |
| b8    | 1            | 1                 | 0 or 1 |
| b16   | 2            | 2                 | 0 or 1 |
| b32   | 4            | 4                 | 0 or 1 |
| b64   | 8            | 8                 | 0 or 1 |

[ all bits = value ]
00000000 β†’ false
00000001 β†’ true
0 = false
anything else = treated as true (language-dependent)

Integers

  • int  and uint  here are implementation-defined, with not fixed-width.

| Type   | Size (bytes)               | Alignment (bytes)          | Range                                                                                        |
|--------|----------------------------|----------------------------|----------------------------------------------------------------------------------------------|
| u8   | 1                          | 1                          | [0 β†’ 255]                                                                                    |
| u16   | 2                          | 2                          | [0 β†’ 65,535]                                                                                 |
| u32   | 4                          | 4                          | [0 β†’ 4,294,967,295]                                                                          |
| u64   | 8                          | 8                          | [0 β†’ 18,446,744,073,709,551,615]                                                             |
| uint  | 4 (32-bits) or 8 (64-bits) | 4 (32-bits) or 8 (64-bits) | [0 β†’ 4,294,967,295] or [0 β†’ 18,446,744,073,709,551,615]                                      |
| i8   | 1                          | 1                          | [-128 β†’ 127]                                                                                 |
| i16   | 2                          | 2                          | [-32,768 β†’ 32,767]                                                                           |
| i32   | 4                          | 4                          | [-2,147,483,648 β†’ 2,147,483,647]                                                             |
| i64   | 8                          | 8                          | [-2^63 β†’ (2^63) - 1] [-9,223,372,036,854,775,808 β†’ 9,223,372,036,854,775,807]                |
| int   | 4 (32-bits) or 8 (64-bits) | 4 (32-bits) or 8 (64-bits) | [-2,147,483,648 β†’ 2,147,483,647] or [-9,223,372,036,854,775,808 β†’ 9,223,372,036,854,775,807] |

Unsigned
[ all bits = value ]
Sign (MSB - most significant bit)
  • All signed integer types ( i8 , i16 , i32 , i64 ) use two’s complement with the same layout rule.

  • Two’s complement is just a way to encode negative numbers so that binary addition still works normally.

  • Instead of having a separate β€œsign + magnitude”, the number is stored in a way where:

    • Positive numbers look like normal binary

    • Negative numbers are encoded so that adding works without special rules

  • This works because

    x + (-x) = 0   (mod 2^N)
    
    00000101   (+5)
    + 11111011   (-5)
    -----------
    00000000   (carry discarded)
    
  • For any signed integer with N bits:

    bit index:  N-1 ............ 0
                β†“
            [ MSB | remaining bits ]
    
  • How to get the negative number :

    1. Write +x in binary

    2. Invert all bits

    3. Add 1

  • As an INDIRECT consequence, the MSB (most significant bit) acts as the sign indicator :

    • If MSB = 1 (negative) β†’ fill new bits with 1

    • If MSB = 0 (positive) β†’ fill new bits with 0

  • Examples :

    00000101 β†’ +5
    
    invert: 11111010
    +1:     11111011
    
    11111011 β†’ -5
    

Pointers

  • "an address value with a specific type".

  • At the memory level, it's just an uint  / uintptr :

| Type   | Size (bytes)               | Alignment (bytes)          | Range                                                   |
|--------|----------------------------|----------------------------|---------------------------------------------------------|
| uint  | 4 (32-bits) or 8 (64-bits) | 4 (32-bits) or 8 (64-bits) | [0 β†’ 4,294,967,295] or [0 β†’ 18,446,744,073,709,551,615] |

Floats (IEEE-754 floating-point)

| Type  | Size (bytes) | Alignment (bytes) | Range                               |
|-------|--------------|-------------------|-------------------------------------|
| f16  | 2            | 2                 | ~Β±6.55Γ—10⁴ (β‰ˆ3–4 decimal digits)    |
| f32  | 4            | 4                 | ~Β±3.4Γ—10³⁸ (β‰ˆ7 decimal digits)      |
| f64  | 8            | 8                 | ~Β±1.8Γ—10³⁰⁸ (β‰ˆ15–16 decimal digits) |

Final value

  • value = (-1)^sign Γ— (1 + mantissa) Γ— 2^(exponent - bias)

Bias

  • Bias is a fixed offset added to the real exponent so it can be stored as an unsigned value.

  • Exponent bits are stored without a sign bit. Instead of storing negative exponents directly, IEEE 754 does:

    stored_exponent = real_exponent + bias
    
  • So:

    • Negative exponents become small positive numbers

    • Positive exponents become larger numbers

    • Everything fits in an unsigned field

Special values

  • Plus Infinite :

    • +∞ > all finite numbers

    • ∞ + 1 = ∞

    • ∞ * 2 = ∞

    • ∞ - ∞ = NaN
      | sign | exponent | mantissa |
      |------|----------|----------|
      | 0    | 11111111 | 000...0  |

    • How to get it:

      • 1.0f / 0.0f β†’ +∞

      • huge_value * huge_value β†’ +∞ // via overflow

  • Minus Infinite :

    • -∞ < all finite numbers
      | sign | exponent | mantissa |
      |------|----------|----------|
      | 1    | 11111111 | 000...0  |

    • How to get it:

      • -1.0f / 0.0f β†’ -∞

  • NaN :
    | sign | exponent | mantissa |
    |------|----------|----------|
    | x    | 11111111 | non-zero |

    • There are many NaN bit patterns because mantissa can vary.

    • How to get it:

      0.0 / 0.0
      ∞ - ∞
      sqrt(-1.0)
      
    • Behavior:

      NaN == NaN β†’ false
      NaN != NaN β†’ true
      NaN < any  β†’ false
      NaN > any  β†’ false
      NaN + 5 = NaN
      NaN * 10 = NaN
      
  • Subnormals (Denormals) :

    • They represent numbers very close to zero, smaller than the smallest β€œnormal” float.
      | sign | exponent | mantissa |
      |------|----------|----------|
      | x    | 00000000 | non-zero |

    • Normal numbers:

      • value = 1.mantissa Γ— 2^(exp - bias)

    • Subnormals:

      • value = 0.mantissa Γ— 2^(1 - bias)

    • No implicit leading 1

    • Reduced precision

    • Without subnormals:

      • smallest normal β‰ˆ 1.175e-38 (f32)

      • next value β†’ 0

    • With subnormals:

      • smooth transition to 0

      • (no sudden underflow gap)

    • Subnormals are slow on many CPUs:

      • Can be 10–100Γ— slower

      • Many systems enable:

      • FTZ (Flush To Zero)

      • DAZ (Denormals Are Zero)

  • Zero :

    +0.0 β‰  -0.0 (bitwise)
    but
    +0.0 == -0.0 (comparison)
    
    1 / +0.0 = +∞
    1 / -0.0 = -∞
    

f16

  • half precision, less universally supported in CPUs but common in GPUs and some SIMD extensions.

[ sign | exponent (5 bits) (bias = 15) | mantissa (10 bits) ]

f32

[ sign | exponent (8 bits) (bias = 127) | mantissa (23 bits) ]
  • Example :

    • f32 = 1.0

      0 01111111 00000000000000000000000
      [ 00 ][ 00 ][ 80 ][ 3F ]
      

f64

[ sign | exponent (11 bits) (bias = 1023) | mantissa (52 bits) ]

SIMD

  • __m128  (128-bit SIMD)

  • __m256  (256-bit SIMD)

  • __m512  (512-bit SIMD)