use crate::InnerFloat::{Finite, Infinity, NaN, Zero};
use crate::TWICE_WIDTH;
use crate::emulate_float_float_to_float_fn;
use crate::emulate_float_to_float_fn;
use crate::float::arithmetic::exp::{
exp_overflow, exp_rational_near_one, exp_underflow, one_neighbor,
};
use crate::float::arithmetic::ln::ln_1_plus_rational_brackets;
use crate::float::arithmetic::log_base_2::log_2_rational_brackets;
use crate::float::arithmetic::round_near_x::float_round_near_x;
use crate::{
Float, float_either_infinity, float_either_zero, float_nan, float_negative_zero,
floor_and_ceiling,
};
use core::cmp::Ordering::{self, *};
use core::cmp::max;
use core::mem::swap;
use malachite_base::fail_on_untested_path;
use malachite_base::num::arithmetic::traits::{
Abs, CeilingLogBase2, CheckedLogBase2, CheckedRoot, CheckedSqrt, DivisibleBy, IsPowerOf2,
NegAssign, Parity, Pow, PowAssign, Square, UnsignedAbs,
};
use malachite_base::num::basic::floats::PrimitiveFloat;
use malachite_base::num::basic::integers::PrimitiveInt;
use malachite_base::num::basic::traits::{
Infinity as InfinityTrait, NaN as NaNTrait, NegativeInfinity, NegativeZero, One,
Zero as ZeroTrait,
};
use malachite_base::num::comparison::traits::OrdAbs;
use malachite_base::num::comparison::traits::PartialOrdAbs;
use malachite_base::num::conversion::traits::{ExactFrom, IsInteger, RoundingFrom, SaturatingFrom};
use malachite_base::num::logic::traits::{BitAccess, BitIterable, SignificantBits};
use malachite_base::rounding_modes::RoundingMode::{self, *};
use malachite_nz::integer::Integer;
use malachite_nz::natural::Natural;
use malachite_nz::natural::arithmetic::float_extras::float_can_round;
use malachite_nz::platform::{Limb, SignedLimb};
use malachite_q::Rational;
const POW_EXP_THRESHOLD: i64 = 256;
fn float_odd_integer(y: &Float) -> bool {
if !y.is_finite() || y.is_zero() || !y.is_integer() {
return false;
}
let e = i64::from(y.get_exponent().unwrap());
let m = y.significand_ref().unwrap();
let b = i64::exact_from(m.significant_bits());
e <= b && i64::exact_from(m.trailing_zeros().unwrap()) == b - e
}
fn pow_underflow(prec: u64, rm: RoundingMode, negative: bool) -> (Float, Ordering) {
if negative {
let (f, o) = exp_underflow(prec, -rm);
(-f, o.reverse())
} else {
exp_underflow(prec, rm)
}
}
fn pow_overflow(prec: u64, rm: RoundingMode, negative: bool) -> (Float, Ordering) {
if negative {
let (f, o) = exp_overflow(prec, -rm);
(-f, o.reverse())
} else {
exp_overflow(prec, rm)
}
}
fn raw_power_of_2(x: &Float) -> bool {
x.significand_ref().unwrap().is_power_of_2()
}
fn float_one_plus_tiny(prec: u64, rm: RoundingMode, above: bool) -> (Float, Ordering) {
match (rm, above) {
(Up | Ceiling, true) => (one_neighbor(prec, true), Greater),
(Down | Floor, false) => (one_neighbor(prec, false), Less),
(_, true) => (Float::one_prec(prec), Less),
(_, false) => (Float::one_prec(prec), Greater),
}
}
enum NearOne {
Rounded(Float, Ordering),
JumpStart(u64),
No,
}
fn pow_near_one_fast_path(
x: &Float,
sb_z: u64,
z_negative: bool,
negate: bool,
prec: u64,
rm: RoundingMode,
) -> NearOne {
if rm == Exact {
return NearOne::No;
}
let ex = i64::from(x.get_exponent().unwrap());
if ex != 0 && ex != 1 {
return NearOne::No;
}
let d = x
.abs()
.sub_prec_round(Float::ONE, x.significant_bits() + 2, Exact)
.0;
if d == 0u32 {
return NearOne::No;
}
let fld = i64::from(d.get_exponent().unwrap());
let Some(shift) = fld.checked_add(i64::exact_from(sb_z)) else {
return NearOne::No;
};
if shift > -3 {
return NearOne::No;
}
let err = u64::exact_from(-shift);
let above = (d > 0u32) != z_negative;
let rm_abs = if negate { -rm } else { rm };
if let Some((v, o)) = float_round_near_x(&Float::ONE, err, above, prec, rm_abs) {
return if negate {
NearOne::Rounded(-v, o.reverse())
} else {
NearOne::Rounded(v, o)
};
}
NearOne::JumpStart(err)
}
fn pow_pos_natural(
x: &Float,
z: &Natural,
prec: u64,
rm: RoundingMode,
cr: bool,
extra_prec: u64,
) -> (Float, Ordering) {
assert_ne!(*z, 0u32);
if *z == 1u32 {
return Float::from_float_prec_round_ref(x, prec, rm);
}
let size_z = z.significant_bits();
let x_exp_ge_1 = x.get_exponent().unwrap() >= 1;
let rnd1 = if x_exp_ge_1 {
Down
} else if x.is_sign_positive() {
Up
} else {
Floor
};
let rnd2 = if x_exp_ge_1 { Floor } else { Up };
let mut wprec = if cr {
prec + 3 + size_z + prec.ceiling_log_base_2() + extra_prec
} else {
prec
};
loop {
let mut inexmul;
let err = wprec - 1 - size_z;
let mut i = size_z;
let (mut res, o) = x.square_prec_round_ref(wprec, rnd2);
inexmul = o != Equal;
assert!(i >= 2);
if z.get_bit(i - 2) {
let o = res.mul_prec_round_assign_ref(x, wprec, rnd1);
inexmul |= o != Equal;
}
if i > 2 {
i -= 3;
while res.is_finite() && !res.is_zero() {
let o = res.square_prec_round_assign(wprec, rnd2);
inexmul |= o != Equal;
if z.get_bit(i) {
let o = res.mul_prec_round_assign_ref(x, wprec, rnd1);
inexmul |= o != Equal;
}
if i == 0 {
break;
}
i -= 1;
}
}
if !x_exp_ge_1
&& inexmul
&& res.is_finite()
&& !res.is_zero()
&& i64::from(res.get_exponent().unwrap()) == i64::from(Float::MIN_EXPONENT)
&& raw_power_of_2(&res)
{
res = if res.is_sign_negative() {
Float::NEGATIVE_ZERO
} else {
Float::ZERO
};
}
let is_zero = res.is_zero();
let exceptional = res.is_infinite() || is_zero;
if !inexmul
|| !cr
|| exceptional
|| float_can_round(res.significand_ref().unwrap(), err, prec, rm)
{
if exceptional {
if !is_zero {
fail_on_untested_path("pow_pos_natural, overflow");
}
let o = if is_zero == res.is_sign_positive() {
Less
} else {
Greater
};
return (res, o);
}
return Float::from_float_prec_round(res, prec, rm);
}
wprec += wprec >> 1;
}
}
fn pow_integer_underflow_nearest(x: &Float, z: &Integer, prec: u64) -> (Float, Ordering) {
let z_bits = z.significant_bits();
let zz = Float::from_integer_prec_round(z.clone(), z_bits, Exact).0;
let (y2, o) = pow_general(x, &zz, 2, Nearest, true);
(Float::from_float_prec_round(y2, prec, Exact).0, o)
}
fn pow_integer(x: &Float, z: &Integer, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if *z == 0u32 {
fail_on_untested_path("pow_integer, z == 0");
return (Float::one_prec(prec), Equal);
}
if x.is_nan() {
fail_on_untested_path("pow_integer, NaN x");
return (Float::NAN, Equal);
}
let z_pos = *z > 0u32;
let z_odd = z.odd();
if x.is_infinite() {
fail_on_untested_path("pow_integer, infinite x");
let negative = x.is_sign_negative() && z_odd;
return (
match (z_pos, negative) {
(true, false) => Float::INFINITY,
(true, true) => Float::NEGATIVE_INFINITY,
(false, false) => Float::ZERO,
(false, true) => Float::NEGATIVE_ZERO,
},
Equal,
);
}
if x.is_zero() {
fail_on_untested_path("pow_integer, zero x");
let negative = x.is_sign_negative() && z_odd;
return (
match (z_pos, negative) {
(true, false) => Float::ZERO,
(true, true) => Float::NEGATIVE_ZERO,
(false, false) => Float::INFINITY,
(false, true) => Float::NEGATIVE_INFINITY,
},
Equal,
);
}
if raw_power_of_2(x) {
let ex = i64::from(x.get_exponent().unwrap());
let sign_negative = x.is_sign_negative() && z_odd;
let new_exp = z * Integer::from(ex - 1) + Integer::ONE;
let base = if sign_negative {
-Float::one_prec(prec)
} else {
Float::one_prec(prec)
};
return if new_exp < Float::MIN_EXPONENT {
pow_underflow(prec, if rm == Nearest { Down } else { rm }, sign_negative)
} else if new_exp > Float::MAX_EXPONENT {
pow_overflow(prec, rm, sign_negative)
} else {
let sh = i64::exact_from(&(new_exp - Integer::ONE));
base.shl_prec_round(sh, prec, rm)
};
}
let negative = x.is_sign_negative() && z_odd;
let mut jump_extra = 0;
match pow_near_one_fast_path(
x,
z.unsigned_abs_ref().significant_bits(),
!z_pos,
negative,
prec,
rm,
) {
NearOne::Rounded(v, o) => return (v, o),
NearOne::JumpStart(extra) => jump_extra = extra,
NearOne::No => {}
}
if jump_extra == 0 {
let est = f64::rounding_from(x.abs().log_base_2_prec(64).0, Nearest).0
* f64::rounding_from(z, Nearest).0;
if est > const { Float::MAX_EXPONENT as f64 + 64.0 } {
return pow_overflow(prec, rm, negative);
}
if est < const { Float::MIN_EXPONENT as f64 - 64.0 } {
return pow_underflow(prec, if rm == Nearest { Down } else { rm }, negative);
}
if est >= const { Float::MAX_EXPONENT as f64 - 66.0 }
&& pow_exponent_at_least(x, z, i64::from(Float::MAX_EXPONENT))
{
return pow_overflow(prec, rm, negative);
}
}
if z_pos {
let (result, o) = pow_pos_natural(x, z.unsigned_abs_ref(), prec, rm, true, jump_extra);
if result.is_zero() {
return if rm == Nearest {
pow_integer_underflow_nearest(x, z, prec)
} else {
pow_underflow(prec, rm, x.is_sign_negative() && z_odd)
};
}
(result, o)
} else {
let abs_z = z.unsigned_abs_ref();
let size_z = abs_z.significant_bits();
let mut wprec = prec + size_z + 3 + prec.ceiling_log_base_2() + jump_extra;
let rnd1 = if x.get_exponent().unwrap() < 1 {
Down
} else if x.is_sign_positive() {
Up
} else {
Floor
};
loop {
let t = Float::ONE.div_prec_round_val_ref(x, wprec, rnd1).0;
if t.is_infinite() {
fail_on_untested_path("pow_integer, 1/x overflow");
return pow_overflow(prec, rm, t.is_sign_negative());
}
let t = pow_pos_natural(&t, abs_z, wprec, rm, false, 0).0;
if t.is_infinite() {
fail_on_untested_path("pow_integer, (1/x)^|z| overflow");
return pow_overflow(prec, rm, t.is_sign_negative());
}
if t.is_zero() {
if rm == Nearest {
return pow_integer_underflow_nearest(x, z, prec);
}
return pow_underflow(prec, rm, x.is_sign_negative() && z_odd);
}
let err = wprec - size_z - 2;
if float_can_round(t.significand_ref().unwrap(), err, prec, rm) {
return Float::from_float_prec_round(t, prec, rm);
}
wprec += wprec >> 1;
}
}
}
fn pow_u(x: Float, n: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if n == 0 {
return (Float::one_prec(prec), Equal);
}
if x.is_nan() {
return (Float::NAN, Equal);
}
if x.is_infinite() {
return (
if x.is_sign_negative() && n.odd() {
Float::NEGATIVE_INFINITY
} else {
Float::INFINITY
},
Equal,
);
}
if x.is_zero() {
return (
if x.is_sign_negative() && n.odd() {
Float::NEGATIVE_ZERO
} else {
Float::ZERO
},
Equal,
);
}
if n <= 2 {
return if n == 1 {
Float::from_float_prec_round(x, prec, rm)
} else {
x.square_prec_round(prec, rm)
};
}
let nlen = n.significant_bits();
let rnd1 = if x.is_sign_positive() { Ceiling } else { Floor };
let mut wprec = {
let p = prec + 67 + prec.ceiling_log_base_2();
if p <= nlen {
fail_on_untested_path("pow_u, working precision clamped up to nlen + 1");
nlen + 1
} else {
p
}
};
match pow_near_one_fast_path(&x, nlen, false, x.is_sign_negative() && n.odd(), prec, rm) {
NearOne::Rounded(v, o) => return (v, o),
NearOne::JumpStart(extra) => wprec += extra,
NearOne::No => {}
}
loop {
let err = wprec - 1 - nlen;
let (mut res, o) = x.square_prec_round_ref(wprec, Ceiling);
let mut inexact = o != Equal;
let mut i = nlen;
if n.get_bit(i - 2) {
inexact |= res.mul_prec_round_assign_ref(&x, wprec, rnd1) != Equal;
}
if i > 2 {
i -= 3;
loop {
if res.is_infinite() || res.is_zero() {
break;
}
inexact |= res.square_prec_round_assign(wprec, Ceiling) != Equal;
if n.get_bit(i) {
inexact |= res.mul_prec_round_assign_ref(&x, wprec, rnd1) != Equal;
}
if i == 0 {
break;
}
i -= 1;
}
}
if res.is_infinite() || res.is_zero() || res.get_exponent().unwrap() <= Float::MIN_EXPONENT
{
if res.is_zero() {
fail_on_untested_path("pow_u, res rounded to zero");
}
return x.pow_integer_prec_round(Integer::from(n), prec, rm);
}
if !inexact || float_can_round(res.significand_ref().unwrap(), err, prec, rm) {
return Float::from_float_prec_round(res, prec, rm);
}
wprec += wprec >> 1;
}
}
fn pow_u_ref(x: &Float, n: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if n == 0 {
return (Float::one_prec(prec), Equal);
}
if x.is_nan() {
return (Float::NAN, Equal);
}
if x.is_infinite() {
return (
if x.is_sign_negative() && n.odd() {
Float::NEGATIVE_INFINITY
} else {
Float::INFINITY
},
Equal,
);
}
if x.is_zero() {
return (
if x.is_sign_negative() && n.odd() {
Float::NEGATIVE_ZERO
} else {
Float::ZERO
},
Equal,
);
}
if n <= 2 {
return if n == 1 {
Float::from_float_prec_round_ref(x, prec, rm)
} else {
x.square_prec_round_ref(prec, rm)
};
}
let nlen = n.significant_bits();
let rnd1 = if x.is_sign_positive() { Ceiling } else { Floor };
let mut wprec = {
let p = prec + 67 + prec.ceiling_log_base_2();
if p <= nlen {
fail_on_untested_path("pow_u, working precision clamped up to nlen + 1");
nlen + 1
} else {
p
}
};
match pow_near_one_fast_path(x, nlen, false, x.is_sign_negative() && n.odd(), prec, rm) {
NearOne::Rounded(v, o) => return (v, o),
NearOne::JumpStart(extra) => wprec += extra,
NearOne::No => {}
}
loop {
let err = wprec - 1 - nlen;
let (mut res, o) = x.square_prec_round_ref(wprec, Ceiling);
let mut inexact = o != Equal;
let mut i = nlen;
if n.get_bit(i - 2) {
inexact |= res.mul_prec_round_assign_ref(x, wprec, rnd1) != Equal;
}
if i > 2 {
i -= 3;
loop {
if res.is_infinite() || res.is_zero() {
break;
}
inexact |= res.square_prec_round_assign(wprec, Ceiling) != Equal;
if n.get_bit(i) {
inexact |= res.mul_prec_round_assign_ref(x, wprec, rnd1) != Equal;
}
if i == 0 {
break;
}
i -= 1;
}
}
if res.is_infinite() || res.is_zero() || res.get_exponent().unwrap() <= Float::MIN_EXPONENT
{
if res.is_zero() {
fail_on_untested_path("pow_u, res rounded to zero");
}
return x.pow_integer_prec_round_ref_val(Integer::from(n), prec, rm);
}
if !inexact || float_can_round(res.significand_ref().unwrap(), err, prec, rm) {
return Float::from_float_prec_round(res, prec, rm);
}
wprec += wprec >> 1;
}
}
fn pow_s(x: Float, n: i64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if n >= 0 {
pow_u(x, n.unsigned_abs(), prec, rm)
} else {
x.pow_integer_prec_round(Integer::from(n), prec, rm)
}
}
fn pow_s_ref(x: &Float, n: i64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if n >= 0 {
pow_u_ref(x, n.unsigned_abs(), prec, rm)
} else {
x.pow_integer_prec_round_ref_val(Integer::from(n), prec, rm)
}
}
fn unsigned_pow_unsigned(k: u64, n: u64, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
if n == 0 {
return (Float::one_prec(prec), Equal);
} else if n == 1 || k <= 1 {
return Float::from_unsigned_prec_round(k, prec, rm);
}
let size_n = n.significant_bits();
let kf = Float::from(k);
let mut wprec = prec + 5 + size_n;
loop {
let (mut res, o) = Float::from_unsigned_prec_round(k, wprec, Ceiling);
let mut inexact = o != Equal;
for bit in n.bits().rev().skip(1) {
inexact |= res.square_prec_round_assign(wprec, Ceiling) != Equal;
if bit {
inexact |= res.mul_prec_round_assign_ref(&kf, wprec, Ceiling) != Equal;
}
}
if res.is_infinite() {
return kf.pow_integer_prec_round(Integer::from(n), prec, rm);
}
if !inexact || float_can_round(res.significand_ref().unwrap(), wprec - size_n - 2, prec, rm)
{
return Float::from_float_prec_round(res, prec, rm);
}
wprec += wprec >> 1;
}
}
fn pow_is_exact(x: &Float, y: &Float, prec: u64, rm: RoundingMode) -> Option<(Float, Ordering)> {
if y.is_sign_negative() {
return None;
}
let (c, mut d) = float_to_odd_mantissa_and_exponent(y);
assert!(d < 0);
let (mut a, mut b) = float_to_odd_mantissa_and_exponent_natural(x);
while d != 0 {
if b.odd() {
a <<= 1u32;
b -= 1;
}
a = a.checked_sqrt()?;
b >>= 1;
d += 1;
}
let tmp_prec = a.significant_bits();
let tmp = Float::from_natural_prec_round(a, tmp_prec, Exact)
.0
.shl_prec_round(b, tmp_prec, Exact)
.0;
Some(pow_integer(&tmp, &c, prec, rm))
}
fn pow_general_tiny_product(
abs_x: &Float,
y: &Float,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
if let Some(result) = pow_is_exact(abs_x, y, prec, rm) {
return result;
}
let yr = Rational::exact_from(y);
let y_pos = *y > 0u32;
let near_one = abs_x
.sub_prec_ref_val(Float::ONE, 64)
.0
.get_exponent()
.unwrap()
< -8;
let e = if near_one {
Some(Rational::exact_from(abs_x) - Rational::ONE)
} else {
None
};
let mut wp = 128;
loop {
let (ln_lo, ln_hi) = if let Some(e) = &e {
ln_1_plus_rational_brackets(e, wp)
} else {
(
Rational::exact_from(abs_x.ln_prec_round_ref(wp, Floor).0),
Rational::exact_from(abs_x.ln_prec_round_ref(wp, Ceiling).0),
)
};
let (t_lo, t_hi) = if y_pos {
(&yr * ln_lo, &yr * ln_hi)
} else {
(&yr * ln_hi, &yr * ln_lo)
};
let lower = Rational::ONE + &t_lo;
let upper = Rational::ONE + &t_hi + (&t_hi).square();
let (p_lo, mut o_lo) = Float::from_rational_prec_round(lower, prec, rm);
let (p_hi, mut o_hi) = Float::from_rational_prec_round(upper, prec, rm);
if o_lo == Equal {
o_lo = o_hi;
}
if o_hi == Equal {
o_hi = o_lo;
}
if o_lo == o_hi && p_lo == p_hi {
return (p_lo, o_lo);
}
wp <<= 1;
}
}
fn pow_general(
x: &Float,
y: &Float,
prec: u64,
mut rm: RoundingMode,
y_is_integer: bool,
) -> (Float, Ordering) {
let abs_x = x.abs();
let mut neg_result = false;
if x.is_sign_negative() {
assert!(y_is_integer);
if float_odd_integer(y) {
neg_result = true;
rm.neg_assign(); }
}
let mut wprec = prec + 9 + prec.ceiling_log_base_2();
let ey = i64::from(y.get_exponent().unwrap());
let d = abs_x.sub_prec_ref_val(Float::ONE, 64).0;
let d_exp = i64::from(d.get_exponent().unwrap());
let ln_exp = if d_exp < -8 {
d_exp
} else {
i64::from(abs_x.ln_prec_round_ref(64, Floor).0.get_exponent().unwrap())
};
if ey.saturating_add(ln_exp) <= i64::from(Float::MIN_EXPONENT) + 2 {
let (mut result, mut o) = pow_general_tiny_product(&abs_x, y, prec, rm);
if neg_result {
result.neg_assign();
o = o.reverse();
}
return (result, o);
}
let mut k: Option<Integer> = None;
let mut check_exact_case = false;
let mut exact_case = false;
let mut result;
let mut o;
loop {
let mut t = abs_x
.ln_prec_round_ref(wprec, if y.is_sign_negative() { Floor } else { Ceiling })
.0;
t.mul_prec_round_assign_ref(y, wprec, Ceiling);
if k.is_none()
&& (t.is_zero()
|| (t.get_exponent() == Some(Float::MIN_EXPONENT) && raw_power_of_2(&t)))
{
(result, o) = pow_general_tiny_product(&abs_x, y, prec, rm);
break;
}
let exp_t = t.get_exponent().map_or(0, i64::from);
if let Some(kv) = &k {
t.sub_prec_round_assign(
Float::ln_2_prec_round(wprec, Floor)
.0
.mul_prec_round(
Float::from_signed_prec(i64::exact_from(kv), wprec).0,
wprec,
Floor,
)
.0,
wprec,
Ceiling,
);
}
let mut err = if !t.is_zero() && exp_t >= -1 {
exp_t + 3
} else {
1
};
if let Some(kv) = &k {
let exp_k = i64::exact_from(kv.significant_bits());
if exp_k > err {
err = exp_k;
}
err += 1;
}
t.exp_prec_assign(wprec);
let t_bottom_binade = t.is_finite()
&& !t.is_zero()
&& k.is_none()
&& t.get_exponent()
.is_some_and(|e| i64::from(e) == i64::from(Float::MIN_EXPONENT));
if t.is_zero() || t.is_infinite() || t_bottom_binade {
assert!(k.is_none());
if t.is_zero() {
(result, o) = pow_underflow(prec, if rm == Nearest { Down } else { rm }, false);
break;
}
if t.is_infinite() {
let t2 = abs_x
.ln_prec_round_ref(wprec, if y.is_sign_negative() { Ceiling } else { Floor })
.0
.mul_prec_round_val_ref(y, wprec, Floor)
.0
.exp_prec_round(wprec, Floor)
.0;
if t2.is_infinite() {
fail_on_untested_path("pow_general, confirmed overflow");
(result, o) = pow_overflow(prec, rm, false);
break;
}
}
k = Some(
Integer::rounding_from(
abs_x.log_base_2_prec_ref(64).0.mul_prec_val_ref(y, 64).0,
Nearest,
)
.0,
);
continue;
}
if float_can_round(
t.significand_ref().unwrap(),
wprec.checked_sub(u64::saturating_from(err)).unwrap_or(1),
prec,
rm,
) {
(result, o) = Float::from_float_prec_round(t, prec, rm);
break;
}
if !check_exact_case && !y_is_integer {
if let Some((z, oz)) = pow_is_exact(&abs_x, y, prec, rm) {
result = z;
o = oz;
exact_case = true;
break;
}
check_exact_case = true;
}
wprec += wprec >> 1;
}
if !exact_case && let Some(kv) = &k {
let lk = i64::exact_from(kv);
let mut shift_rm = rm;
if rm == Nearest
&& o == Less
&& lk < 0
&& result
.get_exponent()
.is_some_and(|e| i64::from(e) == i64::from(Float::MIN_EXPONENT) - 1 - lk)
&& raw_power_of_2(&result)
{
shift_rm = Ceiling;
}
let (shifted, oo) = result.shl_prec_round(lk, prec, shift_rm);
result = shifted;
if oo != Equal {
o = oo;
}
}
if neg_result {
result.neg_assign();
o = o.reverse();
}
(result, o)
}
fn float_to_odd_mantissa_and_exponent(x: &Float) -> (Integer, i64) {
let (n, d) = float_to_odd_mantissa_and_exponent_natural(&x.abs());
(Integer::from_sign_and_abs(x.is_sign_positive(), n), d)
}
fn float_to_odd_mantissa_and_exponent_natural(x: &Float) -> (Natural, i64) {
let m = x.significand_ref().unwrap().clone();
let e = i64::from(x.get_exponent().unwrap()) - i64::exact_from(m.significant_bits());
let tz = m.trailing_zeros().unwrap();
(m >> tz, e + i64::exact_from(tz))
}
fn pow_exponent_at_least(x: &Float, z: &Integer, bound: i64) -> bool {
let (a, b) = float_to_odd_mantissa_and_exponent_natural(&x.abs());
debug_assert!(a > 1u32);
let ar = Rational::from(a);
let zr = Rational::from(z);
let br = Rational::from(b);
let bound_r = Rational::from(bound);
let z_pos = *z > 0u32;
let mut wprec = 128;
loop {
let (l_lo, l_hi) = log_2_rational_brackets(&ar, wprec);
let (t_lo, t_hi) = if z_pos {
(&zr * (&br + l_lo), &zr * (&br + l_hi))
} else {
(&zr * (&br + l_hi), &zr * (&br + l_lo))
};
if t_lo >= bound_r {
return true;
}
if t_hi < bound_r {
return false;
}
wprec <<= 1;
}
}
fn float_sliver_of_one(x: &Float) -> Option<Rational> {
let ex = i64::from(x.get_exponent().unwrap());
if (ex == 0 || ex == 1)
&& x.get_prec().unwrap() >= u64::exact_from(-i64::from(Float::MIN_EXPONENT) - 8)
{
let xr = Rational::exact_from(x);
let d = (&xr).abs() - Rational::ONE;
if d != 0u32 && d.floor_log_base_2_abs() < i64::from(Float::MIN_EXPONENT) + 8 {
return Some(xr);
}
}
None
}
impl Float {
pub fn pow_prec_round_ref_ref(
&self,
y: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if rm == Exact {
let (result, o) = self.pow_prec_ref_ref(y, prec);
assert_eq!(o, Equal, "Inexact pow");
return (result, Equal);
}
let x = self;
match (x, y) {
(_, float_either_zero!()) => {
return (Self::one_prec(prec), Equal);
}
(float_nan!(), _) => return (Self::NAN, Equal),
(_, float_nan!()) => {
return if *x == 1u32 {
(Self::one_prec(prec), Equal)
} else {
(Self::NAN, Equal)
};
}
(float_either_infinity!(), Self(Infinity { sign })) => {
return if *sign {
(Self::INFINITY, Equal)
} else {
(Self::ZERO, Equal)
};
}
(_, Self(Infinity { sign })) => {
let mut cmp = x.partial_cmp_abs(&Self::ONE).unwrap();
if !*sign {
cmp = cmp.reverse();
}
return match cmp {
Greater => (Self::INFINITY, Equal),
Less => (Self::ZERO, Equal),
Equal => (Self::one_prec(prec), Equal),
};
}
(Self(Infinity { sign }), _) => {
let negative = !*sign && float_odd_integer(y);
return (
match (y.is_sign_positive(), negative) {
(true, false) => Self::INFINITY,
(true, true) => Self::NEGATIVE_INFINITY,
(false, false) => Self::ZERO,
(false, true) => Self::NEGATIVE_ZERO,
},
Equal,
);
}
(Self(Zero { sign }), _) => {
let negative = !*sign && float_odd_integer(y);
return (
match (y.is_sign_negative(), negative) {
(true, false) => Self::INFINITY,
(true, true) => Self::NEGATIVE_INFINITY,
(false, false) => Self::ZERO,
(false, true) => Self::NEGATIVE_ZERO,
},
Equal,
);
}
_ => {}
}
let y_is_integer = y.is_integer();
if x.is_sign_negative() && !y_is_integer {
return (Self::NAN, Equal);
}
let cmp_x_1 = x.partial_cmp_abs(&Self::ONE).unwrap();
if cmp_x_1 == Equal {
let negative = x.is_sign_negative() && float_odd_integer(y);
return Self::from_float_prec_round(
if negative { -Self::ONE } else { Self::ONE },
prec,
rm,
);
}
if let Some(xr) = float_sliver_of_one(x) {
return Self::rational_pow_prec_round_val_ref(xr, y, prec, rm);
}
let ex = i64::from(x.get_exponent().unwrap());
let ey = i64::from(y.get_exponent().unwrap());
let no_over_under = ey <= 15 && -32767 < ex && ex <= 32767;
if !no_over_under {
if (cmp_x_1 == Greater) == y.is_sign_positive() {
let t = x
.abs()
.log_base_2_prec_round_ref(64, Down)
.0
.mul_prec_round_val_ref(y, 64, Down)
.0;
if t >= const { Self::const_from_signed(Self::MAX_EXPONENT as SignedLimb) } {
return pow_overflow(prec, rm, x.is_sign_negative() && float_odd_integer(y));
}
}
if if y.is_sign_negative() { ex > 1 } else { ex < 0 } {
let mut tmp = Self::from_signed_prec(ex, 64).0;
if y.is_sign_negative() {
tmp.sub_prec_assign(Self::ONE, 64);
}
tmp.mul_prec_round_assign_ref(y, 64, Ceiling);
let mut ebound = i64::rounding_from(&tmp, Ceiling).0;
if y.is_sign_negative() && tmp == ebound {
ebound += 1;
}
let lim = i64::from(Self::MIN_EXPONENT) - if rm == Nearest { 2 } else { 1 };
if ebound <= lim {
return pow_underflow(
prec,
if rm == Nearest { Down } else { rm },
x.is_sign_negative() && float_odd_integer(y),
);
}
}
}
if y_is_integer && ey <= POW_EXP_THRESHOLD {
return pow_integer(x, &Integer::rounding_from(y, Nearest).0, prec, rm);
}
if raw_power_of_2(x) {
if x.is_sign_negative() {
let negative = float_odd_integer(y);
return pow_underflow(prec, if rm == Nearest { Down } else { rm }, negative);
}
let b = ex - 1;
let (tmp, o) = y.mul_prec_ref_val(Self::from(b), y.significant_bits() + 64);
assert_eq!(o, Equal);
return Self::power_of_2_of_float_prec_round(tmp, prec, rm);
}
let expx = if cmp_x_1 == Less { 1 - ex } else { ex };
let logt = i64::exact_from(u64::exact_from(expx.max(1)).ceiling_log_base_2());
let err = ey + logt;
if err < -i64::exact_from(prec) - 1 {
let above = y.is_sign_positive() == (cmp_x_1 == Greater);
return float_one_plus_tiny(prec, rm, above);
}
pow_general(x, y, prec, rm, y_is_integer)
}
}
impl Float {
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_prec_round(self, other: Self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.pow_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
pub fn pow_prec_round_val_ref(
self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round_ref_ref(other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_prec_round_ref_val(
&self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round_ref_ref(&other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_prec(self, other: Self, prec: u64) -> (Self, Ordering) {
self.pow_prec_ref_ref(&other, prec)
}
#[inline]
pub fn pow_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
self.pow_prec_round_ref_ref(other, prec, Nearest)
}
#[allow(clippy::needless_pass_by_value)]
pub fn pow_round(self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_round_ref_ref(&other, prec, rm)
}
pub fn pow_round_ref_ref(&self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_round_ref_ref(other, prec, rm)
}
#[inline]
pub fn pow_round_val_ref(self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
self.pow_round_ref_ref(other, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_round_ref_val(&self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
self.pow_round_ref_ref(&other, rm)
}
#[inline]
pub fn pow_prec_val_ref(self, other: &Self, prec: u64) -> (Self, Ordering) {
self.pow_prec_ref_ref(other, prec)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_prec_ref_val(&self, other: Self, prec: u64) -> (Self, Ordering) {
self.pow_prec_ref_ref(&other, prec)
}
#[allow(clippy::needless_pass_by_value)]
pub fn pow_prec_round_assign(&mut self, other: Self, prec: u64, rm: RoundingMode) -> Ordering {
let (result, o) = self.pow_prec_round_ref_ref(&other, prec, rm);
*self = result;
o
}
pub fn pow_prec_round_assign_ref(
&mut self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (result, o) = self.pow_prec_round_ref_ref(other, prec, rm);
*self = result;
o
}
#[inline]
pub fn pow_prec_assign(&mut self, other: Self, prec: u64) -> Ordering {
self.pow_prec_round_assign(other, prec, Nearest)
}
#[inline]
pub fn pow_prec_assign_ref(&mut self, other: &Self, prec: u64) -> Ordering {
self.pow_prec_round_assign_ref(other, prec, Nearest)
}
pub fn pow_round_assign(&mut self, other: Self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_round_assign(other, prec, rm)
}
pub fn pow_round_assign_ref(&mut self, other: &Self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_round_assign_ref(other, prec, rm)
}
}
impl Pow<Self> for Float {
type Output = Self;
fn pow(self, other: Self) -> Self {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_ref_ref(&other, prec).0
}
}
impl Pow<&Self> for Float {
type Output = Self;
fn pow(self, other: &Self) -> Self {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_ref_ref(other, prec).0
}
}
impl Pow<Float> for &Float {
type Output = Float;
fn pow(self, other: Float) -> Float {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_ref_ref(&other, prec).0
}
}
impl Pow<&Float> for &Float {
type Output = Float;
fn pow(self, other: &Float) -> Float {
let prec = self.significant_bits().max(other.significant_bits());
self.pow_prec_ref_ref(other, prec).0
}
}
impl PowAssign<Self> for Float {
fn pow_assign(&mut self, other: Self) {
let prec = self.significant_bits().max(other.significant_bits());
*self = self.pow_prec_ref_ref(&other, prec).0;
}
}
impl PowAssign<&Self> for Float {
fn pow_assign(&mut self, other: &Self) {
let prec = self.significant_bits().max(other.significant_bits());
*self = self.pow_prec_ref_ref(other, prec).0;
}
}
fn integer_to_exact_float(z: Integer) -> Float {
let prec = z.significant_bits().max(1);
Float::from_integer_prec_round(z, prec, Exact).0
}
impl Float {
#[inline]
pub fn pow_integer_prec_round(
self,
other: Integer,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round(integer_to_exact_float(other), prec, rm)
}
#[inline]
pub fn pow_integer_prec_round_val_ref(
self,
other: &Integer,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round(integer_to_exact_float(other.clone()), prec, rm)
}
#[inline]
pub fn pow_integer_prec_round_ref_val(
&self,
other: Integer,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round_ref_val(integer_to_exact_float(other), prec, rm)
}
#[inline]
pub fn pow_integer_prec_round_ref_ref(
&self,
other: &Integer,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.pow_prec_round_ref_val(integer_to_exact_float(other.clone()), prec, rm)
}
#[inline]
pub fn pow_integer_prec(self, other: Integer, prec: u64) -> (Self, Ordering) {
self.pow_integer_prec_round(other, prec, Nearest)
}
#[inline]
pub fn pow_integer_prec_val_ref(self, other: &Integer, prec: u64) -> (Self, Ordering) {
self.pow_integer_prec_round_val_ref(other, prec, Nearest)
}
#[inline]
pub fn pow_integer_prec_ref_val(&self, other: Integer, prec: u64) -> (Self, Ordering) {
self.pow_integer_prec_round_ref_val(other, prec, Nearest)
}
#[inline]
pub fn pow_integer_prec_ref_ref(&self, other: &Integer, prec: u64) -> (Self, Ordering) {
self.pow_integer_prec_round_ref_ref(other, prec, Nearest)
}
#[inline]
pub fn pow_integer_round(self, other: Integer, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_integer_prec_round(other, prec, rm)
}
#[inline]
pub fn pow_integer_round_val_ref(self, other: &Integer, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_integer_prec_round_val_ref(other, prec, rm)
}
#[inline]
pub fn pow_integer_round_ref_val(&self, other: Integer, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_integer_prec_round_ref_val(other, prec, rm)
}
#[inline]
pub fn pow_integer_round_ref_ref(&self, other: &Integer, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_integer_prec_round_ref_ref(other, prec, rm)
}
#[inline]
pub fn pow_integer_prec_round_assign(
&mut self,
other: Integer,
prec: u64,
rm: RoundingMode,
) -> Ordering {
self.pow_prec_round_assign(integer_to_exact_float(other), prec, rm)
}
#[inline]
pub fn pow_integer_prec_round_assign_ref(
&mut self,
other: &Integer,
prec: u64,
rm: RoundingMode,
) -> Ordering {
self.pow_prec_round_assign(integer_to_exact_float(other.clone()), prec, rm)
}
#[inline]
pub fn pow_integer_prec_assign(&mut self, other: Integer, prec: u64) -> Ordering {
self.pow_prec_assign(integer_to_exact_float(other), prec)
}
#[inline]
pub fn pow_integer_prec_assign_ref(&mut self, other: &Integer, prec: u64) -> Ordering {
self.pow_prec_assign(integer_to_exact_float(other.clone()), prec)
}
pub fn pow_integer_round_assign(&mut self, other: Integer, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.pow_prec_round_assign(integer_to_exact_float(other), prec, rm)
}
pub fn pow_integer_round_assign_ref(&mut self, other: &Integer, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.pow_prec_round_assign(integer_to_exact_float(other.clone()), prec, rm)
}
}
impl Pow<Integer> for Float {
type Output = Self;
#[inline]
fn pow(self, other: Integer) -> Self {
let prec = self.significant_bits();
self.pow_integer_prec(other, prec).0
}
}
impl Pow<&Integer> for Float {
type Output = Self;
#[inline]
fn pow(self, other: &Integer) -> Self {
let prec = self.significant_bits();
self.pow_integer_prec_val_ref(other, prec).0
}
}
impl Pow<Integer> for &Float {
type Output = Float;
#[inline]
fn pow(self, other: Integer) -> Float {
let prec = self.significant_bits();
self.pow_integer_prec_ref_val(other, prec).0
}
}
impl Pow<&Integer> for &Float {
type Output = Float;
#[inline]
fn pow(self, other: &Integer) -> Float {
let prec = self.significant_bits();
self.pow_integer_prec_ref_ref(other, prec).0
}
}
impl PowAssign<Integer> for Float {
#[inline]
fn pow_assign(&mut self, other: Integer) {
let prec = self.significant_bits();
self.pow_integer_prec_assign(other, prec);
}
}
impl PowAssign<&Integer> for Float {
#[inline]
fn pow_assign(&mut self, other: &Integer) {
let prec = self.significant_bits();
self.pow_integer_prec_assign_ref(other, prec);
}
}
impl Float {
#[inline]
pub fn pow_u_prec_round(self, n: u64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
pow_u(self, n, prec, rm)
}
#[inline]
pub fn pow_u_prec_round_ref(&self, n: u64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
pow_u_ref(self, n, prec, rm)
}
#[inline]
pub fn pow_u_prec(self, n: u64, prec: u64) -> (Self, Ordering) {
pow_u(self, n, prec, Nearest)
}
#[inline]
pub fn pow_u_prec_ref(&self, n: u64, prec: u64) -> (Self, Ordering) {
pow_u_ref(self, n, prec, Nearest)
}
#[inline]
pub fn pow_u_round(self, n: u64, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
pow_u(self, n, prec, rm)
}
#[inline]
pub fn pow_u_round_ref(&self, n: u64, rm: RoundingMode) -> (Self, Ordering) {
pow_u_ref(self, n, self.significant_bits(), rm)
}
pub fn pow_u_prec_round_assign(&mut self, n: u64, prec: u64, rm: RoundingMode) -> Ordering {
let mut x = Self::ZERO;
swap(self, &mut x);
let (result, o) = pow_u(x, n, prec, rm);
*self = result;
o
}
#[inline]
pub fn pow_u_prec_assign(&mut self, n: u64, prec: u64) -> Ordering {
self.pow_u_prec_round_assign(n, prec, Nearest)
}
#[inline]
pub fn pow_u_round_assign(&mut self, n: u64, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.pow_u_prec_round_assign(n, prec, rm)
}
}
impl Pow<u64> for Float {
type Output = Self;
#[inline]
fn pow(self, n: u64) -> Self {
let prec = self.significant_bits();
pow_u(self, n, prec, Nearest).0
}
}
impl Pow<u64> for &Float {
type Output = Float;
#[inline]
fn pow(self, n: u64) -> Float {
pow_u_ref(self, n, self.significant_bits(), Nearest).0
}
}
impl PowAssign<u64> for Float {
#[inline]
fn pow_assign(&mut self, n: u64) {
let prec = self.significant_bits();
self.pow_u_prec_assign(n, prec);
}
}
impl Float {
#[inline]
pub fn pow_s_prec_round(self, n: i64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
pow_s(self, n, prec, rm)
}
#[inline]
pub fn pow_s_prec_round_ref(&self, n: i64, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
pow_s_ref(self, n, prec, rm)
}
#[inline]
pub fn pow_s_prec(self, n: i64, prec: u64) -> (Self, Ordering) {
pow_s(self, n, prec, Nearest)
}
#[inline]
pub fn pow_s_prec_ref(&self, n: i64, prec: u64) -> (Self, Ordering) {
pow_s_ref(self, n, prec, Nearest)
}
#[inline]
pub fn pow_s_round(self, n: i64, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
pow_s(self, n, prec, rm)
}
#[inline]
pub fn pow_s_round_ref(&self, n: i64, rm: RoundingMode) -> (Self, Ordering) {
pow_s_ref(self, n, self.significant_bits(), rm)
}
pub fn pow_s_prec_round_assign(&mut self, n: i64, prec: u64, rm: RoundingMode) -> Ordering {
let mut x = Self::ZERO;
swap(self, &mut x);
let (result, o) = pow_s(x, n, prec, rm);
*self = result;
o
}
#[inline]
pub fn pow_s_prec_assign(&mut self, n: i64, prec: u64) -> Ordering {
self.pow_s_prec_round_assign(n, prec, Nearest)
}
#[inline]
pub fn pow_s_round_assign(&mut self, n: i64, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.pow_s_prec_round_assign(n, prec, rm)
}
}
impl Pow<i64> for Float {
type Output = Self;
#[inline]
fn pow(self, n: i64) -> Self {
let prec = self.significant_bits();
pow_s(self, n, prec, Nearest).0
}
}
impl Pow<i64> for &Float {
type Output = Float;
#[inline]
fn pow(self, n: i64) -> Float {
pow_s_ref(self, n, self.significant_bits(), Nearest).0
}
}
impl PowAssign<i64> for Float {
#[inline]
fn pow_assign(&mut self, n: i64) {
let prec = self.significant_bits();
self.pow_s_prec_assign(n, prec);
}
}
impl Float {
#[inline]
pub fn unsigned_pow_unsigned_prec_round(
x: u64,
y: u64,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
unsigned_pow_unsigned(x, y, prec, rm)
}
#[inline]
pub fn unsigned_pow_unsigned_prec(x: u64, y: u64, prec: u64) -> (Self, Ordering) {
unsigned_pow_unsigned(x, y, prec, Nearest)
}
#[inline]
pub fn unsigned_pow_prec_round(
x: u64,
y: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::from(x).pow_prec_round(y, prec, rm)
}
#[inline]
pub fn unsigned_pow_prec_round_ref(
x: u64,
y: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::from(x).pow_prec_round_val_ref(y, prec, rm)
}
#[inline]
pub fn unsigned_pow_prec(x: u64, y: Self, prec: u64) -> (Self, Ordering) {
Self::unsigned_pow_prec_round(x, y, prec, Nearest)
}
#[inline]
pub fn unsigned_pow_prec_ref(x: u64, y: &Self, prec: u64) -> (Self, Ordering) {
Self::unsigned_pow_prec_round_ref(x, y, prec, Nearest)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn unsigned_pow_rational_prec_round(
x: u64,
y: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
unsigned_pow_rational(x, &y, prec, rm)
}
#[inline]
pub fn unsigned_pow_rational_prec_round_ref(
x: u64,
y: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
unsigned_pow_rational(x, y, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn unsigned_pow_rational_prec(x: u64, y: Rational, prec: u64) -> (Self, Ordering) {
unsigned_pow_rational(x, &y, prec, Nearest)
}
#[inline]
pub fn unsigned_pow_rational_prec_ref(x: u64, y: &Rational, prec: u64) -> (Self, Ordering) {
unsigned_pow_rational(x, y, prec, Nearest)
}
}
fn unsigned_pow_rational(k: u64, q: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(prec, 0);
if rm == Exact {
let (result, o) = unsigned_pow_rational(k, q, prec, Floor);
assert_eq!(o, Equal, "Inexact unsigned_pow_rational");
return (result, Equal);
}
if *q == 0u32 || k == 1 {
return (Float::one_prec(prec), Equal);
}
if k == 0 {
return if *q > 0u32 {
(Float::ZERO, Equal)
} else {
(Float::INFINITY, Equal)
};
}
if k.is_power_of_2() {
return Float::power_of_2_rational_prec_round(
Rational::from(k.trailing_zeros()) * q,
prec,
rm,
);
}
if let Ok(b) = u64::try_from(q.denominator_ref())
&& let Some(j) = k.checked_root(b)
{
let a = Integer::from_sign_and_abs_ref(*q >= 0, q.numerator_ref());
return Float::from(j).pow_integer_prec_round(a, prec, rm);
}
if let Some(result) = unsigned_pow_rational_near_one(k, q, prec, rm) {
return result;
}
pow_squeeze_t(&Rational::from(k), 0, q, prec, rm)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_pow<T: PrimitiveFloat>(x: T, y: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_float_to_float_fn(Float::pow_prec, x, y)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_rational_pow<T: PrimitiveFloat>(x: &Rational, y: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|y2, prec| Float::rational_pow_prec_ref_val(x, y2, prec), y)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_pow_rational<T: PrimitiveFloat>(x: T, y: &Rational) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|x, prec| Float::pow_rational_prec_val_ref(x, y, prec), x)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_pow_integer<T: PrimitiveFloat>(x: T, y: &Integer) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|x, prec| Float::pow_integer_prec_val_ref(x, y, prec), x)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_pow_u<T: PrimitiveFloat>(x: T, n: u64) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|x, prec| x.pow_u_prec(n, prec), x)
}
#[allow(clippy::type_repetition_in_bounds)]
#[inline]
pub fn primitive_float_unsigned_pow<T: PrimitiveFloat>(x: u64, y: T) -> T
where
Float: From<T> + PartialOrd<T>,
for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
{
emulate_float_to_float_fn(|y2, prec| Float::unsigned_pow_prec(x, y2, prec), y)
}
fn rational_mantissa_nearest_power_of_2(x: &Rational) -> (Rational, i64) {
let fl = x.floor_log_base_2_abs();
let mant = x >> fl;
let g = if (&mant).square() < 2u32 { fl } else { fl + 1 };
(x >> g, g)
}
fn rational_pow_exact_decomposition(
a: &Natural,
b: &Natural,
e: i64,
y: &Float,
) -> Option<(Natural, Integer, Integer)> {
let (c, d) = float_to_odd_mantissa_and_exponent(y);
let (mut a, mut b) = (a.clone(), b.clone());
let mut e = Integer::from(e);
if d < 0 {
for _ in 0..-d {
if a != 1u32 {
a = a.checked_sqrt()?;
}
if b != 1u32 {
b = b.checked_sqrt()?;
}
if e.odd() {
return None;
}
e >>= 1;
}
} else {
e <<= d;
}
let pow = e * &c;
let m = if c > 0u32 {
if b != 1u32 {
return None;
}
a
} else {
if a != 1u32 {
return None;
}
b
};
let mut z = Integer::from(c.unsigned_abs());
if d > 0 {
z <<= d;
}
Some((m, z, pow))
}
fn rational_pow_squeeze_x(
x: &Rational,
y: &Float,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let mut wprec = prec.saturating_add(TWICE_WIDTH);
let mut increment = Limb::WIDTH;
loop {
let x_lo = Float::from_rational_prec_round_ref(x, wprec, Floor).0;
let x_hi = Float::from_rational_prec_round_ref(x, wprec, Ceiling).0;
let (p_lo, mut o_lo) = x_lo.pow_prec_round_val_ref(y, prec, rm);
let (p_hi, mut o_hi) = x_hi.pow_prec_round_val_ref(y, prec, rm);
if o_lo == Equal {
o_lo = o_hi;
}
if o_hi == Equal {
o_hi = o_lo;
}
if o_lo == o_hi && p_lo == p_hi {
return (p_lo, o_lo);
}
wprec += increment;
increment = wprec >> 1;
}
}
fn unsigned_pow_rational_near_one(
k: u64,
q: &Rational,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let ql = q.floor_log_base_2_abs();
let kbb = i64::exact_from(k.significant_bits().significant_bits());
let t_exp_ub = ql + 1 + kbb;
if t_exp_ub >= 0 || t_exp_ub > -i64::exact_from(prec) + i64::exact_from(Limb::WIDTH) {
return None;
}
let above = *q > 0u32;
let mut working_prec = u64::saturating_from(i64::exact_from(prec) + t_exp_ub) + Limb::WIDTH;
let mut increment = Limb::WIDTH;
let kf = Float::from(k);
loop {
let (ln_k_lo, ln_k_hi) = floor_and_ceiling(kf.ln_prec_round_ref(working_prec, Floor));
let ln_k_lo = Rational::exact_from(&ln_k_lo);
let ln_k_hi = Rational::exact_from(&ln_k_hi);
let (p_lo, p_hi) = if above {
(q * ln_k_lo, q * ln_k_hi)
} else {
(q * ln_k_hi, q * ln_k_lo)
};
let (lo, o_lo) = exp_rational_near_one(&p_lo, prec, rm);
let (hi, o_hi) = exp_rational_near_one(&p_hi, prec, rm);
if o_lo == o_hi && lo == hi {
return Some((lo, o_lo));
}
working_prec += increment;
increment = working_prec >> 1;
}
}
fn pow_squeeze_t(
xp: &Rational,
e: i64,
y: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let er = Rational::from(e);
let mut wprec = prec.saturating_add(TWICE_WIDTH);
let mut increment = Limb::WIDTH;
loop {
let (l_lo, l_hi) = log_2_rational_brackets(xp, wprec);
let (t_lo, t_hi) = if *y > 0u32 {
(y * (&er + l_lo), y * (&er + l_hi))
} else {
(y * (&er + l_hi), y * (&er + l_lo))
};
let (p_lo, mut o_lo) = Float::power_of_2_rational_prec_round(t_lo, prec, rm);
let (p_hi, mut o_hi) = Float::power_of_2_rational_prec_round(t_hi, prec, rm);
if o_lo == Equal {
fail_on_untested_path(
"pow_squeeze_t, lo_eq: exact results (t an integer) are caught by each caller's \
exact decomposition before the squeeze, so t is never an integer here; a bracket \
end equalling an integer is a measure-zero coincidence of the log brackets",
);
o_lo = o_hi;
}
if o_hi == Equal {
fail_on_untested_path(
"pow_squeeze_t, hi_eq: as lo_eq -- t is never an integer in the squeeze, so a \
bracket end equalling one is a measure-zero coincidence",
);
o_hi = o_lo;
}
if o_lo == o_hi && p_lo == p_hi {
return (p_lo, o_lo);
}
wprec += increment;
increment = wprec >> 1;
}
}
fn rational_pow_exact(
m: &Natural,
z: &Integer,
pow: &Integer,
prec: u64,
rm: RoundingMode,
) -> Option<(Float, Ordering)> {
let zu = u64::try_from(z).ok()?;
debug_assert!(*m > 1u32 && m.odd());
let bits_lower = (m.significant_bits() - 1).checked_mul(zu)?.checked_add(1)?;
if bits_lower > prec + 2 {
return None;
}
let value = m.clone().pow(zu);
let (result, o) = Float::from_natural_prec_round(value, prec, rm);
let Ok(shift) = i64::try_from(pow) else {
return Some(if *pow > 0u32 {
fail_on_untested_path(
"rational_pow, ex_pow_overflow: reachable only with a base whose 2-adic \
valuation exceeds i64::MAX / prec while its odd part fits in prec + 2 bits -- \
simultaneously a ~512-MB base and a ~2^31 precision, beyond practical test \
sizes",
);
exp_overflow(prec, rm)
} else {
fail_on_untested_path(
"rational_pow, ex_pow_underflow: as ex_pow_overflow, in the negative-exponent \
direction",
);
exp_underflow(prec, if rm == Nearest { Down } else { rm })
});
};
let (shifted, oo) = result.shl_prec_round(shift, prec, rm);
Some((shifted, if oo == Equal { o } else { oo }))
}
fn rational_odd_integer(y: &Rational) -> bool {
*y.denominator_ref() == 1u32 && y.numerator_ref().odd()
}
fn positive_float_pow_rational(
x: &Float,
y: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
let (c, d) = float_to_odd_mantissa_and_exponent_natural(x);
if c == 1u32 {
return Float::power_of_2_rational_prec_round(Rational::from(d) * y, prec, rm);
}
if let Ok(b) = u64::try_from(y.denominator_ref())
&& d.unsigned_abs().divisible_by(b)
&& let Some(j) = (&c).checked_root(b)
{
let base = Float::exact_from(j) << (d / i64::exact_from(b));
let a = Integer::from_sign_and_abs_ref(*y > 0u32, y.numerator_ref());
return base.pow_integer_prec_round(a, prec, rm);
}
let ex = i64::from(x.get_exponent().unwrap());
let ey = y.floor_log_base_2_abs() + 1;
let above = (*y > 0u32) == (*x > 1u32);
let expb = if ex == 0 || ex == 1 {
(Rational::exact_from(x) - Rational::ONE).floor_log_base_2_abs() + 2
} else {
let expx = if ex > 1 { ex } else { 1 - ex };
i64::exact_from(u64::exact_from(expx).ceiling_log_base_2())
};
if ey + expb < -i64::exact_from(prec) - 1 {
return float_one_plus_tiny(prec, rm, above);
}
pow_squeeze_t(&Rational::from(c), d, y, prec, rm)
}
fn float_rational_pow(x: &Float, y: &Rational, prec: u64, rm: RoundingMode) -> (Float, Ordering) {
assert_ne!(prec, 0);
if rm == Exact {
let (result, o) = float_rational_pow(x, y, prec, Nearest);
assert_eq!(o, Equal, "Inexact pow");
return (result, Equal);
}
if *y == 0u32 {
return (Float::one_prec(prec), Equal);
}
match x {
float_nan!() => return (Float::NAN, Equal),
Float(Infinity { sign }) => {
let negative = !*sign && rational_odd_integer(y);
return (
match (*y > 0u32, negative) {
(true, false) => Float::INFINITY,
(true, true) => Float::NEGATIVE_INFINITY,
(false, false) => Float::ZERO,
(false, true) => Float::NEGATIVE_ZERO,
},
Equal,
);
}
Float(Zero { sign }) => {
let negative = !*sign && rational_odd_integer(y);
return (
match (*y < 0u32, negative) {
(true, false) => Float::INFINITY,
(true, true) => Float::NEGATIVE_INFINITY,
(false, false) => Float::ZERO,
(false, true) => Float::NEGATIVE_ZERO,
},
Equal,
);
}
_ => {}
}
let y_is_integer = *y.denominator_ref() == 1u32;
if x.is_sign_negative() && !y_is_integer {
return (Float::NAN, Equal);
}
if x.partial_cmp_abs(&Float::ONE).unwrap() == Equal {
let negative = x.is_sign_negative() && rational_odd_integer(y);
return Float::from_float_prec_round(
if negative { -Float::ONE } else { Float::ONE },
prec,
rm,
);
}
if y_is_integer {
return pow_integer(x, &Integer::rounding_from(y, Exact).0, prec, rm);
}
positive_float_pow_rational(x, y, prec, rm)
}
fn rational_rational_pow_exact_decomposition(
a: &Natural,
b: &Natural,
e: i64,
y: &Rational,
) -> Option<(Natural, Integer, Integer)> {
let b_y = u64::try_from(y.denominator_ref()).ok()?;
if !e.unsigned_abs().divisible_by(b_y) {
return None;
}
let p = a.checked_root(b_y)?;
let q = b.checked_root(b_y)?;
let a_y_abs = y.numerator_ref();
let pow = Integer::from(e / i64::exact_from(b_y))
* Integer::from_sign_and_abs_ref(*y > 0u32, a_y_abs);
if *y > 0u32 {
if q != 1u32 {
return None;
}
Some((p, Integer::from(a_y_abs), pow))
} else {
if p != 1u32 {
return None;
}
Some((q, Integer::from(a_y_abs), pow))
}
}
fn rational_rational_pow(
x: &Rational,
y: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Float, Ordering) {
assert_ne!(prec, 0);
if rm == Exact {
let (result, o) = rational_rational_pow(x, y, prec, Nearest);
assert_eq!(o, Equal, "Inexact rational_rational_pow");
return (result, Equal);
}
if *y == 0u32 {
return (Float::one_prec(prec), Equal);
}
if *x == 0u32 {
return if *y > 0u32 {
(Float::ZERO, Equal)
} else {
(Float::INFINITY, Equal)
};
}
let y_is_integer = *y.denominator_ref() == 1u32;
if *x < 0u32 {
if !y_is_integer {
return (Float::NAN, Equal);
}
let negative = rational_odd_integer(y);
let (result, o) = rational_rational_pow(&(-x), y, prec, if negative { -rm } else { rm });
return if negative {
(-result, o.reverse())
} else {
(result, o)
};
}
if *x == 1u32 {
return (Float::one_prec(prec), Equal);
}
if let Some(e) = x.checked_log_base_2() {
let t = Rational::from(e) * y;
return Float::power_of_2_rational_prec_round(t, prec, rm);
}
let nbits = x.significant_bits();
if y_is_integer
&& let Ok(z) = i64::try_from(y.numerator_ref())
&& z.unsigned_abs().saturating_mul(nbits) <= max(65536, prec << 2)
{
let z = if *y > 0u32 { z } else { -z };
return Float::from_rational_prec_round(x.pow(z), prec, rm);
}
let fl = x.floor_log_base_2_abs();
let in_range =
fl > i64::from(Float::MIN_EXPONENT) + 2 && fl < i64::from(Float::MAX_EXPONENT) - 2;
let sliver_fld = if fl == 0 || fl == -1 {
Some((x - Rational::ONE).floor_log_base_2_abs())
} else {
None
};
let sliver_of_one = sliver_fld.is_some_and(|fld| fld < i64::from(Float::MIN_EXPONENT) + 8);
if in_range && !sliver_of_one && x.denominator_ref().is_power_of_2() {
let xf = Float::from_rational_prec_round_ref(x, nbits, Floor).0;
return xf.pow_rational_prec_round_val_ref(y, prec, rm);
}
let n = x.numerator_ref();
let d = x.denominator_ref();
let alpha = i64::exact_from(n.trailing_zeros().unwrap());
let beta = i64::exact_from(d.trailing_zeros().unwrap());
let a = n >> alpha;
let b = d >> beta;
if let Some((m, z, pow)) = rational_rational_pow_exact_decomposition(&a, &b, alpha - beta, y)
&& let Some(result) = rational_pow_exact(&m, &z, &pow, prec, rm)
{
return result;
}
if let Some(fld) = sliver_fld {
let ey = y.floor_log_base_2_abs() + 1;
if ey + fld + 2 < -i64::exact_from(prec) - 1 {
let above = (*y > 0u32) == (*x > 1u32);
return float_one_plus_tiny(prec, rm, above);
}
}
let xp = Rational::from(a) / Rational::from(b);
pow_squeeze_t(&xp, alpha - beta, y, prec, rm)
}
impl Float {
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn rational_pow_rational_prec_round(
x: Rational,
y: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
rational_rational_pow(&x, &y, prec, rm)
}
#[inline]
pub fn rational_pow_rational_prec_round_ref(
x: &Rational,
y: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
rational_rational_pow(x, y, prec, rm)
}
#[inline]
#[allow(clippy::needless_pass_by_value)]
pub fn rational_pow_rational_prec(x: Rational, y: Rational, prec: u64) -> (Self, Ordering) {
rational_rational_pow(&x, &y, prec, Nearest)
}
#[inline]
pub fn rational_pow_rational_prec_ref(
x: &Rational,
y: &Rational,
prec: u64,
) -> (Self, Ordering) {
rational_rational_pow(x, y, prec, Nearest)
}
}
impl Float {
pub fn rational_pow_prec_round_ref_ref(
x: &Rational,
y: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
if rm == Exact {
let (result, o) = Self::rational_pow_prec_ref_ref(x, y, prec);
assert_eq!(o, Equal, "Inexact rational_pow");
return (result, Equal);
}
match y {
float_either_zero!() => {
return (Self::one_prec(prec), Equal);
}
float_nan!() => {
return if *x == 1u32 {
(Self::one_prec(prec), Equal)
} else {
(Self::NAN, Equal)
};
}
Self(Infinity { sign }) => {
let mut cmp = x.cmp_abs(&Rational::ONE);
if !*sign {
cmp = cmp.reverse();
}
return match cmp {
Greater => (Self::INFINITY, Equal),
Less => (Self::ZERO, Equal),
Equal => (Self::one_prec(prec), Equal),
};
}
_ => {}
}
if *x == 0u32 {
return if *y > 0u32 {
(Self::ZERO, Equal)
} else {
(Self::INFINITY, Equal)
};
}
let y_is_integer = y.is_integer();
if *x < 0u32 {
if !y_is_integer {
return (Self::NAN, Equal);
}
let negative = float_odd_integer(y);
let (result, o) = Self::rational_pow_prec_round_ref_ref(
&(-x),
y,
prec,
if negative { -rm } else { rm },
);
return if negative {
(-result, o.reverse())
} else {
(result, o)
};
}
if *x == 1u32 {
return (Self::one_prec(prec), Equal);
}
if let Some(e) = x.checked_log_base_2() {
let t = Rational::from(e) * Rational::exact_from(y);
return Self::power_of_2_rational_prec_round(t, prec, rm);
}
let nbits = x.significant_bits();
if y_is_integer && y.get_exponent().unwrap() <= 32 {
let z = i64::rounding_from(y, Nearest).0;
if z.unsigned_abs().saturating_mul(nbits) <= max(65536, prec << 2) {
return Self::from_rational_prec_round(x.pow(z), prec, rm);
}
}
let fl = x.floor_log_base_2_abs();
let in_range =
fl > i64::from(Self::MIN_EXPONENT) + 2 && fl < i64::from(Self::MAX_EXPONENT) - 2;
let sliver_fld = if fl == 0 || fl == -1 {
if *x == 1u32 {
None
} else {
Some((x - Rational::ONE).floor_log_base_2_abs())
}
} else {
None
};
let sliver_of_one = sliver_fld.is_some_and(|fld| fld < i64::from(Self::MIN_EXPONENT) + 8);
if in_range && !sliver_of_one && x.denominator_ref().is_power_of_2() {
let xf = Self::from_rational_prec_round_ref(x, nbits, Floor).0;
return xf.pow_prec_round_val_ref(y, prec, rm);
}
let n = x.numerator_ref();
let d = x.denominator_ref();
let alpha = i64::exact_from(n.trailing_zeros().unwrap());
let beta = i64::exact_from(d.trailing_zeros().unwrap());
let a = n >> alpha;
let b = d >> beta;
if let Some((m, z, pow)) = rational_pow_exact_decomposition(&a, &b, alpha - beta, y)
&& let Some(result) = rational_pow_exact(&m, &z, &pow, prec, rm)
{
return result;
}
if in_range && !sliver_of_one {
rational_pow_squeeze_x(x, y, prec, rm)
} else {
if let Some(fld) = sliver_fld {
let ey = i64::from(y.get_exponent().unwrap());
if ey + fld + 2 < -i64::exact_from(prec) - 1 {
let above = (*y > 0u32) == (*x > 1u32);
return float_one_plus_tiny(prec, rm, above);
}
}
let (xp, g) = rational_mantissa_nearest_power_of_2(x);
pow_squeeze_t(&xp, g, &Rational::exact_from(y), prec, rm)
}
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec_round(
x: Rational,
y: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::rational_pow_prec_round_ref_ref(&x, &y, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec_round_val_ref(
x: Rational,
y: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::rational_pow_prec_round_ref_ref(&x, y, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec_round_ref_val(
x: &Rational,
y: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
Self::rational_pow_prec_round_ref_ref(x, &y, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec(x: Rational, y: Self, prec: u64) -> (Self, Ordering) {
Self::rational_pow_prec_ref_ref(&x, &y, prec)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec_val_ref(x: Rational, y: &Self, prec: u64) -> (Self, Ordering) {
Self::rational_pow_prec_ref_ref(&x, y, prec)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn rational_pow_prec_ref_val(x: &Rational, y: Self, prec: u64) -> (Self, Ordering) {
Self::rational_pow_prec_ref_ref(x, &y, prec)
}
#[inline]
pub fn rational_pow_prec_ref_ref(x: &Rational, y: &Self, prec: u64) -> (Self, Ordering) {
Self::rational_pow_prec_round_ref_ref(x, y, prec, Nearest)
}
}
impl Float {
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_rational_prec_round(
self,
other: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
float_rational_pow(&self, &other, prec, rm)
}
#[inline]
pub fn pow_rational_prec_round_val_ref(
self,
other: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
float_rational_pow(&self, other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn pow_rational_prec_round_ref_val(
&self,
other: Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
float_rational_pow(self, &other, prec, rm)
}
#[inline]
pub fn pow_rational_prec_round_ref_ref(
&self,
other: &Rational,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
float_rational_pow(self, other, prec, rm)
}
#[inline]
pub fn pow_rational_prec(self, other: Rational, prec: u64) -> (Self, Ordering) {
self.pow_rational_prec_round(other, prec, Nearest)
}
#[inline]
pub fn pow_rational_prec_val_ref(self, other: &Rational, prec: u64) -> (Self, Ordering) {
self.pow_rational_prec_round_val_ref(other, prec, Nearest)
}
#[inline]
pub fn pow_rational_prec_ref_val(&self, other: Rational, prec: u64) -> (Self, Ordering) {
self.pow_rational_prec_round_ref_val(other, prec, Nearest)
}
#[inline]
pub fn pow_rational_prec_ref_ref(&self, other: &Rational, prec: u64) -> (Self, Ordering) {
self.pow_rational_prec_round_ref_ref(other, prec, Nearest)
}
pub fn pow_rational_round(self, other: Rational, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_rational_prec_round(other, prec, rm)
}
pub fn pow_rational_round_val_ref(
self,
other: &Rational,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_rational_prec_round_val_ref(other, prec, rm)
}
pub fn pow_rational_round_ref_val(
&self,
other: Rational,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_rational_prec_round_ref_val(other, prec, rm)
}
pub fn pow_rational_round_ref_ref(
&self,
other: &Rational,
rm: RoundingMode,
) -> (Self, Ordering) {
let prec = self.significant_bits();
self.pow_rational_prec_round_ref_ref(other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
pub fn pow_rational_prec_round_assign(
&mut self,
other: Rational,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (result, o) = float_rational_pow(self, &other, prec, rm);
*self = result;
o
}
pub fn pow_rational_prec_round_assign_ref(
&mut self,
other: &Rational,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (result, o) = float_rational_pow(self, other, prec, rm);
*self = result;
o
}
#[inline]
pub fn pow_rational_prec_assign(&mut self, other: Rational, prec: u64) -> Ordering {
self.pow_rational_prec_round_assign(other, prec, Nearest)
}
#[inline]
pub fn pow_rational_prec_assign_ref(&mut self, other: &Rational, prec: u64) -> Ordering {
self.pow_rational_prec_round_assign_ref(other, prec, Nearest)
}
pub fn pow_rational_round_assign(&mut self, other: Rational, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits();
self.pow_rational_prec_round_assign(other, prec, rm)
}
pub fn pow_rational_round_assign_ref(
&mut self,
other: &Rational,
rm: RoundingMode,
) -> Ordering {
let prec = self.significant_bits();
self.pow_rational_prec_round_assign_ref(other, prec, rm)
}
}
impl Pow<Rational> for Float {
type Output = Self;
#[inline]
fn pow(self, other: Rational) -> Self {
let prec = self.significant_bits();
self.pow_rational_prec_round(other, prec, Nearest).0
}
}
impl Pow<&Rational> for Float {
type Output = Self;
#[inline]
fn pow(self, other: &Rational) -> Self {
let prec = self.significant_bits();
self.pow_rational_prec_round_val_ref(other, prec, Nearest).0
}
}
impl Pow<Rational> for &Float {
type Output = Float;
#[inline]
fn pow(self, other: Rational) -> Float {
let prec = self.significant_bits();
self.pow_rational_prec_round_ref_val(other, prec, Nearest).0
}
}
impl Pow<&Rational> for &Float {
type Output = Float;
#[inline]
fn pow(self, other: &Rational) -> Float {
let prec = self.significant_bits();
self.pow_rational_prec_round_ref_ref(other, prec, Nearest).0
}
}
impl PowAssign<Rational> for Float {
#[inline]
fn pow_assign(&mut self, other: Rational) {
let prec = self.significant_bits();
self.pow_rational_prec_assign(other, prec);
}
}
impl PowAssign<&Rational> for Float {
#[inline]
fn pow_assign(&mut self, other: &Rational) {
let prec = self.significant_bits();
self.pow_rational_prec_assign_ref(other, prec);
}
}
impl Float {
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn powr_prec_round(self, other: Self, prec: u64, rm: RoundingMode) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(&other, prec, rm)
}
#[inline]
pub fn powr_prec_round_val_ref(
self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn powr_prec_round_ref_val(
&self,
other: Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(&other, prec, rm)
}
pub fn powr_prec_round_ref_ref(
&self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> (Self, Ordering) {
assert_ne!(prec, 0);
let x = self;
let y = other;
match (x, y) {
(Self(NaN | Finite { sign: false, .. } | Infinity { sign: false }), _)
| (Self(Zero { .. } | Infinity { sign: true }), float_either_zero!()) => {
(Self::NAN, Equal)
}
(float_negative_zero!(), Self(Finite { sign, .. })) => {
if *sign {
(Self::ZERO, Equal)
} else {
(Self::INFINITY, Equal)
}
}
(_, float_either_infinity!()) if *x == 1u32 => (Self::NAN, Equal),
_ => self.pow_prec_round_ref_ref(y, prec, rm),
}
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn powr_prec(self, other: Self, prec: u64) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(&other, prec, Nearest)
}
#[inline]
pub fn powr_prec_val_ref(self, other: &Self, prec: u64) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(other, prec, Nearest)
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn powr_prec_ref_val(&self, other: Self, prec: u64) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(&other, prec, Nearest)
}
#[inline]
pub fn powr_prec_ref_ref(&self, other: &Self, prec: u64) -> (Self, Ordering) {
self.powr_prec_round_ref_ref(other, prec, Nearest)
}
#[allow(clippy::needless_pass_by_value)]
pub fn powr_round(self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_ref_ref(&other, prec, rm)
}
pub fn powr_round_val_ref(self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_ref_ref(other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
pub fn powr_round_ref_val(&self, other: Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_ref_ref(&other, prec, rm)
}
pub fn powr_round_ref_ref(&self, other: &Self, rm: RoundingMode) -> (Self, Ordering) {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_ref_ref(other, prec, rm)
}
#[allow(clippy::needless_pass_by_value)]
pub fn powr_prec_round_assign(&mut self, other: Self, prec: u64, rm: RoundingMode) -> Ordering {
let (result, o) = self.powr_prec_round_ref_ref(&other, prec, rm);
*self = result;
o
}
pub fn powr_prec_round_assign_ref(
&mut self,
other: &Self,
prec: u64,
rm: RoundingMode,
) -> Ordering {
let (result, o) = self.powr_prec_round_ref_ref(other, prec, rm);
*self = result;
o
}
#[allow(clippy::needless_pass_by_value)]
#[inline]
pub fn powr_prec_assign(&mut self, other: Self, prec: u64) -> Ordering {
self.powr_prec_round_assign(other, prec, Nearest)
}
#[inline]
pub fn powr_prec_assign_ref(&mut self, other: &Self, prec: u64) -> Ordering {
self.powr_prec_round_assign_ref(other, prec, Nearest)
}
#[allow(clippy::needless_pass_by_value)]
pub fn powr_round_assign(&mut self, other: Self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_assign(other, prec, rm)
}
pub fn powr_round_assign_ref(&mut self, other: &Self, rm: RoundingMode) -> Ordering {
let prec = self.significant_bits().max(other.significant_bits());
self.powr_prec_round_assign_ref(other, prec, rm)
}
}