use std::num::NonZeroU32;
use num_bigint::BigInt;
use num_traits::{One, Signed};
use crate::binary::{Binary, XBinary};
pub fn binary_pow(x: &Binary, n: u32) -> Binary {
if n == 0 {
return Binary::new(BigInt::one(), BigInt::from(0));
}
let mut result = Binary::new(BigInt::one(), BigInt::from(0_i32));
let mut base = x.clone();
let mut exp = n;
while exp > 0 {
if exp & 1 == 1 {
result = result.mul(&base);
}
exp >>= 1_u32;
if exp > 0 {
base = base.mul(&base);
}
}
result
}
pub fn xbinary_pow(x: &XBinary, n: NonZeroU32) -> XBinary {
let n_val = n.get();
match x {
XBinary::NegInf => {
if n_val.is_multiple_of(2) {
XBinary::PosInf
} else {
XBinary::NegInf
}
}
XBinary::PosInf => XBinary::PosInf,
XBinary::Finite(b) => XBinary::Finite(binary_pow(b, n_val)),
}
}
pub fn xbinary_max(a: &XBinary, b: &XBinary) -> XBinary {
if a >= b { a.clone() } else { b.clone() }
}
pub fn is_negative(x: &XBinary) -> bool {
match x {
XBinary::NegInf => true,
XBinary::PosInf => false,
XBinary::Finite(b) => b.mantissa().is_negative(),
}
}
pub fn is_positive(x: &XBinary) -> bool {
match x {
XBinary::NegInf => false,
XBinary::PosInf => true,
XBinary::Finite(b) => b.mantissa().is_positive(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{bin, xbin};
#[test]
fn binary_pow_zero_exponent() {
let x = bin(3, 0);
assert_eq!(binary_pow(&x, 0), bin(1, 0));
}
#[test]
fn binary_pow_one_exponent() {
let x = bin(3, 0);
assert_eq!(binary_pow(&x, 1), bin(3, 0));
}
#[test]
fn binary_pow_square() {
let x = bin(3, 0);
assert_eq!(binary_pow(&x, 2), bin(9, 0));
}
#[test]
fn binary_pow_cube() {
let x = bin(3, 0);
assert_eq!(binary_pow(&x, 3), bin(27, 0));
}
#[test]
fn binary_pow_negative_base() {
let x = bin(-2, 0);
assert_eq!(binary_pow(&x, 2), bin(4, 0)); assert_eq!(binary_pow(&x, 3), bin(-8, 0)); }
#[test]
fn binary_pow_with_exponent() {
let x = bin(1, 3); let result = binary_pow(&x, 2);
assert_eq!(result, bin(1, 6)); }
#[test]
fn xbinary_pow_finite() {
let x = xbin(3, 0);
let result = xbinary_pow(&x, NonZeroU32::new(2).expect("2 is non-zero"));
assert_eq!(result, xbin(9, 0));
}
#[test]
fn xbinary_pow_pos_inf() {
let result = xbinary_pow(&XBinary::PosInf, NonZeroU32::new(5).expect("5 is non-zero"));
assert_eq!(result, XBinary::PosInf);
}
#[test]
fn xbinary_pow_neg_inf_even() {
let result = xbinary_pow(&XBinary::NegInf, NonZeroU32::new(4).expect("4 is non-zero"));
assert_eq!(result, XBinary::PosInf);
}
#[test]
fn xbinary_pow_neg_inf_odd() {
let result = xbinary_pow(&XBinary::NegInf, NonZeroU32::new(3).expect("3 is non-zero"));
assert_eq!(result, XBinary::NegInf);
}
#[test]
fn xbinary_max_finite() {
let a = xbin(3, 0);
let b = xbin(5, 0);
assert_eq!(xbinary_max(&a, &b), xbin(5, 0));
assert_eq!(xbinary_max(&b, &a), xbin(5, 0));
}
#[test]
fn xbinary_max_with_inf() {
let a = xbin(3, 0);
assert_eq!(xbinary_max(&a, &XBinary::PosInf), XBinary::PosInf);
assert_eq!(xbinary_max(&XBinary::NegInf, &a), xbin(3, 0));
}
#[test]
fn is_negative_tests() {
assert!(is_negative(&XBinary::NegInf));
assert!(!is_negative(&XBinary::PosInf));
assert!(is_negative(&xbin(-5, 0)));
assert!(!is_negative(&xbin(5, 0)));
assert!(!is_negative(&xbin(0, 0)));
}
#[test]
fn is_positive_tests() {
assert!(!is_positive(&XBinary::NegInf));
assert!(is_positive(&XBinary::PosInf));
assert!(!is_positive(&xbin(-5, 0)));
assert!(is_positive(&xbin(5, 0)));
assert!(!is_positive(&xbin(0, 0)));
}
}