use super::CheckedUnsignedAbs::{Negative, Positive};
use super::Sign::NoSign;
use super::{BigInt, UnsignedAbs};
use crate::{IsizePromotion, UsizePromotion};
use core::ops::{Div, DivAssign, Rem, RemAssign};
use num_integer::Integer;
use num_traits::{CheckedDiv, CheckedEuclid, Euclid, Signed, ToPrimitive, Zero};
forward_all_binop_to_ref_ref!(impl Div for BigInt, div);
impl Div<&BigInt> for &BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: &BigInt) -> BigInt {
let (q, _) = self.div_rem(other);
q
}
}
impl DivAssign<&BigInt> for BigInt {
#[inline]
fn div_assign(&mut self, other: &BigInt) {
*self = &*self / other;
}
}
forward_val_assign!(impl DivAssign for BigInt, div_assign);
promote_all_scalars!(impl Div for BigInt, div);
promote_all_scalars_assign!(impl DivAssign for BigInt, div_assign);
forward_all_scalar_binop_to_val_val!(impl Div<u32> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<u64> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<u128> for BigInt, div);
impl Div<u32> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data / other)
}
}
impl DivAssign<u32> for BigInt {
#[inline]
fn div_assign(&mut self, other: u32) {
self.data /= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Div<BigInt> for u32 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
BigInt::from_biguint(other.sign, self / other.data)
}
}
impl Div<u64> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data / other)
}
}
impl DivAssign<u64> for BigInt {
#[inline]
fn div_assign(&mut self, other: u64) {
self.data /= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Div<BigInt> for u64 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
BigInt::from_biguint(other.sign, self / other.data)
}
}
impl Div<u128> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: u128) -> BigInt {
BigInt::from_biguint(self.sign, self.data / other)
}
}
impl DivAssign<u128> for BigInt {
#[inline]
fn div_assign(&mut self, other: u128) {
self.data /= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Div<BigInt> for u128 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
BigInt::from_biguint(other.sign, self / other.data)
}
}
forward_all_scalar_binop_to_val_val!(impl Div<i32> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<i128> for BigInt, div);
impl Div<i32> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: i32) -> BigInt {
match other.checked_uabs() {
Positive(u) => self / u,
Negative(u) => -self / u,
}
}
}
impl DivAssign<i32> for BigInt {
#[inline]
fn div_assign(&mut self, other: i32) {
match other.checked_uabs() {
Positive(u) => *self /= u,
Negative(u) => {
self.sign = -self.sign;
*self /= u;
}
}
}
}
impl Div<BigInt> for i32 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u / other,
Negative(u) => u / -other,
}
}
}
impl Div<i64> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: i64) -> BigInt {
match other.checked_uabs() {
Positive(u) => self / u,
Negative(u) => -self / u,
}
}
}
impl DivAssign<i64> for BigInt {
#[inline]
fn div_assign(&mut self, other: i64) {
match other.checked_uabs() {
Positive(u) => *self /= u,
Negative(u) => {
self.sign = -self.sign;
*self /= u;
}
}
}
}
impl Div<BigInt> for i64 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u / other,
Negative(u) => u / -other,
}
}
}
impl Div<i128> for BigInt {
type Output = BigInt;
#[inline]
fn div(self, other: i128) -> BigInt {
match other.checked_uabs() {
Positive(u) => self / u,
Negative(u) => -self / u,
}
}
}
impl DivAssign<i128> for BigInt {
#[inline]
fn div_assign(&mut self, other: i128) {
match other.checked_uabs() {
Positive(u) => *self /= u,
Negative(u) => {
self.sign = -self.sign;
*self /= u;
}
}
}
}
impl Div<BigInt> for i128 {
type Output = BigInt;
#[inline]
fn div(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u / other,
Negative(u) => u / -other,
}
}
}
forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem);
impl Rem<&BigInt> for &BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: &BigInt) -> BigInt {
if let Some(other) = other.to_u32() {
self % other
} else if let Some(other) = other.to_i32() {
self % other
} else {
let (_, r) = self.div_rem(other);
r
}
}
}
impl RemAssign<&BigInt> for BigInt {
#[inline]
fn rem_assign(&mut self, other: &BigInt) {
*self = &*self % other;
}
}
forward_val_assign!(impl RemAssign for BigInt, rem_assign);
promote_all_scalars!(impl Rem for BigInt, rem);
promote_all_scalars_assign!(impl RemAssign for BigInt, rem_assign);
forward_all_scalar_binop_to_val_val!(impl Rem<u32> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<u64> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<u128> for BigInt, rem);
impl Rem<u32> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: u32) -> BigInt {
BigInt::from_biguint(self.sign, self.data % other)
}
}
impl RemAssign<u32> for BigInt {
#[inline]
fn rem_assign(&mut self, other: u32) {
self.data %= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Rem<BigInt> for u32 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
BigInt::from(self % other.data)
}
}
impl Rem<u64> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: u64) -> BigInt {
BigInt::from_biguint(self.sign, self.data % other)
}
}
impl RemAssign<u64> for BigInt {
#[inline]
fn rem_assign(&mut self, other: u64) {
self.data %= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Rem<BigInt> for u64 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
BigInt::from(self % other.data)
}
}
impl Rem<u128> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: u128) -> BigInt {
BigInt::from_biguint(self.sign, self.data % other)
}
}
impl RemAssign<u128> for BigInt {
#[inline]
fn rem_assign(&mut self, other: u128) {
self.data %= other;
if self.data.is_zero() {
self.sign = NoSign;
}
}
}
impl Rem<BigInt> for u128 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
BigInt::from(self % other.data)
}
}
forward_all_scalar_binop_to_val_val!(impl Rem<i32> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<i128> for BigInt, rem);
impl Rem<i32> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: i32) -> BigInt {
self % other.uabs()
}
}
impl RemAssign<i32> for BigInt {
#[inline]
fn rem_assign(&mut self, other: i32) {
*self %= other.uabs();
}
}
impl Rem<BigInt> for i32 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u % other,
Negative(u) => -(u % other),
}
}
}
impl Rem<i64> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: i64) -> BigInt {
self % other.uabs()
}
}
impl RemAssign<i64> for BigInt {
#[inline]
fn rem_assign(&mut self, other: i64) {
*self %= other.uabs();
}
}
impl Rem<BigInt> for i64 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u % other,
Negative(u) => -(u % other),
}
}
}
impl Rem<i128> for BigInt {
type Output = BigInt;
#[inline]
fn rem(self, other: i128) -> BigInt {
self % other.uabs()
}
}
impl RemAssign<i128> for BigInt {
#[inline]
fn rem_assign(&mut self, other: i128) {
*self %= other.uabs();
}
}
impl Rem<BigInt> for i128 {
type Output = BigInt;
#[inline]
fn rem(self, other: BigInt) -> BigInt {
match self.checked_uabs() {
Positive(u) => u % other,
Negative(u) => -(u % other),
}
}
}
impl CheckedDiv for BigInt {
#[inline]
fn checked_div(&self, v: &BigInt) -> Option<BigInt> {
if v.is_zero() {
return None;
}
Some(self.div(v))
}
}
impl CheckedEuclid for BigInt {
#[inline]
fn checked_div_euclid(&self, v: &BigInt) -> Option<BigInt> {
if v.is_zero() {
return None;
}
Some(self.div_euclid(v))
}
#[inline]
fn checked_rem_euclid(&self, v: &BigInt) -> Option<BigInt> {
if v.is_zero() {
return None;
}
Some(self.rem_euclid(v))
}
}
impl Euclid for BigInt {
#[inline]
fn div_euclid(&self, v: &BigInt) -> BigInt {
let (q, r) = self.div_rem(v);
if r.is_negative() {
if v.is_positive() {
q - 1
} else {
q + 1
}
} else {
q
}
}
#[inline]
fn rem_euclid(&self, v: &BigInt) -> BigInt {
let r = self % v;
if r.is_negative() {
if v.is_positive() {
r + v
} else {
r - v
}
} else {
r
}
}
}