Nitpick Floating Point Type Family

Nitpick natively supports standard IEEE 754 floating point numbers, extended precision floats, and deterministic fixed-point variants.

1. Floating Point (flt)

Literals: Suffix with the type name (e.g., 3.14f32, 2.71828f64).

Usage Example:

flt32:pi = 3.14159f32;
flt64:high_precision_val = -10.5f64;

2. Fixed Point (fixN)

To guarantee absolute determinism across different architectures (which often have subtly different hardware FPUs), Nitpick provides a family of native fixed-point types.

Type Family

Type Total Bits Integer Bits Fractional Bits Q-Format IR Representation
fix32 32 16 16 Q16.16 LLVM i32
fix64 64 32 32 Q32.32 LLVM i64
fix128 128 64 64 Q64.64 %struct.fix128 { [2 x i64] }
fix256 256 128 128 Q128.128 %struct.fix256 { [4 x i64] }

Design Rationale

Literals

Suffix with the type name:

fix32:speed = 42.5fix32;
fix64:position = 1000.123fix64;
fix128:precise = 3.14159265358979fix128;
fix256:velocity = 299792458.0fix256;

Arithmetic

All arithmetic is performed in pure integer math for determinism. Overflow produces the ERR sentinel.

fix64:a = fix64_from_int(10);
fix64:b = fix64_from_int(3);
fix64:sum = a + b;      // 13
fix64:prod = a * b;     // 30
fix64:quot = a / b;     // 3 (with fractional precision)

ERR Sentinel

Each fixed-point type has a dedicated ERR sentinel value (the minimum signed value for that width). ERR propagates stickily: any operation with an ERR operand returns ERR.

Type ERR Sentinel
fix32 0x80000000 (INT32_MIN)
fix64 0x8000000000000000 (INT64_MIN)
fix128 {0, 0x8000000000000000}
fix256 {0, 0, 0, 0x8000000000000000}

Test for ERR with the ok() builtin:

fix64:result = a / fix64_from_int(0);  // ERR (division by zero)
if (ok(result) != 0) {
    // result is valid
}

Intrinsics

All fixed-point types support the same intrinsic set, prefixed with the type name:

Category Intrinsics
Conversion fixN_from_int(v), fixN_to_int(v), fixN_from_float(v), fixN_to_float(v)
Constants fixN_ERR(), fixN_MAX(), fixN_EPSILON()
Rounding fixN_trunc(v), fixN_floor(v), fixN_ceil(v), fixN_round(v)
Unary fixN_abs(v), fixN_neg(v)
Math fixN_sqrt(v), fixN_exp(v), fixN_log(v), fixN_pow(a, b)
Trig fixN_sin(v), fixN_cos(v)

Where N is 32, 64, 128, or 256.

Cross-Width Conversions

Use @cast to convert between fixed-point widths:

fix32:narrow = fix32_from_int(42);
fix64:wide = @cast<fix64>(narrow);   // widening: lossless
fix32:back = @cast<fix32>(wide);     // narrowing: may produce ERR on overflow

3. Dimensional Analysis

The compiler supports attaching SI units to any fixN type at compile-time to prevent unit mismatch errors (e.g., adding meters to seconds). * fix64<Joules> * fix64<Meters> * fix128<Seconds> * fix256<Newtons>

Usage Example:

fix64<Meters>:distance = 100.0fix64;
fix64<Seconds>:time = 9.58fix64;
// Compile error if you tried to assign `distance` to `time`!

fix64<Meters>:speed = distance / time;  // fix64<Meters/Seconds>