use super::super::Q;
use crate::{
integer::Z,
macros::arithmetics::{
arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
arithmetic_between_types, arithmetic_trait_borrowed_to_owned,
arithmetic_trait_mixed_borrowed_owned,
},
};
use flint_sys::fmpq::{fmpq_add, fmpq_add_fmpz, fmpq_add_si, fmpq_add_ui};
use std::ops::{Add, AddAssign};
impl AddAssign<&Q> for Q {
fn add_assign(&mut self, other: &Self) {
unsafe { fmpq_add(&mut self.value, &self.value, &other.value) };
}
}
impl AddAssign<&Z> for Q {
fn add_assign(&mut self, other: &Z) {
unsafe { fmpq_add_fmpz(&mut self.value, &self.value, &other.value) };
}
}
impl AddAssign<i64> for Q {
fn add_assign(&mut self, other: i64) {
unsafe { fmpq_add_si(&mut self.value, &self.value, other) };
}
}
impl AddAssign<u64> for Q {
fn add_assign(&mut self, other: u64) {
unsafe { fmpq_add_ui(&mut self.value, &self.value, other) };
}
}
impl AddAssign<f64> for Q {
fn add_assign(&mut self, other: f64) {
let other = Q::from(other);
unsafe { fmpq_add(&mut self.value, &self.value, &other.value) };
}
}
arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, Q, Q);
arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, Q, Z);
arithmetic_assign_between_types!(AddAssign, add_assign, Q, i64, i32 i16 i8);
arithmetic_assign_between_types!(AddAssign, add_assign, Q, u64, u32 u16 u8);
arithmetic_assign_between_types!(AddAssign, add_assign, Q, f64, f32);
impl Add for &Q {
type Output = Q;
fn add(self, other: Self) -> Self::Output {
let mut out = Q::default();
unsafe {
fmpq_add(&mut out.value, &self.value, &other.value);
}
out
}
}
arithmetic_trait_borrowed_to_owned!(Add, add, Q, Q, Q);
arithmetic_trait_mixed_borrowed_owned!(Add, add, Q, Q, Q);
arithmetic_between_types!(Add, add, Q, Q, i64 i32 i16 i8 u64 u32 u16 u8 f32 f64);
impl Add<&Z> for &Q {
type Output = Q;
fn add(self, other: &Z) -> Self::Output {
let mut out = Q::default();
unsafe {
fmpq_add_fmpz(&mut out.value, &self.value, &other.value);
}
out
}
}
arithmetic_trait_borrowed_to_owned!(Add, add, Q, Z, Q);
arithmetic_trait_mixed_borrowed_owned!(Add, add, Q, Z, Q);
#[cfg(test)]
mod test_add_assign {
use crate::{integer::Z, rational::Q};
#[test]
fn correct_small() {
let mut a = Q::MINUS_ONE;
let b = Q::MINUS_ONE;
let c = Q::ONE;
let d = Q::from((1, 2));
a += &b;
assert_eq!(-2, a);
a += &c;
assert_eq!(-1, a);
a += &c;
assert_eq!(0, a);
a += &c;
assert_eq!(1, a);
a += &c;
assert_eq!(2, a);
a += 2 * b;
assert_eq!(0, a);
a += d;
assert_eq!(Q::from((1, 2)), a);
}
#[test]
fn correct_large() {
let mut a = Q::from(i64::MAX);
let b = Q::from(i64::MIN);
let c = Q::from(u64::MAX);
a += b;
assert_eq!(-1, a);
a += c;
assert_eq!(u64::MAX - 1, a);
}
#[test]
fn availability() {
let mut a = Q::from((1, 2));
let b = Q::from((4, 5));
let c = Z::ONE;
a += &b;
a += b;
a += &c;
a += c;
a += 0.5_f64;
a += 0.5_f32;
a += 1_u8;
a += 1_u16;
a += 1_u32;
a += 1_u64;
a += 1_i8;
a += 1_i16;
a += 1_i32;
a += 1_i64;
}
}
#[cfg(test)]
mod test_add {
use super::Q;
use std::str::FromStr;
#[test]
fn add() {
let a: Q = Q::from(42);
let b: Q = Q::from((42, 2));
let c: Q = a + b;
assert_eq!(c, Q::from(63));
}
#[test]
fn add_borrow() {
let a: Q = Q::from(42);
let b: Q = Q::from((42, 2));
let c: Q = &a + &b;
assert_eq!(c, Q::from(63));
}
#[test]
fn add_first_borrowed() {
let a: Q = Q::from((42, 5));
let b: Q = Q::from((42, 10));
let c: Q = &a + b;
assert_eq!(c, Q::from((63, 5)));
}
#[test]
fn add_second_borrowed() {
let a: Q = Q::from(42);
let b: Q = Q::from((42, 2));
let c: Q = a + &b;
assert_eq!(c, Q::from(63));
}
#[test]
fn add_large() {
let a: Q = Q::from(i64::MAX);
let b: Q = Q::from(u64::MAX - 1);
let c: Q = Q::from((1, i32::MAX));
let d: Q = Q::from((1, u32::MAX));
let e: Q = &a + &a;
let f: Q = c + d;
assert_eq!(e, b);
assert_eq!(
f,
Q::from_str(&format!(
"{}/{}",
u64::from(u32::MAX) + u64::from((u32::MAX - 1) / 2),
u64::from(u32::MAX) * u64::from((u32::MAX - 1) / 2)
))
.unwrap()
);
}
}
#[cfg(test)]
mod test_add_between_q_and_z {
use crate::integer::Z;
use crate::rational::Q;
#[test]
fn add() {
let a: Q = Q::from((5, 7));
let b: Z = Z::from(4);
let c: Q = a + b;
assert_eq!(c, Q::from((33, 7)));
}
#[test]
fn add_borrow() {
let a: Q = Q::from((5, 7));
let b: Z = Z::from(4);
let c: Q = &a + &b;
assert_eq!(c, Q::from((33, 7)));
}
#[test]
fn add_first_borrowed() {
let a: Q = Q::from((5, 7));
let b: Z = Z::from(4);
let c: Q = &a + b;
assert_eq!(c, Q::from((33, 7)));
}
#[test]
fn add_second_borrowed() {
let a: Q = Q::from((5, 7));
let b: Z = Z::from(4);
let c: Q = a + &b;
assert_eq!(c, Q::from((33, 7)));
}
#[test]
fn add_large_numbers() {
let a: Q = Q::from((u64::MAX, 2));
let b: Q = Q::from((1, u64::MAX));
let c: Z = Z::from(u64::MAX);
let d: Q = a + &c;
let e: Q = b + c;
assert_eq!(d, Q::from(u64::MAX) + Q::from((u64::MAX, 2)));
assert_eq!(e, Q::from((1, u64::MAX)) + Q::from(u64::MAX));
}
}
#[cfg(test)]
mod test_add_between_types {
use crate::rational::Q;
#[test]
#[allow(clippy::op_ref)]
fn add() {
let a: Q = Q::from(42);
let b: u64 = 1;
let c: u32 = 1;
let d: u16 = 1;
let e: u8 = 1;
let f: i64 = 1;
let g: i32 = 1;
let h: i16 = 1;
let i: i8 = 1;
let j: f32 = 0.3;
let k: f64 = 0.3;
let _: Q = &a + &b;
let _: Q = &a + &c;
let _: Q = &a + &d;
let _: Q = &a + &e;
let _: Q = &a + &f;
let _: Q = &a + &g;
let _: Q = &a + &h;
let _: Q = &a + &i;
let _: Q = &a + &j;
let _: Q = &a + &k;
let _: Q = &b + &a;
let _: Q = &c + &a;
let _: Q = &d + &a;
let _: Q = &e + &a;
let _: Q = &f + &a;
let _: Q = &g + &a;
let _: Q = &h + &a;
let _: Q = &i + &a;
let _: Q = &j + &a;
let _: Q = &k + &a;
let _: Q = &a + b;
let _: Q = &a + c;
let _: Q = &a + d;
let _: Q = &a + e;
let _: Q = &a + f;
let _: Q = &a + g;
let _: Q = &a + h;
let _: Q = &a + i;
let _: Q = &a + j;
let _: Q = &a + k;
let _: Q = &b + Q::from(42);
let _: Q = &c + Q::from(42);
let _: Q = &d + Q::from(42);
let _: Q = &e + Q::from(42);
let _: Q = &f + Q::from(42);
let _: Q = &g + Q::from(42);
let _: Q = &h + Q::from(42);
let _: Q = &i + Q::from(42);
let _: Q = &j + Q::from(42);
let _: Q = &k + Q::from(42);
let _: Q = Q::from(42) + &b;
let _: Q = Q::from(42) + &c;
let _: Q = Q::from(42) + &d;
let _: Q = Q::from(42) + &e;
let _: Q = Q::from(42) + &f;
let _: Q = Q::from(42) + &g;
let _: Q = Q::from(42) + &h;
let _: Q = Q::from(42) + &i;
let _: Q = Q::from(42) + &j;
let _: Q = Q::from(42) + &k;
let _: Q = b + &a;
let _: Q = c + &a;
let _: Q = d + &a;
let _: Q = e + &a;
let _: Q = f + &a;
let _: Q = g + &a;
let _: Q = h + &a;
let _: Q = i + &a;
let _: Q = j + &a;
let _: Q = k + &a;
let _: Q = Q::from(42) + b;
let _: Q = Q::from(42) + c;
let _: Q = Q::from(42) + d;
let _: Q = Q::from(42) + e;
let _: Q = Q::from(42) + f;
let _: Q = Q::from(42) + g;
let _: Q = Q::from(42) + h;
let _: Q = Q::from(42) + i;
let _: Q = Q::from(42) + j;
let _: Q = Q::from(42) + k;
let _: Q = b + Q::from(42);
let _: Q = c + Q::from(42);
let _: Q = d + Q::from(42);
let _: Q = e + Q::from(42);
let _: Q = f + Q::from(42);
let _: Q = g + Q::from(42);
let _: Q = h + Q::from(42);
let _: Q = i + Q::from(42);
let _: Q = j + Q::from(42);
let _: Q = k + Q::from(42);
}
}