// Copyright © 2024 Mikhail Hogrefe // // This file is part of Malachite. // // Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU // Lesser General Public License (LGPL) as published by the Free Software Foundation; either version // 3 of the License, or (at your option) any later version. See . use malachite_base::num::arithmetic::traits::{ CheckedRoot, Parity, Pow, PowAssign, PowerOf2, Reciprocal, Square, }; use malachite_base::num::basic::traits::{NegativeOne, One, Two, Zero}; use malachite_base::num::conversion::traits::ExactFrom; use malachite_base::test_util::generators::{signed_gen_var_5, unsigned_gen_var_5}; use malachite_nz::test_util::generators::integer_unsigned_pair_gen_var_2; use malachite_q::test_util::generators::{ rational_gen, rational_gen_var_1, rational_rational_signed_triple_gen_var_1, rational_rational_unsigned_triple_gen_var_1, rational_signed_pair_gen_var_2, rational_signed_signed_triple_gen_var_1, rational_unsigned_pair_gen_var_1, rational_unsigned_unsigned_triple_gen_var_1, }; use malachite_q::Rational; use num::traits::Pow as NumPow; use num::BigRational; use rug::ops::Pow as RugPow; use std::str::FromStr; #[test] fn test_pow() { let test = |s, exp: u64, out| { let u = Rational::from_str(s).unwrap(); let mut x = u.clone(); x.pow_assign(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = u.clone().pow(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = (&u).pow(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = BigRational::from_str(s).unwrap().pow(exp); assert_eq!(x.to_string(), out); let x = rug::Rational::from_str(s) .unwrap() .pow(u32::exact_from(exp)); assert_eq!(x.to_string(), out); }; test("0", 0, "1"); test("1", 0, "1"); test("2", 0, "1"); test("1000", 0, "1"); test("1000000000000", 0, "1"); test("0", 1, "0"); test("1", 1, "1"); test("2", 1, "2"); test("1000", 1, "1000"); test("1000000000000", 1, "1000000000000"); test("0", 2, "0"); test("1", 2, "1"); test("2", 2, "4"); test("3", 2, "9"); test("1000", 2, "1000000"); test("1000000000000", 2, "1000000000000000000000000"); test("1/2", 0, "1"); test("1/2", 1, "1/2"); test("1/2", 2, "1/4"); test("1/2", 3, "1/8"); test("22/7", 0, "1"); test("22/7", 1, "22/7"); test("22/7", 2, "484/49"); test("22/7", 3, "10648/343"); test("-1", 0, "1"); test("-2", 0, "1"); test("-1000", 0, "1"); test("-1000000000000", 0, "1"); test("-1", 1, "-1"); test("-2", 1, "-2"); test("-1000", 1, "-1000"); test("-1000000000000", 1, "-1000000000000"); test("-1", 2, "1"); test("-2", 2, "4"); test("-3", 2, "9"); test("-1000", 2, "1000000"); test("-1000000000000", 2, "1000000000000000000000000"); test("-1/2", 0, "1"); test("-1/2", 1, "-1/2"); test("-1/2", 2, "1/4"); test("-1/2", 3, "-1/8"); test("-22/7", 0, "1"); test("-22/7", 1, "-22/7"); test("-22/7", 2, "484/49"); test("-22/7", 3, "-10648/343"); let test = |s, exp: i64, out| { let u = Rational::from_str(s).unwrap(); let mut x = u.clone(); x.pow_assign(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = u.clone().pow(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = (&u).pow(exp); assert_eq!(x.to_string(), out); assert!(x.is_valid()); let x = BigRational::from_str(s).unwrap().pow(exp); assert_eq!(x.to_string(), out); let x = rug::Rational::from_str(s) .unwrap() .pow(i32::exact_from(exp)); assert_eq!(x.to_string(), out); }; test("0", 0, "1"); test("1", 0, "1"); test("2", 0, "1"); test("1000", 0, "1"); test("1000000000000", 0, "1"); test("0", 1, "0"); test("1", 1, "1"); test("2", 1, "2"); test("1000", 1, "1000"); test("1000000000000", 1, "1000000000000"); test("0", 2, "0"); test("1", 2, "1"); test("2", 2, "4"); test("3", 2, "9"); test("1000", 2, "1000000"); test("1000000000000", 2, "1000000000000000000000000"); test("1/2", 0, "1"); test("1/2", 1, "1/2"); test("1/2", 2, "1/4"); test("1/2", 3, "1/8"); test("22/7", 0, "1"); test("22/7", 1, "22/7"); test("22/7", 2, "484/49"); test("22/7", 3, "10648/343"); test("1", -1, "1"); test("2", -1, "1/2"); test("1000", -1, "1/1000"); test("1000000000000", -1, "1/1000000000000"); test("1", -2, "1"); test("2", -2, "1/4"); test("3", -2, "1/9"); test("1000", -2, "1/1000000"); test("1000000000000", -2, "1/1000000000000000000000000"); test("1/2", -1, "2"); test("1/2", -2, "4"); test("1/2", -3, "8"); test("22/7", -1, "7/22"); test("22/7", -2, "49/484"); test("22/7", -3, "343/10648"); test("-1", 0, "1"); test("-2", 0, "1"); test("-1000", 0, "1"); test("-1000000000000", 0, "1"); test("-1", 1, "-1"); test("-2", 1, "-2"); test("-1000", 1, "-1000"); test("-1000000000000", 1, "-1000000000000"); test("-1", 2, "1"); test("-2", 2, "4"); test("-3", 2, "9"); test("-1000", 2, "1000000"); test("-1000000000000", 2, "1000000000000000000000000"); test("-1/2", 0, "1"); test("-1/2", 1, "-1/2"); test("-1/2", 2, "1/4"); test("-1/2", 3, "-1/8"); test("-22/7", 0, "1"); test("-22/7", 1, "-22/7"); test("-22/7", 2, "484/49"); test("-22/7", 3, "-10648/343"); test("-1", -1, "-1"); test("-2", -1, "-1/2"); test("-1000", -1, "-1/1000"); test("-1000000000000", -1, "-1/1000000000000"); test("-1", -2, "1"); test("-2", -2, "1/4"); test("-3", -2, "1/9"); test("-1000", -2, "1/1000000"); test("-1000000000000", -2, "1/1000000000000000000000000"); test("-1/2", -1, "-2"); test("-1/2", -2, "4"); test("-1/2", -3, "-8"); test("-22/7", -1, "-7/22"); test("-22/7", -2, "49/484"); test("-22/7", -3, "-343/10648"); } #[test] fn pow_properties() { // exponent is u64 rational_unsigned_pair_gen_var_1::().test_properties(|(x, exp)| { let power = (&x).pow(exp); assert!(power.is_valid()); let power_alt = x.clone().pow(exp); assert!(power_alt.is_valid()); assert_eq!(power_alt, power); let mut power_alt = x.clone(); power_alt.pow_assign(exp); assert!(power_alt.is_valid()); assert_eq!(power_alt, power); let power_of_neg = (-&x).pow(exp); if exp.even() { assert_eq!(power_of_neg, power); } else { assert_eq!(power_of_neg, -&power); } if exp > 0 && (x >= 0 || exp.odd()) { assert_eq!((&power).checked_root(exp).as_ref(), Some(&x)); } assert_eq!((&x).pow(i64::exact_from(exp)), power); assert_eq!(Rational::from(&BigRational::from(&x).pow(exp)), power); assert_eq!( Rational::from(&rug::Rational::from(&x).pow(u32::exact_from(exp))), power ); }); rational_gen().test_properties(|x| { assert_eq!((&x).pow(0u64), 1); assert_eq!((&x).pow(1u64), x); assert_eq!((&x).pow(2u64), x.square()); }); unsigned_gen_var_5::().test_properties(|exp| { assert_eq!(Rational::ZERO.pow(exp), u64::from(exp == 0)); assert_eq!(Rational::ONE.pow(exp), 1); assert_eq!(Rational::TWO.pow(exp), Rational::power_of_2(exp)); assert_eq!( Rational::NEGATIVE_ONE.pow(exp), if exp.even() { 1 } else { -1 } ); }); rational_rational_unsigned_triple_gen_var_1::().test_properties(|(x, y, exp)| { assert_eq!((&x * &y).pow(exp), x.pow(exp) * y.pow(exp)); }); rational_unsigned_unsigned_triple_gen_var_1::().test_properties(|(x, e, f)| { assert_eq!((&x).pow(e + f), (&x).pow(e) * (&x).pow(f)); assert_eq!((&x).pow(e * f), x.pow(e).pow(f)); }); integer_unsigned_pair_gen_var_2().test_properties(|(x, exp)| { assert_eq!((&x).pow(exp), Rational::from(x).pow(exp)); }); // exponent is i64 rational_signed_pair_gen_var_2::().test_properties(|(x, exp)| { let power = (&x).pow(exp); assert!(power.is_valid()); let power_alt = x.clone().pow(exp); assert!(power_alt.is_valid()); assert_eq!(power_alt, power); let mut power_alt = x.clone(); power_alt.pow_assign(exp); assert!(power_alt.is_valid()); assert_eq!(power_alt, power); let power_of_neg = (-&x).pow(exp); if exp.even() { assert_eq!(power_of_neg, power); } else { assert_eq!(power_of_neg, -&power); } if x != 0 { assert_eq!((&x).pow(-exp), (&power).reciprocal()); } if exp > 0 && (x >= 0 || exp.odd()) { assert_eq!((&power).checked_root(exp).as_ref(), Some(&x)); } assert_eq!(Rational::from(&BigRational::from(&x).pow(exp)), power); assert_eq!( Rational::from(&rug::Rational::from(&x).pow(i32::exact_from(exp))), power ); }); rational_gen().test_properties(|x| { assert_eq!((&x).pow(0i64), 1); assert_eq!((&x).pow(1i64), x); assert_eq!((&x).pow(2i64), x.square()); }); rational_gen_var_1().test_properties(|x| { assert_eq!((&x).pow(-1i64), x.reciprocal()); }); signed_gen_var_5::().test_properties(|exp| { if exp >= 0 { assert_eq!(Rational::ZERO.pow(exp), u64::from(exp == 0)); } assert_eq!(Rational::ONE.pow(exp), 1); assert_eq!(Rational::TWO.pow(exp), Rational::power_of_2(exp)); assert_eq!( Rational::NEGATIVE_ONE.pow(exp), if exp.even() { 1 } else { -1 } ); }); rational_rational_signed_triple_gen_var_1::().test_properties(|(x, y, exp)| { assert_eq!((&x * &y).pow(exp), x.pow(exp) * y.pow(exp)); }); rational_signed_signed_triple_gen_var_1::().test_properties(|(x, e, f)| { assert_eq!((&x).pow(e + f), (&x).pow(e) * (&x).pow(f)); assert_eq!((&x).pow(e * f), x.pow(e).pow(f)); }); }