Skip to content

RedScript v2.5.0: Double Precision, N-Order Bezier, and a Complete Stdlib Overhaul

Published: 2026-03-18
Version: v2.5.0
Tests: 1277 → 1485 (+208) | Commits today: ~20


Today was one of the most intense development days in RedScript's history. v2.5.0 introduces true double-precision floating point, a type system redesign, and a batch of new standard library modules. This post covers the technical details — especially the dark magic behind "implementing IEEE 754 inside Minecraft."

1. Type System Redesign

floatfixed Rename

The old float type was never actually IEEE 754 — it was a fixed-point number backed by scoreboard integers, storing values multiplied by 10000. In other words:

rs
let x: fixed = 3.14   // stored internally as scoreboard integer 31400

We renamed it from float to fixed to accurately reflect what it is.

New double Type

double is true IEEE 754 double-precision, stored in NBT:

rs
let d: double = 3.141592653589793   // stored in rs:d NBT storage
  • Storage: rs:d NBT storage (storage rs:d)
  • Precision: Full IEEE 754 double, ~15-16 significant digits
  • Compiler intrinsics: a + b on two doubles automatically lowers to double_add in the MIR lowering pass

No More Implicit Type Conversions

v2.5.0 eliminates all implicit type conversions. All cross-type operations require an explicit as cast:

rs
let f: fixed = 1.5
let d: double = f as double   // ✅ explicit cast
let x: double = f             // ❌ compile error

[FloatArithmetic] Lint Warning

Multiplication and division on fixed types now triggers a new lint warning:

warning[FloatArithmetic]: fixed-point multiplication may lose precision
  --> mypack/src/main.rs:12:5
   |
12 |     let result = a * b
   |                  ^^^^^
   = note: consider using `double` for higher precision arithmetic

2. Double Arithmetic in Minecraft (The Tricks)

This is the most interesting part of this release — how to implement IEEE 754 double operations inside Minecraft's command system, which has no native floating-point instructions.

double_add / double_sub: The Entity Position Trick

Key insight: The loot spawn command's coordinate arguments have no numeric limits, and Minecraft entity Pos fields are natively stored as IEEE 754 doubles.

The approach:

  1. Teleport a marker entity to coordinate x = a using /tp
  2. Move it relatively by +b (i.e., execute ... tp @e[...] ~b ~ ~)
  3. Read Pos[0] → result is a + b with full IEEE 754 double precision
mcfunction
# double_add(a, b) -> a + b
data modify storage rs:d in0 set from storage rs:d a
data modify storage rs:d in1 set from storage rs:d b
# ... teleport marker to a, then +b, read Pos[0]
data get entity @e[tag=rs_marker,limit=1] Pos[0]
data modify storage rs:d result set from entity @e[tag=rs_marker,limit=1] Pos[0]

Subtraction works the same way — just negate b.

double_mul_fixed: Execute Store + Function Macros

Multiplying a double by a fixed-point number, using MC function macros to inject the scale parameter dynamically:

mcfunction
$execute store result storage rs:d out double $(scale) run data get storage rs:d input 1

$(scale) is injected at runtime via the MC function macro mechanism, equivalent to input * scale. This allows reusing the same function logic with different scale factors.

double_div: The Display Entity SVD Trick

Key insight: Display Entity transformation matrices are internally SVD-decomposed, normalizing the matrix so its last element equals 1.

The approach:

  1. Construct a transformation matrix where matrix[3][3] = b and matrix[0][0] = a
  2. Read the normalized matrix → result is a / b

This is currently the only known way to implement arbitrary double division using vanilla Minecraft commands.

Compiler Intrinsics

The compiler's MIR lowering pass automatically recognizes double operations and inserts the corresponding intrinsic calls:

rs
// Code written by user
let c: double = a + b   // a, b are both double

// Compiler lowers to
let c = __intrinsic_double_add(a, b)
// Ultimately generates a call to rs:internal/double_add mcfunction

Users don't need to care about the underlying implementation — just use + - * / directly.


3. New Stdlib Modules

parabola.mcrs — Ballistic Trajectory

Computes projectile motion trajectories: given initial velocity and angle, calculate landing position, or solve for the required launch angle. Useful for arrows, TNT cannons, and similar mechanics.

quaternion.mcrs — Display Entity Rotation

Quaternion operations, primarily for smooth rotation animations on Display Entities.

This release fixes a tricky normalization bug: during SLERP interpolation, when the angle between two quaternions approaches 180°, the normalization step produces NaN, causing Display Entities to suddenly disappear. The fix checks for the antipodal case before interpolating and selects an alternate rotation axis:

rs
// SLERP with antipodal fix
fn slerp(q1: Quaternion, q2: Quaternion, t: fixed) -> Quaternion {
    let dot = q1.dot(q2)
    // If dot product is negative, flip q2 to take the short arc
    let q2 = if dot < 0 { q2.negate() } else { q2 }
    // ...
}

bezier_quartic.mcrs + bezier_n.mcrs — N-Order Bezier

  • bezier_quartic: Quartic Bezier curve, hard-coded unrolled for maximum performance
  • bezier_n: Arbitrary order, implemented recursively using the De Casteljau algorithm

Implementing De Casteljau in Minecraft is quite interesting — recursion is simulated via recursive function calls, with control points stored in an NBT array:

rs
// N-order De Casteljau
fn de_casteljau(points: [double], t: fixed, n: int) -> double {
    if n == 1 { return points[0] }
    // Recursive degree reduction
    let reduced = lerp_adjacent(points, t, n)
    return de_casteljau(reduced, t, n - 1)
}

bigint_mul / bigint_sq

Big integer multiplication and squaring, using scoreboard integers to simulate multi-precision arithmetic. Primarily used for cryptography demos and scenarios requiring extreme numerical precision.


4. High-Precision Math

ln_hp: High-Precision Natural Logarithm

Starting from ln_5term (5-term Taylor expansion), then refining with Newton iteration to achieve ~8-9 significant digits:

ln_hp(x):
  y₀ = ln_5term(x)           // initial estimate (5-term expansion)
  y₁ = y₀ + (x - e^y₀) / x  // Newton step: y ← y + (x - e^y)/x
  y₂ = y₁ + (x - e^y₁) / x  // one more iteration

Under the fixed type (×10000 precision), two Newton steps typically achieve 8+ digits of accuracy.

Statistical Distributions

Three new random distribution generators:

DistributionAlgorithm
GammaSum of exponentials (integer shape parameter)
PoissonKnuth algorithm (product of uniform randoms)
Negative BinomialGamma + Poisson compound

The Knuth Poisson algorithm is particularly well-suited for Minecraft since it only needs uniform random numbers (generated via the random value command):

rs
fn poisson(lambda: fixed) -> int {
    let L = exp(-lambda)
    let k = 0
    let p: fixed = 1.0
    loop {
        k += 1
        p *= random_uniform()   // uniform [0, 1)
        if p <= L { break }
    }
    return k - 1
}

5. Numbers

Metricv2.4.xv2.5.0Delta
Test cases12771485+208
Commits today~20
New stdlib modules7

The 208 new test cases cover all new double operation intrinsics, high-precision math functions, and validation of statistical distributions (mean and variance convergence checks).


Summary

v2.5.0 is a milestone release. The addition of double gives RedScript genuine high-precision floating-point capability for the first time — even though the underlying implementation requires entity coordinates, Display Entity transformation matrices, and other Minecraft mechanics to "simulate" IEEE 754. That's exactly the fun of systems programming in a constrained environment.

Next steps: improve type inference for double/fixed interoperability, and add more documentation and examples to the stdlib.


Author: bkmashiro | RedScript maintainer

Released under the MIT License.