use malachite_base::num::arithmetic::traits::{CheckedDiv, Reciprocal};
use malachite_base::num::basic::traits::{NegativeOne, One, Zero};
use malachite_q::Rational;
use malachite_q::test_util::arithmetic::div::div_naive;
use malachite_q::test_util::generators::{
rational_gen, rational_gen_var_1, rational_pair_gen, rational_pair_gen_var_1,
rational_triple_gen_var_1,
};
use num::{BigRational, CheckedDiv as NumCheckedDiv};
use std::str::FromStr;
#[test]
fn test_div() {
let test = |s, t, out| {
let u = Rational::from_str(s).unwrap();
let v = Rational::from_str(t).unwrap();
let mut n = u.clone();
n /= v.clone();
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let mut n = u.clone();
n /= &v;
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let n = u.clone() / v.clone();
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let n = &u / v.clone();
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let n = u.clone() / &v;
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let n = &u / &v;
assert_eq!(n.to_string(), out);
assert!(n.is_valid());
let n = BigRational::from_str(s).unwrap() / BigRational::from_str(t).unwrap();
assert_eq!(n.to_string(), out);
let n = rug::Rational::from_str(s).unwrap() / rug::Rational::from_str(t).unwrap();
assert_eq!(n.to_string(), out);
};
test("0", "1/123", "0");
test("0", "-1/123", "0");
test("1", "1/123", "123");
test("1", "-1/123", "-123");
test("-1", "1/123", "-123");
test("-1", "-1/123", "123");
test("123", "1", "123");
test("123", "-1", "-123");
test("-123", "1", "-123");
test("-123", "-1", "123");
test("123", "1/456", "56088");
test("123", "-1/456", "-56088");
test("-123", "1/456", "-56088");
test("-123", "-1/456", "56088");
test("22/7", "2/3", "33/7");
test("22/7", "-2/3", "-33/7");
test("-22/7", "2/3", "-33/7");
test("-22/7", "-2/3", "33/7");
test("4/5", "4/5", "1");
test("4/5", "-4/5", "-1");
test("-4/5", "4/5", "-1");
test("-4/5", "-4/5", "1");
}
#[test]
fn test_checked_div() {
let test = |s, t, out: Option<&'static str>| {
let u = Rational::from_str(s).unwrap();
let v = Rational::from_str(t).unwrap();
let n = u.clone().checked_div(v.clone());
assert_eq!(n.as_ref().map(ToString::to_string).as_deref(), out);
if out.is_some() {
assert!(n.unwrap().is_valid());
}
let n = (&u).checked_div(v.clone());
assert_eq!(n.as_ref().map(ToString::to_string).as_deref(), out);
if out.is_some() {
assert!(n.unwrap().is_valid());
}
let n = u.clone().checked_div(&v);
assert_eq!(n.as_ref().map(ToString::to_string).as_deref(), out);
if out.is_some() {
assert!(n.unwrap().is_valid());
}
let n = (&u).checked_div(&v);
assert_eq!(n.as_ref().map(ToString::to_string).as_deref(), out);
if out.is_some() {
assert!(n.unwrap().is_valid());
}
let n = BigRational::from_str(s)
.unwrap()
.checked_div(&BigRational::from_str(t).unwrap());
assert_eq!(n.as_ref().map(ToString::to_string).as_deref(), out);
};
test("0", "1/123", Some("0"));
test("0", "-1/123", Some("0"));
test("0", "0", None);
test("1", "1/123", Some("123"));
test("1", "-1/123", Some("-123"));
test("1", "0", None);
test("-1", "1/123", Some("-123"));
test("-1", "-1/123", Some("123"));
test("-1", "0", None);
test("123", "1", Some("123"));
test("123", "-1", Some("-123"));
test("123", "0", None);
test("-123", "1", Some("-123"));
test("-123", "-1", Some("123"));
test("-123", "0", None);
test("123", "1/456", Some("56088"));
test("123", "-1/456", Some("-56088"));
test("-123", "1/456", Some("-56088"));
test("-123", "-1/456", Some("56088"));
test("22/7", "2/3", Some("33/7"));
test("22/7", "-2/3", Some("-33/7"));
test("22/7", "0", None);
test("-22/7", "2/3", Some("-33/7"));
test("-22/7", "-2/3", Some("33/7"));
test("-22/7", "0", None);
test("4/5", "4/5", Some("1"));
test("4/5", "-4/5", Some("-1"));
test("4/5", "0", None);
test("-4/5", "4/5", Some("-1"));
test("-4/5", "-4/5", Some("1"));
test("-4/5", "0", None);
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_fail_1() {
Rational::ONE / Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_fail_2() {
Rational::ZERO / Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_val_ref_fail_1() {
Rational::ONE / &Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_val_ref_fail_2() {
Rational::ZERO / &Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_ref_val_fail_1() {
&Rational::ONE / Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_ref_val_fail_2() {
&Rational::ZERO / Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_ref_ref_fail_1() {
&Rational::ONE / &Rational::ZERO;
}
#[allow(clippy::no_effect, unused_must_use)]
#[test]
#[should_panic]
fn div_ref_ref_fail_2() {
&Rational::ZERO / &Rational::ZERO;
}
#[test]
#[should_panic]
fn div_assign_fail_1() {
let mut x = Rational::ONE;
x /= Rational::ZERO;
}
#[test]
#[should_panic]
fn div_assign_fail_2() {
let mut x = Rational::ZERO;
x /= Rational::ZERO;
}
#[test]
#[should_panic]
fn div_assign_ref_fail_1() {
let mut x = Rational::ONE;
x /= &Rational::ZERO;
}
#[test]
#[should_panic]
fn div_assign_ref_fail_2() {
let mut x = Rational::ZERO;
x /= &Rational::ZERO;
}
#[allow(clippy::eq_op)]
#[test]
fn div_properties() {
rational_pair_gen_var_1().test_properties(|(x, y)| {
let quotient_val_val = x.clone() / y.clone();
let quotient_val_ref = x.clone() / &y;
let quotient_ref_val = &x / y.clone();
let quotient = &x / &y;
assert!(quotient_val_val.is_valid());
assert!(quotient_val_ref.is_valid());
assert!(quotient_ref_val.is_valid());
assert!(quotient.is_valid());
assert_eq!(quotient_val_val, quotient);
assert_eq!(quotient_val_ref, quotient);
assert_eq!(quotient_ref_val, quotient);
let mut mut_x = x.clone();
mut_x /= y.clone();
assert!(mut_x.is_valid());
assert_eq!(mut_x, quotient);
let mut mut_x = x.clone();
mut_x /= &y;
assert_eq!(mut_x, quotient);
assert!(mut_x.is_valid());
let mut mut_x = rug::Rational::from(&x);
mut_x /= rug::Rational::from(&y);
assert_eq!(Rational::from(&mut_x), quotient);
assert_eq!(
Rational::from(&(BigRational::from(&x) / BigRational::from(&y))),
quotient
);
assert_eq!(
Rational::from(&(rug::Rational::from(&x) / rug::Rational::from(&y))),
quotient
);
assert_eq!(div_naive(x.clone(), y.clone()), quotient);
assert_eq!((&x).checked_div(y.clone()).unwrap(), quotient);
assert_eq!(&x * (&y).reciprocal(), quotient);
assert_eq!("ient * &y, x);
if quotient != 0u32 {
assert_eq!(&y / &x, ("ient).reciprocal());
assert_eq!(&x / "ient, y);
}
assert_eq!(-&x / &y, -"ient);
assert_eq!(x / -y, -quotient);
});
rational_gen().test_properties(|ref x| {
assert_eq!(x / Rational::ONE, *x);
assert_eq!(x / Rational::NEGATIVE_ONE, -x);
});
rational_gen_var_1().test_properties(|ref x| {
assert_eq!(Rational::ZERO / x, 0);
assert_eq!(Rational::ONE / x, x.reciprocal());
assert_eq!(Rational::NEGATIVE_ONE / x, -x.reciprocal());
assert_eq!(x / x, 1);
});
rational_triple_gen_var_1().test_properties(|(ref x, ref y, ref z)| {
assert_eq!((x + y) / z, x / z + y / z);
assert_eq!((x - y) / z, x / z - y / z);
});
}
#[test]
fn checked_div_properties() {
rational_pair_gen().test_properties(|(x, y)| {
let quotient_val_val = x.clone().checked_div(y.clone());
let quotient_val_ref = x.clone().checked_div(&y);
let quotient_ref_val = (&x).checked_div(y.clone());
let quotient = (&x).checked_div(&y);
assert!(quotient_val_val.as_ref().is_none_or(Rational::is_valid));
assert!(quotient_val_ref.as_ref().is_none_or(Rational::is_valid));
assert!(quotient_ref_val.as_ref().is_none_or(Rational::is_valid));
assert!(quotient.as_ref().is_none_or(Rational::is_valid));
assert_eq!(quotient_val_val, quotient);
assert_eq!(quotient_val_ref, quotient);
assert_eq!(quotient_ref_val, quotient);
if y != 0u32 {
assert_eq!(quotient, Some(&x / &y));
}
assert_eq!(
BigRational::from(&x)
.checked_div(&BigRational::from(&y))
.map(|q| Rational::from(&q)),
quotient
);
});
rational_gen().test_properties(|ref x| {
assert_eq!(x.checked_div(Rational::ZERO), None);
assert_eq!(x.checked_div(Rational::ONE), Some(x.clone()));
assert_eq!(x.checked_div(Rational::NEGATIVE_ONE), Some(-x));
});
rational_gen_var_1().test_properties(|ref x| {
assert_eq!(Rational::ZERO.checked_div(x), Some(Rational::ZERO));
assert_eq!(Rational::ONE.checked_div(x), Some(x.reciprocal()));
assert_eq!(Rational::NEGATIVE_ONE.checked_div(x), Some(-x.reciprocal()));
assert_eq!(x.checked_div(x), Some(Rational::ONE));
});
}