use num_traits::Float;
pub fn powi_portable<F: Float>(x: F, n: i32) -> F {
if n == 0 {
return F::one();
}
if x.is_nan() {
return F::nan();
}
if x.is_zero() {
let n_odd = n % 2 != 0;
let neg = x.is_sign_negative() && n_odd;
return match (n > 0, neg) {
(true, false) => F::zero(),
(true, true) => F::neg_zero(),
(false, false) => F::infinity(),
(false, true) => F::neg_infinity(),
};
}
if x.is_infinite() {
let n_odd = n % 2 != 0;
let neg = x.is_sign_negative() && n_odd;
return match (n > 0, neg) {
(true, false) => F::infinity(),
(true, true) => F::neg_infinity(),
(false, false) => F::zero(),
(false, true) => F::neg_zero(),
};
}
let mut base = x;
let mut exp = n.unsigned_abs();
let mut acc = F::one();
loop {
if !exp.is_multiple_of(2) {
acc = base * acc;
}
exp /= 2;
if exp == 0 {
break;
}
base = base * base;
}
if n < 0 { acc.recip() } else { acc }
}