1
Fork 0

Optimize integer pow by removing exit branch

The branch at the end of the `pow` implementations is redundant
with multiplication code already present in the loop. By rotating
the exit check, this branch can be largely removed, improving code size
and instruction cache coherence.
This commit is contained in:
Mikhail Zabaluev 2024-03-22 16:50:48 +02:00
parent bcf1f6db45
commit df27dfa0ea
2 changed files with 52 additions and 73 deletions

View file

@ -1495,18 +1495,17 @@ macro_rules! int_impl {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
loop {
if (exp & 1) == 1 {
acc = try_opt!(acc.checked_mul(base));
// since exp!=0, finally the exp must be 1.
if exp == 1 {
return Some(acc);
}
}
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.checked_mul(base)
}
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@ -1546,18 +1545,17 @@ macro_rules! int_impl {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
loop {
if (exp & 1) == 1 {
acc = acc.strict_mul(base);
// since exp!=0, finally the exp must be 1.
if exp == 1 {
return acc;
}
}
exp /= 2;
base = base.strict_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.strict_mul(base)
}
/// Returns the square root of the number, rounded down.
@ -2181,19 +2179,17 @@ macro_rules! int_impl {
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
loop {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
// since exp!=0, finally the exp must be 1.
if exp == 1 {
return acc;
}
}
exp /= 2;
base = base.wrapping_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.wrapping_mul(base)
}
/// Calculates `self` + `rhs`
@ -2687,9 +2683,14 @@ macro_rules! int_impl {
// Scratch space for storing results of overflowing_mul.
let mut r;
while exp > 1 {
loop {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
// since exp!=0, finally the exp must be 1.
if exp == 1 {
r.1 |= overflown;
return r;
}
acc = r.0;
overflown |= r.1;
}
@ -2698,14 +2699,6 @@ macro_rules! int_impl {
base = r.0;
overflown |= r.1;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
}
/// Raises self to the power of `exp`, using exponentiation by squaring.
@ -2732,19 +2725,17 @@ macro_rules! int_impl {
let mut base = self;
let mut acc = 1;
while exp > 1 {
loop {
if (exp & 1) == 1 {
acc = acc * base;
// since exp!=0, finally the exp must be 1.
if exp == 1 {
return acc;
}
}
exp /= 2;
base = base * base;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc * base
}
/// Returns the square root of the number, rounded down.