# Rust 1.98 Algebraic Floats Fix the 8x C++ Speed Gap

> Source: <https://byteiota.com/rust-1-98-algebraic-floats-fix-the-8x-c-speed-gap/>
> Published: 2026-08-22 22:10:35+00:00

Rust 1.98 landed on August 20 with a headline feature the previews missed: algebraic floating-point methods that directly address the long-standing gap where Rust dot products ran **8x slower than C++** on x86_64 CPUs. If you write numerical, audio, graphics, or ML inference code in Rust, this is the release you have been waiting for. Run `rustup update stable`

and read on.

## The Float Problem: Why Rust Was Losing to C++

In 2025, a [GitHub issue](https://github.com/rust-lang/libs-team/issues/532) demonstrated that a simple Rust dot-product loop ran 8x slower than the equivalent C++ on modern x86_64 hardware. The culprit was not Rust’s optimizer — it was correctness. Rust strictly follows IEEE 754, which mandates that floating-point additions execute left to right. That means `a + b + c + d`

must be evaluated as `((a + b) + c) + d`

, one operation at a time.

C++ with `-O3`

relaxes that constraint and lets the compiler reorder operations into `(a + b) + (c + d)`

, which maps directly to SIMD parallel execution. That is where the 8x gap came from. The previous Rust workaround — `fadd_fast`

intrinsics — assumed all inputs were finite, causing undefined behavior if a NaN or infinity appeared. Not exactly production-safe.

## Algebraic Methods: Opt-In Performance, No Undefined Behavior

Rust 1.98 adds five new methods to both `f32`

and `f64`

: `algebraic_add`

, `algebraic_sub`

, `algebraic_mul`

, `algebraic_div`

, and `algebraic_rem`

. They signal to the compiler that it may reorder these specific operations for better vectorization. Results may differ slightly from strict IEEE sequential execution — but they are never undefined behavior. The compiler picks valid floating-point values, not garbage.

Here is what a vectorization-friendly dot product looks like in Rust 1.98:

``` php
fn dot(a: &[f32], b: &[f32]) -> f32 {
    a.iter().zip(b).fold(0.0_f32, |acc, (x, y)| {
        acc.algebraic_add(x.algebraic_mul(*y))
    })
}
```

That is the entire change. The compiler now has permission to generate vectorized code for this loop. Performance gains depend on your workload — simple accumulations can approach the C++ baseline, and numerical kernels previously bottlenecked on sequential float ops should see meaningful improvements.

This is a more surgical design than C++’s `-ffast-math`

, which applies to every float operation in the compilation unit — you cannot opt specific hot loops in while leaving the rest IEEE-compliant. Rust’s algebraic methods are per-operation, giving you precise control. [Python Speed’s breakdown](https://pythonspeed.com/articles/faster-float-math-rust/) walks through the performance implications in detail.

## format_into: Remove itoa from Your Cargo.toml

The second headline addition is `format_into`

on all primitive integer types, paired with the new `NumBuffer`

type. It is a stack-allocated, zero-heap, zero-dynamic-dispatch way to turn integers into string slices:

``` js
let mut buf = NumBuffer::<u64>::INIT;
let s: &str = 1234567u64.format_into(&mut buf);
```

The [ itoa crate](https://crates.io/crates/itoa) has served this purpose for years and logs around 200 million downloads per month on crates.io.

`format_into`

benchmarks on par with it. For new code using primitive integers in performance-critical paths, the stdlib now covers this use case without an external dependency. The `itoa`

crate still makes sense for its byte-slice API or broader type coverage, but most users can reach for stdlib instead.## Other Additions Worth Noting

Rust 1.98 also stabilizes `String::from_utf16le`

and `String::from_utf16be`

for explicit-endian UTF-16 conversion — a common pain point when processing Windows-native data formats. The `strip_circumfix`

method removes a matching prefix and suffix in a single call. And `str::substr_range`

/ `[T]::subslice_range`

return the index range of a sub-slice within its parent, simplifying several common string manipulation patterns.

The type system also gains the ability to shorten `&mut`

lifetimes when unsize-coercing in invariant positions — a narrow but previously frustrating limitation that forced some generic code into unsafe workarounds.

## When Not to Use Algebraic Methods

Algebraic methods are not appropriate for financial calculations, cryptographic code, or anywhere exact IEEE 754 reproducibility matters. If your test suite verifies exact floating-point output or you are implementing a spec that mandates sequential evaluation, leave `algebraic_*`

alone. For simulation, inference, audio processing, and rendering — anywhere approximate-but-faster is the right tradeoff — this is a clear upgrade.

## Upgrading

Rust 1.98 is a standard stable release with full backward compatibility. Existing code compiles without changes. The algebraic methods and `format_into`

are available immediately with no feature flags required:

```
rustup update stable
```

The full release announcement is on the [official Rust blog](https://blog.rust-lang.org/2026/08/20/Rust-1.98.0/). The complete API changelog lives at [releases.rs](https://releases.rs/docs/1.98.0/). Coverage on [Phoronix](https://www.phoronix.com/news/Rust-1.98-Released) digs into the vectorization angle further.
