Skip to content

Improve performance of ilog and checked_ilog for primitive integer types #115874

Open
@FedericoStra

Description

@FedericoStra

Currently checked_ilog is implemented with iterated divisions:

pub const fn checked_ilog(self, base: Self) -> Option<u32> {
if self <= 0 || base <= 1 {
None
} else {
let mut n = 0;
let mut r = self;
// Optimization for 128 bit wide integers.
if Self::BITS == 128 {
let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
n += b;
r /= base.pow(b as u32);
}
while r >= base {
r /= base;
n += 1;
}
Some(n)
}
}

It's pretty straightforward to convert it to iterated multiplications:

fn checked_int_log(self, base:Self) -> Option<u32> {
    if self <= 0 || base <= 1 {
        None
    } else {
        let mut n = 0;
        let mut r = 1;

        // Optimization for 128 bit wide integers.
        if Self::BITS == 128 {
            let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
            n += b;
            r *= base.pow(b);
        }

        while r <= self / base {
            n += 1;
            r *= base;
        }
        Some(n)
    }
}

and this results in some decent speedups (1.5x - 7x).

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchI-slowIssue: Problems and improvements with respect to performance of generated code.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