Skip to main content

Fix128

Struct Fix128 

Source
#[repr(C)]
pub struct Fix128 { pub hi: i64, pub lo: u64, }
Expand description

128-bit fixed-point number (64 integer bits, 64 fractional bits)

Internal representation: value = raw / 2^64

This provides:

  • Range: ±9.2 × 10^18
  • Precision: ~5.4 × 10^-20
  • Bit-exact arithmetic across all platforms

Fields§

§hi: i64

Raw 128-bit value (stored as two i64s for portability) Interpretation: (hi << 64) | lo as a signed 128-bit integer The decimal point is between hi and lo

§lo: u64

Fractional part (64-bit unsigned)

Implementations§

Source§

impl Fix128

Source

pub const ZERO: Self

Zero constant

Source

pub const ONE: Self

One constant (1.0)

Source

pub const NEG_ONE: Self

Negative one (-1.0)

Source

pub const PI: Self

Pi (π) - precomputed to full precision π ≈ 3.14159265358979323846…

Source

pub const HALF_PI: Self

Half Pi (π/2)

Source

pub const TWO_PI: Self

Two Pi (2π)

Source

pub const fn from_int(n: i64) -> Self

Create from integer

Source

pub const fn from_raw(hi: i64, lo: u64) -> Self

Create from raw parts (hi = integer, lo = fraction)

Source

pub fn from_f64(f: f64) -> Self

Create from f64 (for initialization only, not deterministic!)

Source

pub fn to_f64(self) -> f64

Convert to f64 (for debugging only, not deterministic!)

Source

pub fn from_f32(f: f32) -> Self

Create from f32 (for SDF bridge, not deterministic!)

Source

pub fn to_f32(self) -> f32

Convert to f32 (for SDF bridge, not deterministic!)

Source

pub fn from_ratio(num: i64, denom: i64) -> Self

Create from fraction (numerator / denominator)

Source

pub fn abs(self) -> Self

Absolute value

§Claims
  • |x| for every value except the most negative one
  • saturating: |-2^63| = 2^63 is not representable, so abs of the most negative value (hi == i64::MIN, lo == 0) is the largest representable value instead of wrapping back to itself; the result is never negative (AUD-A-S1W5-028, AUD-A-S3W3-010, AUD-A-S5W2-017)
Source

pub const fn is_negative(self) -> bool

Check if negative

Source

pub const fn is_zero(self) -> bool

Check if zero

Source

pub const fn floor(self) -> Self

Floor (round toward negative infinity)

Source

pub const fn ceil(self) -> Self

Ceiling (round toward positive infinity)

§Claims
  • an integer value is returned unchanged; otherwise the next integer up
  • saturating: above i64::MAX (integer part i64::MAX with a fraction) the next integer is not representable, and the result is the largest representable value, which is still >= self (AUD-A-S1W5-028)
Source

pub fn sqrt(self) -> Self

Square root, exact floor: floor(sqrt(self)) in I64F64.

Restoring digit-recurrence (one result bit per step) on the 192-bit radicand self << 64, 96 fixed steps, so the result is the largest r with r * r <= self — bit-identical on every platform and to the pre-1.2.0 Newton-Raphson implementation (verified over 20 000 samples plus edge values in tests::sqrt_matches_newton_reference).

Before 1.2.0 this ran 64 Newton iterations, each calling the 64-step long division, ≈ 4 096 inner steps per call (≈ 10 µs); 3-5 iterations had already converged. The recurrence needs 96 shift/compare/subtract steps (≈ 24× faster, see benches/physics_bench.rs::fix128_sqrt).

Negative input returns ZERO (deterministic, no NaN).

Deterministic: fixed number of iterations, integer-only.

Source

pub const fn half(self) -> Self

Divide by 2 (bit shift, exact)

Source

pub const fn shr_bits(self, i: u32) -> Self

Arithmetic right shift of the full 128-bit value by i bits (exact self / 2^i, rounding toward negative infinity).

The single source of truth for the CORDIC x >> i / y >> i micro-rotations (cordic_sin_cos and cordic_atan). Before 1.1.1 cordic_atan had its own copy that dropped the bits carried from hi into lo, so ONE >> 1 evaluated to 0 instead of 0.5 and every atan / atan2 result was off by up to ~0.17 rad.

Source

pub const fn double(self) -> Self

Multiply by 2 (bit shift, exact)

Source

pub fn sin(self) -> Self

Sine using CORDIC algorithm (deterministic)

Input should be in range [-π, π] for best precision

Source

pub fn cos(self) -> Self

Cosine using CORDIC algorithm (deterministic)

Input should be in range [-π, π] for best precision

Source

pub fn sin_cos(self) -> (Self, Self)

Simultaneous sin and cos (more efficient)

Source

pub fn atan(self) -> Self

Arctangent using CORDIC (deterministic)

Source

pub fn atan2(y: Self, x: Self) -> Self

Arctangent2 (deterministic)

Source

pub unsafe fn add_simd(self, rhs: Self) -> Self

Addition through the simd feature’s API surface — scalar-equivalent.

Bit-identical to self + rhs. SSE2’s _mm_add_epi64 adds the two 64-bit lanes independently and cannot carry from lo into hi, so a Fix128 add has no profitable SSE2 form; LLVM already emits add/adc for the scalar path. Before 1.2.0 this function loaded both operands into __m128i registers and then discarded them (let _ = (a, b)), i.e. it was scalar with dead intrinsics.

§Safety

No preconditions; kept unsafe + #[target_feature(enable = "sse2")] for signature compatibility with existing callers.

Source

pub unsafe fn sub_simd(self, rhs: Self) -> Self

Subtraction through the simd feature’s API surface — scalar-equivalent (see Self::add_simd).

§Safety

No preconditions; kept unsafe + #[target_feature(enable = "sse2")] for signature compatibility with existing callers.

Source§

impl Fix128

Source

pub fn checked_mul(self, rhs: Self) -> Option<Self>

Mul と同じ積を計算し、範囲外なら None を返す

§なぜ必要か (WM-01 / doctrine B-12)

Mul は全段 wrapping_* なので 範囲外の積が silent に巻き戻る 実測 (2026-09-30): 2⁴⁰ × 2⁴⁰ は exact 1.21e24 だが、Q64.64 では hh = 2⁸⁰ で 2⁸⁰ mod 2⁶⁴ = 0 なので hi が厳密に 0 になる

⇒ position += velocity * dt が 0 加算になり、update_velocities が velocity = (position − prev_position) * inv_dt で速度も 0 に上書きする ⇒ 「原点で完全に静止した自己整合な状態」 に落ちる ⚠️ 静止は物理的に妥当なのでどの不変条件でも red にならないため、 「値が大きい / 値が飛んだ」を見る検出器では原理的に捕まえられない

⚠️ Mul 自体の挙動は変えない — 既存の決定論 golden と bit 互換を 保つため、検出が要る経路だけが本 method を使う (PhysicsWorld::step の積分と速度導出、PhysicsWorld::overflow_detected)

Source

pub fn checked_add(self, rhs: Self) -> Option<Self>

Add と同じ和を計算し、範囲外 (|a + b| ≥ 2⁶³) なら None を返す

Add は wrap するので、範囲の検査が要る経路だけが本 method を使う (Add 自体の挙動は変えない)

Source

pub fn powf_pos(self, exponent: Self) -> Self

self^exponent for self > 0 and exponent ≥ 0 (real exponent).

Integer part of the exponent by repeated multiplication, fractional part by its binary expansion base^f = Π base^(1/2^k) over the first 24 bits using successive Fix128::sqrt calls — pure integer arithmetic, bit-identical on every platform, relative error ≲ |ln base| · 2⁻²⁴ plus sqrt truncation (measured ≤ 1e-6 relative for results ≥ 1e-9 over base ∈ [1e-3, 1e3], exponent ∈ [0, 8], math::tests::powf_pos_matches_f64_reference; smaller results hit the 2⁻⁶⁴ absolute resolution). self ≤ 0 or a negative exponent returns ZERO (no NaN; callers that need those cases handle them explicitly).

§Integer part of the exponent

Exponents whose integer part is at most 64 use left-to-right repeated multiplication; above 64 the integer part uses exponentiation by squaring. The seam exists to keep results bit-identical to 1.5.0 and earlier wherever those versions were already correct: fixed-point multiplication truncates and is therefore not associative, so the two orders differ in the low bits for a base that is not exactly representable. Before 1.6.0 the integer part was silently capped at 64 (1.01^100 returned 1.01^64 = 1.89 rather than 2.705), so only the n ≤ 64 range has bits worth preserving; above it the result was wrong and the faster O(log n) order is used instead of an O(n) loop.

Source

pub fn exp(self) -> Self

Deterministic e^self via 2^(x·log₂e) (Fix128::powf_pos with base 2; negative arguments as 1 / e^|x|). Relative error ≲ 1e-6 for |x| ≤ 40 (math::tests::exp_matches_f64_reference); x < −44 is below the 2⁻⁶⁴ resolution and returns ZERO, and from x ≥ 63 · ln 2 (≈ 43.668, where e^x reaches 2⁶³) it saturates at the representable maximum instead of wrapping.

Source

pub fn ln(self) -> Self

Deterministic natural log via range reduction to [1, 2) + atanh series (ln(m) = 2·atanh((m−1)/(m+1)), 16 terms). Non-positive input returns ZERO (no panic, no NaN representation in Fix128). Moved here from a private turbulence.rs helper of the same algorithm (canonical source: one ln, not one per caller module).

Source

pub fn checked_div(self, rhs: Self) -> Option<Self>

Checked division: None when rhs == 0, otherwise Some(self / rhs).

The Div operator returns ZERO for a zero divisor (deterministic, no panic, no NaN) which is convenient in solver hot paths but hides bugs in caller code that never expected a zero — use this in validation and setup paths. Bit-identical to / for every non-zero divisor.

Trait Implementations§

Source§

impl Add for Fix128

Source§

type Output = Fix128

The resulting type after applying the + operator.
Source§

fn add(self, rhs: Self) -> Self

Performs the + operation. Read more
Source§

impl Clone for Fix128

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Fix128

Source§

impl Debug for Fix128

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Fix128

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Display for Fix128

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Div for Fix128

Fixed-point division, truncating toward zero on the raw bit pattern.

⚠️ Not the same direction as Mul, which floors toward −∞. This operator takes the magnitudes apart, divides them and reapplies the sign, so the result is symmetric about zero: (-a) / b == -(a / b) exactly. Mul is not — (-a) * b is one raw unit below -(a * b) whenever the product has a remainder. Measured on a = 1/3, b = 1/7.

The difference matters wherever the direction of the bias decides an outcome rather than its size: a contraction ratio read as > 1 or = 1, a residual that either reaches an exact fixed point or keeps drifting, a quadrature weight that is one unit light on one side of zero and not the other. Division is the safer of the two there, because the sign cannot change which way the error leans.

§Division by zero

Returns ZERO (documented contract since 1.2.0; the behaviour predates it). This keeps the solver deterministic and panic-free — a zero inverse mass, a degenerate normal or a zero dt never poisons a lockstep peer with NaN — but it also means a caller bug is silently masked. Use Fix128::checked_div where a zero divisor is an error. A Result-based operator is planned for 2.0 (PhysicsError is not #[non_exhaustive], so a new variant cannot be added in 1.x).

Source§

type Output = Fix128

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Self) -> Self

Performs the / operation. Read more
Source§

impl Div<Fix128> for Vec3Fix

Source§

type Output = Vec3Fix

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Fix128) -> Self

Performs the / operation. Read more
Source§

impl Div<Fix128> for Vec2Fix

Source§

type Output = Vec2Fix

The resulting type after applying the / operator.
Source§

fn div(self, rhs: Fix128) -> Self

Performs the / operation. Read more
Source§

impl Eq for Fix128

Source§

impl From<i32> for Fix128

Source§

fn from(n: i32) -> Self

Converts to this type from the input type.
Source§

impl From<i64> for Fix128

Source§

fn from(n: i64) -> Self

Converts to this type from the input type.
Source§

impl Hash for Fix128

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Mul for Fix128

Fixed-point multiplication: the 256-bit product of the two Q64.64 values, keeping bits [192:64].

§Overflow and rounding

  • Wrapping: if the mathematical product does not fit the ±2^63 integer range the high bits are discarded — the result wraps modulo 2^128 of the raw two’s-complement representation. There is no saturation and no panic, in debug builds too (every intermediate uses wrapping_*). Callers that need range safety must check operands beforehand; the engine’s own hot paths keep magnitudes far below the limit.
  • Truncation: fractional bits below 2^-64 are dropped, which is a floor toward −∞ on the two’s-complement bit pattern (e.g. -2^-64 * 0.5 == -2^-64, not 0).

Both properties are part of the determinism contract: the same operands yield the same bits on every platform.

Source§

type Output = Fix128

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Self) -> Self

Performs the * operation. Read more
Source§

impl Mul<Fix128> for Vec3Fix

Source§

type Output = Vec3Fix

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Fix128) -> Self

Performs the * operation. Read more
Source§

impl Mul<Fix128> for Vec2Fix

Source§

type Output = Vec2Fix

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Fix128) -> Self

Performs the * operation. Read more
Source§

impl Neg for Fix128

Source§

type Output = Fix128

The resulting type after applying the - operator.
Source§

fn neg(self) -> Self

Performs the unary - operation. Read more
Source§

impl Ord for Fix128

Source§

fn cmp(&self, other: &Self) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 (const: unstable) · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 (const: unstable) · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 (const: unstable) · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

fn clamp_to<R>(self, range: R) -> Self
where Self: Sized, R: ClampBounds<Self>,

🔬This is a nightly-only experimental API. (clamp_to)
Restrict a value to a certain range. Read more
Source§

impl PartialEq for Fix128

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialOrd for Fix128

Source§

fn partial_cmp(&self, other: &Self) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 (const: unstable) · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 (const: unstable) · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 (const: unstable) · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 (const: unstable) · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl StructuralPartialEq for Fix128

Source§

impl Sub for Fix128

Source§

type Output = Fix128

The resulting type after applying the - operator.
Source§

fn sub(self, rhs: Self) -> Self

Performs the - operation. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.