spirix 0.1.0

Two's complement floating-point arithmetic library
Documentation
#![no_std]
// src/ │ ├── core/                    Core types and traits │   ├── circle.rs            Circle<F, E> complex number type │   ├── circle_aliases.rs    Circle type aliases (F3E3-F7E7) │   ├── integer.rs           Public Integer and internal numeric traits │   ├── mod.rs               Module exports │   ├── scalar.rs            Scalar<F, E> real number type │   ├── scalar_aliases.rs    Scalar type aliases (F3E3-F7E7) │   └── undefined.rs         Undefined value prefixes and patterns │ ├── conversions/             Type conversion implementations │   ├── circle_circle.rs     Circle conversion traits │   ├── circle_rust.rs       Circle to primitive conversions │   ├── circle_scalar.rs     Circle to Scalar conversions │   ├── mod.rs               Conversion exports │   ├── rust_circle.rs       Primitive to Circle conversions │   ├── rust_scalar.rs       Primitive to Scalar conversions │   ├── scalar_circle.rs     Scalar to Circle conversions │   ├── scalar_rust.rs       Scalar to primitive conversions │   └── scalar_scalar.rs     Scalar to Scalar conversions │ ├── constants/               Constant values and implementations │   ├── circle.rs            Circle constants (i, π, roots) │   ├── exponent.rs          Exponent component constants │   ├── fraction.rs          Fraction component constants │   ├── mod.rs               Constants exports │   └── scalar.rs            Scalar constants (π, e, roots) │ ├── implementations/         Mathematical operations │   ├── addition/            Addition operations │   │   ├── circle_circle.rs Circle + Circle │   │   ├── circle_scalar.rs Circle + Scalar │   │   ├── mod.rs           Addition exports │   │   ├── scalar_circle.rs Scalar + Circle │   │   └── scalar_scalar.rs Scalar + Scalar │   │ │   ├── subtraction/         Subtraction operations │   │   ├── circle_circle.rs Circle - Circle │   │   ├── circle_scalar.rs Circle - Scalar │   │   ├── mod.rs           Subtraction exports │   │   ├── scalar_circle.rs Scalar - Circle │   │   └── scalar_scalar.rs Scalar - Scalar │   │ │   ├── multiplication/      Multiplication operations │   │   ├── circle_circle.rs Circle * Circle │   │   ├── circle_scalar.rs Circle * Scalar │   │   ├── mod.rs           Multiplication exports │   │   ├── scalar_circle.rs Scalar * Circle │   │   └── scalar_scalar.rs Scalar * Scalar │   │ │   ├── division/            Division operations │   │   ├── circle_circle.rs Circle / Circle │   │   ├── circle_scalar.rs Circle / Scalar │   │   ├── mod.rs           Division exports │   │   ├── scalar_circle.rs Scalar / Circle │   │   └── scalar_scalar.rs Scalar / Scalar │   │ │   ├── modular/             Modular arithmetic operations │   │   ├── circle_circle.rs Circle % Circle │   │   ├── circle_scalar.rs Circle % Scalar │   │   ├── mod.rs           Modular operations exports │   │   ├── scalar_circle.rs Scalar % Circle │   │   └── scalar_scalar.rs Scalar % Scalar │   │ │   ├── exponents/           Power and exponent operations │   │   ├── circle_circle.rs Circle^Circle powers │   │   ├── circle.rs        Circle exponent operations │   │   ├── circle_scalar.rs Circle^Scalar powers │   │   ├── mod.rs           Exponent operations exports │   │   ├── scalar_circle.rs Scalar^Circle powers │   │   ├── scalar.rs        Scalar exponent operations │   │   └── scalar_scalar.rs Scalar^Scalar powers │   │ │   ├── trigonometry/        Trig functions │   │   ├── circle.rs        Circle trigonometry │   │   ├── mod.rs           Trigonometry exports │   │   └── scalar.rs        Scalar trigonometry │   │ │   ├── bitwise/             Aligned bitwise operations │   │   ├── circle.rs        Circle bitwise operations │   │   ├── mod.rs           Bitwise operations exports │   │   └── scalar.rs        Scalar bitwise operations │   │ │   ├── formatting/          Display implementations │   │   ├── circle.rs        Circle formatting │   │   ├── colours.rs       ANSI colour support │   │   ├── mod.rs           Formatting exports │   │   └── scalar.rs        Scalar formatting │   │ │   ├── basic_circle.rs      Core Circle operations │   ├── basic_scalar.rs      Core Scalar operations │   ├── comparison.rs        Ordering operations (<, >, ==) │   ├── mod.rs               Implementation exports │   └── random.rs            Random number generation │ ├── operators/               Type interaction traits │   ├── circle.rs            Circle-specific operations │   ├── circle_circle.rs     Circle-Circle operations │   ├── circle_rust.rs       Circle-to-primitive ops │   ├── circle_scalar.rs     Circle-Scalar operations │   ├── mod.rs               Operator exports │   ├── rust_circle.rs       Primitive-to-Circle ops │   ├── rust_scalar.rs       Primitive-to-Scalar ops │   ├── scalar.rs            Scalar-specific operations │   ├── scalar_circle.rs     Scalar-Circle operations │   ├── scalar_rust.rs       Scalar-to-primitive ops │   └── scalar_scalar.rs     Scalar-Scalar operations │ ├── tensor/                  Tensor operations and neural networks │   ├── autograd.rs          Automatic differentiation │   ├── mod.rs               Tensor exports │   ├── nn.rs                Neural network layers │   ├── ops.rs               Tensor operations │   ├── optim.rs             Optimization algorithms │   └── tensor.rs            Core Tensor type │ └── lib.rs                   Library root and exports (this file)

//! # Spirix
//!
//! A high-performance two's complement floating-point arithmetic library with customizable precision. Spirix allows you to choose both fraction and exponent sizes independently.
//!
//! ## Core Types
//!
//! Spirix provides two primary numeric types:
//!
//! - `Scalar<F, E>`: Real numbers with fraction `F` and exponent `E`
//! - `Circle<F, E>`: Complex numbers with fractions `F` and shared exponent `E`
//!
//! Both types use Rust's native signed integer types (i8, i16, i32, i64, i128) for their components, allowing you to select precision and range based on your application's needs.
//!
//! ### Type Aliases for Valid Configurations
//!
//! For convenience, Spirix provides type aliases for all valid Rust fraction and exponent combinations.
//!
//! Here are some examples:
//! ```rust
//! use spirix::{ScalarF5E3, ScalarF6E4, ScalarF5E5, ScalarF6E6, ScalarF7E3}; // Format: F#E# = 2^# fraction bits, 2^# exponent bits. // F5E3 = 32-bit fraction, 8-bit exponent  (similar to f32) // F6E4 = 64-bit fraction, 16-bit exponent (similar to f64) // F5E5 = 32-bit fraction, 32-bit exponent // F6E6 = 64-bit fraction, 64-bit exponent // F7E3 = 128-bit fraction, 8-bit exponent let _ = (ScalarF5E3::ONE, ScalarF6E4::ONE, ScalarF5E5::ONE, ScalarF6E6::ONE, ScalarF7E3::ONE);
//! ```
//!
//! Similarly for complex numbers with `CircleF5E3`, `CircleF6E4`, etc.
//!
//! ```rust
//! use spirix::{Power, Scalar, ScalarConstants}; // High-precision fraction with small range. Note: this uses Rust f64 as an intermediary! let _precise_near_one = Scalar::<i128, i8>::from(9.8696044010893586188344909998761511353_f64);
//!
//! // Small fraction with huge range. let _large_magnitude_low_precision = Scalar::<i8, i128>::from(6000_i16).pow(6000_i16);
//! ```
//!
//! ## Key Features and Benefits
//!
//! ### 0. Escaped Values
//!
//! When numbers grow too large or small to maintain magnitude, Spirix creates ambiguous "escaped" values that:
//!
//! - Preserve orientation information, even tho magnitude is unknown
//! - Can still participate in absolute operations, i.e. * and /
//! - Track whether they escaped toward Infinity (`exploded`) or toward Zero (`vanished`)
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF4E7};
//!
//! // Create a value so large it loses its magnitude. let huge = ScalarF4E7::MAX * 2_i8; assert!(huge.exploded()); assert!(huge.is_positive());
//!
//! // Absolute operations can continue with escaped values (* / .square() etc.) let still_exploded = huge * 3_i8; assert!(still_exploded.exploded());
//!
//! // Division works too! let neg_huge = huge / -5_i8; assert!(!neg_huge.is_undefined()); // Still defined! assert!(neg_huge.is_negative());
//! ```
//!
//! ### 1. Infinity and Zero Identities
//!
//! Spirix implements mathematical identities in accordance with Riemann sphere principles, with proper handling of Infinity and Zero:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! // Division by Zero produces Infinity. let infinity = ScalarF5E3::from(42_i8) / 0_i8; assert!(infinity.is_infinite());
//!
//! // Multiplicative identities with Infinity. let still_infinite = infinity * 7_i8;          // ∞ × n = ∞ (for any non-Zero n) assert!(still_infinite.is_infinite());
//!
//! // Infinity times Zero is undefined. let inf_times_zero = infinity * 0_i8;          // ∞ × 0 = undefined assert!(inf_times_zero.is_undefined());
//!
//! // Zero is the multiplicative absorber (except with Infinity). let still_zero = ScalarF5E3::ZERO * 42_i8;     // 0 × n = 0 assert!(still_zero.is_zero()); let exploded = ScalarF5E3::MAX.square(); let also_zero = 0_i8 * exploded; assert!(also_zero.is_zero()); // You can use the built-in Infinity constant. let undefined_multiply = ScalarF5E3::INFINITY * still_zero; assert!(undefined_multiply.is_undefined());
//!
//! // Reciprocal relationships. let zero = ScalarF5E3::ONE / infinity;         // 1/∞ = 0 assert!(zero.is_zero());
//!
//! // Division by Infinity. let also_zero = ScalarF5E3::from(42_i8) / infinity;  // n/∞ = 0 (for any non-infinite n) assert!(also_zero.is_zero());
//!
//! // Infinity divided by Infinity is undefined. let inf_div_inf = infinity / infinity;         // ∞/∞ = undefined assert!(inf_div_inf.is_undefined());
//!
//! // Addition and subtraction with Infinity return Infinity (Riemann sphere: ∞ absorbs). let inf_add = infinity + 5_i8;                 // ∞ + n = ∞ let inf_sub = infinity - infinity;             // ∞ − ∞ = ∞ assert!(inf_add.is_infinite() && inf_sub.is_infinite());
//!
//! // Infinity absorbs Zero under addition too. let inf_plus_zero = infinity + 0_i8;           // ∞ + 0 = ∞ assert!(inf_plus_zero.is_infinite());
//! ```
//!
//! Infinity in Spirix represents the directionless "point at Infinity" on the Riemann sphere, a singularity that conceptually unifies various approaches to Infinity and zero.
//!
//! ### 2. Vanished Values and Their Identities
//!
//! Spirix uniquely handles infinitesimal values that approach but never equal Zero:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! // Create a vanished value. let tiny = ScalarF5E3::MIN_POS / 42_i8; assert!(tiny.vanished() && tiny.is_positive());
//!
//! // Adding a vanished value to a normal value is like adding Zero. let normal = ScalarF5E3::from(42_i8); let sum = normal + tiny; assert!(sum == normal);
//!
//! // But adding two vanished values is undefined, as the magnitude is unknown. let tiny2 = ScalarF5E3::MIN_POS / 17_i8; let undef_sum = tiny + tiny2; assert!(undef_sum.is_undefined());
//!
//! // Division by a vanished value produces an exploded result. let huge = ScalarF5E3::ONE / tiny; assert!(huge.exploded());
//!
//! // Multiplying vanished returns vanished. let even_smaller = tiny * tiny2; assert!(even_smaller.vanished());
//! ```
//!
//! ### 3. Tracking Undefined States
//!
//! Spirix provides undefined states that preserve the initial cause:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! // Division by Zero produces Infinity. let infinity = ScalarF5E3::ONE / 0_i8; assert!(infinity.is_infinite());
//!
//! // But indeterminate forms are undefined. let undefined = ScalarF5E3::ZERO / 0_i8;       // 0/0 is undefined assert!(undefined.is_undefined());
//!
//! // Operations with undefined states propagate, preserving the original cause. let still_undefined = undefined + 42_i8; assert!(still_undefined.is_undefined());
//!
//! // Specific undefined cases are tracked. let undefined_inf_div_inf = infinity / infinity;    // ∞/∞ is undefined assert!(undefined_inf_div_inf.is_undefined());
//! ```
//!
//! ### 4. Continuous Mathematical Functions
//!
//! Spirix attempts to maintain mathematical continuity across the entire number space, even beyond exponent magnitude:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E5};
//!
//! // Vanished values retain phase information. let tiny_positive = ScalarF5E5::MIN_POS.square(); assert!(tiny_positive.vanished()); assert!(tiny_positive.is_positive()); let tiny_negative = tiny_positive * -2.4_f32; assert!(tiny_negative.is_negative()); // Multiplication and divison don't truncate to Zero. let supa_tiny = tiny_positive.square(); assert!(supa_tiny != 0_i8);
//!
//! // Trigonometric functions work with vanished values. let sin_tiny = tiny_positive.sin(); assert!(sin_tiny.vanished() && sin_tiny.is_positive());
//! ```
//!
//! ### 5. Predictable Comparisons
//!
//! Comparing values is intuitive and follows mathematical principles:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! let pos_normal = ScalarF5E3::from(42_i8); let neg_normal = ScalarF5E3::from(-42_i8); let pos_exploded = ScalarF5E3::MAX * 2_i8; let neg_exploded = ScalarF5E3::MIN * 2_i8; let pos_vanished = ScalarF5E3::MIN_POS / 2_i8; let neg_vanished = pos_vanished * -1_i8; let infinity = ScalarF5E3::ONE / 0_i8;
//!
//! // Escaped and Zero values maintain ordering. assert!(pos_exploded > pos_normal); assert!(pos_normal > pos_vanished); assert!(pos_vanished > 0_i8); assert!(neg_exploded < neg_normal); assert!(neg_normal < neg_vanished); assert!(neg_vanished < 0_i8);
//!
//! // Infinity is not comparable to anything. assert!(!(infinity > pos_normal)); assert!(!(infinity < pos_normal));
//!
//! // Undefined states don't compare with anything either, including themselves. let undefined = ScalarF5E3::ZERO / 0_i8;       // 0/0 assert!(!(undefined == undefined)); assert!(!(undefined < pos_normal)); assert!(!(undefined > pos_normal)); assert!(!(undefined < infinity)); assert!(!(undefined > infinity));
//! ```
//!
//! ### 6. Modulus and Modulo Operations
//!
//! Spirix provides two distinct remainder operations:
//!
//! #### 0. Mathematical Modulus (%)
//!
//! The standard `%` operator calculates the mathematical remainder after division:
//!
//! ```rust
//! use spirix::{CircleF5E3, ScalarF5E3};
//!
//! // Scalar modulus — remainder after division. let a = ScalarF5E3::from(7.5_f32); let b = ScalarF5E3::from(3_i8); let remainder = a % b; assert!(remainder == 1.5_f32);
//!
//! // Circle-Circle modulus — derived from complex division. let z1 = CircleF5E3::from((7_i8, 4_i8)); let z2 = CircleF5E3::from((3.8_f32, 2.2_f32)); let _complex_remainder = z1 % z2;
//! ```
//! For Circle-Circle operations, this implements:
//!
//! (a + b*i) % (c + d*i) = ((a*c + b*d) + (b*c − a*d)*i) % (c² + d²)
//!
//! ```rust
//! use spirix::{CircleF5E3, ScalarF5E3}; let z1 = CircleF5E3::from((7_i8, 4_i8));
//!
//! // Circle-Scalar modulus — based on magnitude. let s = ScalarF5E3::from(2_i8); let _magnitude_remainder = z1 % s; // Or via a Rust primitive directly — primitives are always treated as Scalars // and ALL ops work with ALL primitives :) let _magnitude_remainder = z1 % 2_i8;
//! ```
//!
//! #### 1. Component-wise Modulo (.modulo())
//!
//! The `.modulo()` method performs modulo on each component separately:
//!
//! ```rust
//! use spirix::{CircleF5E3, ScalarF5E3};
//!
//! // Circle-Circle component-wise modulo — acts on each part independently. let z1 = CircleF5E3::from((7_i8, 4_i8));   // 7 + 4i let z2 = CircleF5E3::from((3_i8, 2_i8));   // 3 + 2i let _component_remainder = z1.modulo(z2);  // (7 % 3) + (4 % 2)i = 1 + 0i
//!
//! // Circle-Scalar component-wise modulo — both components modulo Scalar. let s = ScalarF5E3::from(2_i8); let _component_scalar_mod = z1.modulo(s);  // (7 % 2) + (4 % 2)i = 1 + 0i
//! ```
//!
//! The component-wise formula for Circle values is:
//! ```text
//! (a + b*i).modulo(c + d*i) = (a % c) + (b % d)*i
//! ```
//!
//! Both operations handle special cases (undefined, exploded, vanished) appropriately, preserving mathematical consistency thruout numerical space.
//!
//! ### 7. Circles!
//!
//! Spirix provides complex number support with the `Circle` type:
//!
//! ```rust
//! use spirix::{CircleConstants, CircleF6E4};
//!
//! // Create a complex number — note the float real, integer imag mix. let z = CircleF6E4::from((1.5_f32, 2_i8));
//!
//! // Access real and imaginary parts. assert!(z.r() == 1.5_f32); let imag = z.i(); assert!(imag == 2_i8);
//!
//! // Calculate magnitude. let mag = z.magnitude(); assert!(mag == 2.5_f32); // Or magnitude squared. let mag_sq = z.magnitude_squared(); assert!(mag_sq == 6.25_f32);
//!
//! // Complex conjugate. let _conj = z.conjugate();
//!
//! // Complex multiplication. let w = CircleF6E4::from((3_i8, -4.1_f32)); let _product = z * w * 5_i8;
//!
//! // Complex constants. let i = CircleF6E4::POS_I; assert!(i.square() == -1_i8);
//! ```
//!
//! ## Getting Started
//!
//! ### Basic Usage
//!
//! ```rust
//! use spirix::{Circle, Scalar, ScalarF5E3};
//!
//! // Create Scalar values. let a = Scalar::<i32, i8>::from(7_i8); // F5E3 alias = 32-bit (2^5) fraction, 8-bit (2^3) exponent. let b = ScalarF5E3::from(1.2020569_f32);
//!
//! // Convert between types — only same-sized Scalars and Circles are interoperable. let misfit: Scalar<i16, i16> = 42_i8.into(); let _c: Scalar<i32, i8> = misfit.into(); // Cross-width conversion.
//!
//! // Basic arithmetic. let _sum = a + b; let product = a * b; let _quotient = a / b; let _reciprocal = b / a;                 // Reciprocal via division.
//!
//! // Modulo operations. let _remainder = a % b;                  // Mathematical modulus — remainder after division.
//!
//! // Transcendental functions. let _sin_a = a.sin(); let _exp_b = b.exp(); let _natural_log_product = product.ln();
//!
//! // Create a complex number. let z = Circle::<i32, i8>::from((1.5_f32, 11_i8)); let _conjugate = z.conjugate();
//!
//! // Complex modulo operations. let z1 = Circle::<i32, i8>::from((5_i8, 3.6_f32));    // 5 + 3.6i let z2 = Circle::<i32, i8>::from((2.4_f32, -1_i8));   // 2.4 − i let _complex_remainder = z1 % z2;          // Complex mathematical modulus. let _component_remainder = z1.modulo(z2);  // Component-wise modulo.
//! ```
//!
//! ## Choosing Precision
//!
//! When selecting fraction and exponent sizes, consider:
//!
//! - **Fraction bits**: Determines precision (significant digits)
//! - **Exponent bits**: Determines range (how large/small values can be)
//!
//! ```rust
//! use spirix::Scalar;
//!
//! // High precision with limited range.
//! type HighPrecisionNearOne = Scalar<i128, i8>;
//!
//! // Medium precision with large range.
//! type ScientificNotation = Scalar<i32, i64>;
//!
//! // Extreme range with limited precision.
//! type RoughApproximation = Scalar<i8, i128>;
//! # use spirix::ScalarConstants;
//! # let _ = (HighPrecisionNearOne::ONE, ScientificNotation::ONE, RoughApproximation::ONE);
//! ```
//!
//! | Type   | Precision (decimal digits) | Range                    |
//! |--------|----------------------------|--------------------------|
//! | F3E3   | 2.1 digits                 | 10^±38.5                 |
//! | F4E4   | 4.5 digits                 | 10^±9860                 |
//! | F5E5   | 9.3 digits                 | 10^(10^8.81)             |
//! | F6E6   | 18.9 digits                | 10^(10^18.4)             |
//! | F7E7   | 38.2 digits                | 10^(10^37.7)             |
//!
//! ## Extra Features!
//!
//! ### Bit Manipulation
//!
//! Spirix supports native bit-level operations that maintain alignment and mathematical consistancy:
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! let a = ScalarF5E3::from(42_i8);
//!
//! // Bitwise operations align fractions and return expected results. let _b = a & ScalarF5E3::from(15_i8);  // Aligned bitwise AND let _c = a | ScalarF5E3::from(3_i8);   // Aligned bitwise OR let _d = a ^ ScalarF5E3::from(21_i8);  // Aligned bitwise XOR
//!
//! // Bit shifts apply checked exponent adjustments directly. let _doubled = a << 1_u8;  // Multiply by 2 let _halved = a >> 3_u8;   // Divide by 8 // Spirix recognises an escape and returns a vanished Scalar. let _vanished = ScalarF5E3::MIN_POS >> 1_u8;
//! ```
//!
//! ### Mathematical Truncation
//!
//! Spirix provides various mathematical truncation functions:
//!
//! ```rust
//! use spirix::ScalarF5E3;
//!
//! let x = ScalarF5E3::from(3.7_f32);
//!
//! let _floor_x = x.floor();    // 3 let _ceil_x = x.ceil();      // 4 let _round_x = x.round();    // 4 let _frac_x = x.frac();      // 0.7
//! ```
//!
//! ## Application Examples
//!
//! ### Complex Number Grid
//!
//! ```rust
//! use spirix::CircleF5E3;
//!
//! // Wrapping a point to an 8×8 grid cell.
//! fn wrap_to_grid(point: &CircleF5E3, grid_size: &CircleF5E3) -> CircleF5E3 { point.modulo(*grid_size) }
//!
//! let point = CircleF5E3::from((37.54_f32, -12.3_f32)); let grid = CircleF5E3::from((8_i8, 8_i8)); let _wrapped = wrap_to_grid(&point, &grid);
//! ```
//!
//! ### Periodic Function Mapping
//!
//! ```rust
//! use spirix::{ScalarConstants, ScalarF5E3};
//!
//! // Map angle to [0, 2π) range.
//! fn normalize_angle(angle: ScalarF5E3) -> ScalarF5E3 { angle % ScalarF5E3::TAU }
//!
//! let angle = ScalarF5E3::from(8.5_f32); let normalized = normalize_angle(angle); assert!(normalized >= ScalarF5E3::ZERO); assert!(normalized < ScalarF5E3::PI * 2_i8);
//! ```

#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;

pub mod constants;
pub mod conversions;
pub mod core;
pub mod implementations;
pub mod lut;
pub mod operators;
pub mod simd;

// Public core types and traits
pub use crate::core::{
    // Core types
    circle::Circle,
    // Type aliases
    circle_aliases::*,
    // Core traits
    integer::Integer,
    scalar::Scalar,
    scalar_aliases::*,
};

// Constants for components
pub use crate::constants::{CircleConstants, ScalarConstants};

// Operator traits for mixed-type operations
pub use crate::operators::{Clamp, Logarithm, Max, Min, Power};

// Circle → (real, imag) Scalar decomposition.
pub use crate::conversions::circle_scalar::IntoScalars;

/// Compile-time `ScalarF4E4` literal from an f32 expression.
///
/// `sf!(0.0031308)` expands to a `const ScalarF4E4` at compile time — no IEEE runtime ops in the binary. The argument must be a normal finite non-zero f32 literal or simple const expression.
#[macro_export]
macro_rules! sf {
    ($e:expr) => {
        $crate::ScalarF4E4::from_f32($e as f32)
    };
}

/// Compile-time `ScalarF4E4` literal from an f64 expression.
///
/// `sd!(1.0/3.0)` expands to a `const ScalarF4E4` at compile time — no IEEE runtime ops in the binary. Provides higher precision than `sf!` for constants with more than 7 significant digits. The argument must be a normal finite non-zero f64 literal or simple const expression.
#[macro_export]
macro_rules! sd {
    ($e:expr) => {
        $crate::ScalarF4E4::from_f64($e as f64)
    };
}

// Tensor / NN demo layer. Deliberately NOT re-exported at the crate root: the numeric core is the semver commitment; reach these via `spirix::tensor::` where the experimental scope is explicit.
#[cfg(feature = "alloc")]
pub mod tensor;