# Performance of isqrt

**URL:** <https://internals.rust-lang.org/t/performance-of-isqrt/23228>\
**Category:** libs\
**Created:** [July 14, 2025, 1:46pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228 "2025-07-14T13:46:01Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [July 14, 2025, 1:46pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/1 "2025-07-14T13:46:01Z")

</div>

I'm really curious about the performance issues about isqrt, since they are quite long.

There is a very simple idea come into my mind: Will it faster to convert u32 into f64, calculating its square root directly, and convert its result back, is faster than calling .isqrt() directly?

```rust
$ cat main.rs && cargo rr
fn fsqrt(u: u32) -> u32 {
    (u as f64).sqrt() as u32
}
fn isqrt(u: u32) -> u32 {
    u.isqrt()
}
fn timing(f: fn(u32) -> u32, range: impl Iterator<Item = u32>) {
    let now = std::time::Instant::now();
    let mut res = 0;
    for i in range {
        res += f(i);
    }
    println!("res = {res} {:?}", now.elapsed());
}
fn main() {
    timing(fsqrt, 0..=u32::MAX);
    timing(isqrt, 0..=u32::MAX);
}
    Finished `release` profile [optimized] target(s) in 0.00s
     Running `/me/test-isqrt/target/release/test-isqrt`
res = 715816960 8.357294192s
res = 715816960 18.820145928s

```

I have no idea whether it deserved to create a PR about this trick.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [July 14, 2025, 1:49pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/2 "2025-07-14T13:49:05Z")

</div>

I feel I have seen a thread on this already here, a year ago or so. Wasn't the issue raised (and never addressed) that not all targets have hardware floating point?

---

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [July 14, 2025, 1:57pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/3 "2025-07-14T13:57:11Z")

</div>

If the issue is "not all targets have hardware floating point", we could pick all the target that isqrt is slower than convert it to f64 directly.

for example:

```rust
#[cfg(or(target_arch = "x86_64", target_arch = "x86"))]
fn isqrt(i: u32) -> u32 {
    (i as f64).sqrt() as f32
}
#[cfg(not(or(target_arch = "x86_64", target_arch = "x86")))]
fn isqrt(i: u32) -> u32 {
    // old impl
}

```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 14, 2025, 3:07pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/4 "2025-07-14T15:07:59Z")

</div>

IIRC part of the problem is that it's a full target question, not just an arch problem. There was something like the linux kernel not wanting to use SSE (which rust does for `f64` operations like this) in kernel mode even on x64 chips that all have it.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [July 14, 2025, 3:10pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/5 "2025-07-14T15:10:47Z")

</div>

Some previous discussion of this: [Do the square root intrinsics work on all platforms?](https://internals.rust-lang.org/t/do-the-square-root-intrinsics-work-on-all-platforms/19665)

Note that the discussion only start part way through, it starts out as a different question and... meanders. As often happens.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [July 14, 2025, 3:49pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/6 "2025-07-14T15:49:54Z")

</div>

> [@scottmcm](#):
>
> linux kernel not wanting to use SSE

This is mostly about not wanting to save and restore floating point state from the userspace process, especially since interrupts and preemption can happen at any time. There are no callee/caller-save ABI rules to limit state here, so the kernel has to save everything that it might clobber.

> **[Floating-point API — The Linux Kernel documentation](https://docs.kernel.org/core-api/floating-point.html)**

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [July 14, 2025, 8:46pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/7 "2025-07-14T20:46:17Z")

</div>

We already implement [f32::midpoint](https://github.com/rust-lang/rust/blob/aa51a9b0948ff406958dca8dc74839a3009b7e5f/library/core/src/num/f32.rs#L994-L1006) in platform-dependent way.

But I think there might be a much bigger variance between integer and float behavior compared to the gap between f32 and f64 (with the assumption that both of the latter are hardfloat).

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [July 14, 2025, 8:56pm UTC](https://internals.rust-lang.org/t/performance-of-isqrt/23228/8 "2025-07-14T20:56:54Z")

</div>

see also, stabilization report of the isqrt feature: [Tracking Issue for `{u8,i8,...}::isqrt` · Issue #116226 · rust-lang/rust · GitHub](https://github.com/rust-lang/rust/issues/116226#issuecomment-2395625154)
