Skip to content

Regarding isqrt performance #137786

Open
Open
@leonardo-m

Description

@leonardo-m

This is experimental code, it could be compiled with one or the other implementation of the integer square root:

#![feature(cfg_overflow_checks, stmt_expr_attributes)]
#![allow(unused_macros)]

#[cfg(overflow_checks)]
macro_rules! fto { ($e:expr, $t:ident) => (($e) as $t) }

#[cfg(not(overflow_checks))]
macro_rules! fto { ($e:expr, $t:ident) => (#[allow(unused_unsafe)] unsafe { $e.to_int_unchecked::<$t>() }) }

macro_rules! isqrt { ($e:expr, $t:ident) => ( fto!{(($e) as f64).sqrt(), $t} ) }

fn main() {
    let mut tot: u64 = 0;
    for x in (1_u64 .. 1_000_000_000).step_by(3) {
        tot += isqrt!(x, u64); // Version A.  1.04 seconds.
        //tot += x.isqrt(); // Version B.       4.94 seconds.
    }
    println!("{tot}");
}

As you see the floating-point based isqrt implementation is almost five times faster on my PC (using rustc 1.87.0-nightly). The std lib isqrt has upside of being const, so I can use it for const generics calculations and similar situations. And when I need to compute only one or few isqrt, this performance difference isn't important, and I use the std one. But when I need to compute a lot of isqrt, I consider faster alternatives.

While I don't propose to replace the std library isqrt with the code I've shown here, I suggest std lib implementers to express an opinion regarding the usage of floating point sqrt+ int cast in some vetted and safe cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions