use crate::ext::xmpq;
use crate::ext::xmpz;
use crate::integer::big as big_integer;
use crate::misc;
use crate::misc::{StringLike, VecLike};
use crate::ops::{NegAssign, SubFrom};
use crate::rational::BorrowRational;
use crate::rational::arith::MulIncomplete;
use crate::{Assign, Complete, Integer};
use az::{Cast, CheckedCast, StrictAs, StrictCast};
use core::cmp::Ordering;
use core::error::Error;
use core::fmt::{Display, Formatter, Result as FmtResult};
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
use gmp_mpfr_sys::gmp;
use gmp_mpfr_sys::gmp::mpq_t;
#[repr(transparent)]
pub struct Rational {
inner: mpq_t,
}
static_assert_same_layout!(Rational, mpq_t);
static_assert_same_layout!(BorrowRational<'_>, mpq_t);
static_assert_same_size!(Rational, Option<Rational>);
macro_rules! ref_rat_op_int {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
$(#[$attr_ref])*
#[derive(Debug)]
pub struct $Incomplete<'a> {
ref_self: &'a Rational,
$($param: $T,)*
}
impl Assign<$Incomplete<'_>> for Integer {
#[inline]
fn assign(&mut self, src: $Incomplete<'_>) {
$func(self, src.ref_self, $(src.$param),*);
}
}
impl From<$Incomplete<'_>> for Integer {
#[inline]
fn from(src: $Incomplete<'_>) -> Self {
let mut dst = Self::default();
dst.assign(src);
dst
}
}
impl Complete for $Incomplete<'_> {
type Completed = Rational;
#[inline]
fn complete(self) -> Rational {
Rational::from(self)
}
}
};
}
macro_rules! ref_rat_op_rat_int {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
$(#[$attr_ref])*
#[derive(Debug)]
pub struct $Incomplete<'a> {
ref_self: &'a Rational,
$($param: $T,)*
}
impl Assign<$Incomplete<'_>> for (&mut Rational, & mut Integer) {
#[inline]
fn assign(&mut self, src: $Incomplete<'_>) {
$func(self.0, self.1, src.ref_self, $(src.$param),*);
}
}
impl Assign<$Incomplete<'_>> for (Rational, Integer) {
#[inline]
fn assign(&mut self, src: $Incomplete<'_>) {
Assign::assign(&mut (&mut self.0, &mut self.1), src);
}
}
from_assign! { $Incomplete<'_> => Rational, Integer }
};
}
impl Rational {
pub const ZERO: &'static Rational = {
const INT: &Integer = &Integer::ZERO;
const BORROW: BorrowRational = INT.as_rational();
BorrowRational::const_deref(&BORROW)
};
pub const ONE: &'static Rational = {
const BORROW: BorrowRational = Integer::ONE.as_rational();
BorrowRational::const_deref(&BORROW)
};
pub const NEG_ONE: &'static Rational = {
const BORROW: BorrowRational = Integer::NEG_ONE.as_rational();
BorrowRational::const_deref(&BORROW)
};
#[inline]
pub fn new() -> Self {
unsafe {
let mut ret = MaybeUninit::uninit();
gmp::mpq_init(misc::cast_ptr_mut(ret.as_mut_ptr()));
ret.assume_init()
}
}
#[inline]
pub const unsafe fn from_raw(raw: mpq_t) -> Self {
Rational { inner: raw }
}
#[inline]
pub const fn into_raw(self) -> mpq_t {
let ret = self.inner;
let _ = ManuallyDrop::new(self);
ret
}
#[inline]
pub const fn as_raw(&self) -> *const mpq_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut mpq_t {
&mut self.inner
}
#[inline]
pub fn from_f32(value: f32) -> Option<Self> {
value.checked_cast()
}
#[inline]
pub fn from_f64(value: f64) -> Option<Self> {
value.checked_cast()
}
#[inline]
pub fn from_str_radix(src: &str, radix: i32) -> Result<Self, ParseRationalError> {
Ok(Rational::from(Rational::parse_radix(src, radix)?))
}
#[inline]
pub fn parse<S: AsRef<[u8]>>(src: S) -> Result<ParseIncomplete, ParseRationalError> {
parse(src.as_ref(), 10)
}
#[inline]
pub fn parse_radix<S: AsRef<[u8]>>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseRationalError> {
parse(src.as_ref(), radix)
}
#[inline]
pub fn to_f32(&self) -> f32 {
self.cast()
}
#[inline]
pub fn to_f64(&self) -> f64 {
self.cast()
}
#[cfg(feature = "std")]
#[inline]
pub fn to_string_radix(&self, radix: i32) -> String {
let mut s = StringLike::new_string();
append_to_string(&mut s, self, radix, false);
s.unwrap_string()
}
#[inline]
#[allow(clippy::result_unit_err)]
pub fn assign_f32(&mut self, val: f32) -> Result<(), ()> {
self.assign_f64(val.into())
}
#[inline]
#[allow(clippy::result_unit_err)]
pub fn assign_f64(&mut self, val: f64) -> Result<(), ()> {
if val.is_finite() {
xmpq::set_f64(self, val);
Ok(())
} else {
Err(())
}
}
pub unsafe fn from_canonical<Num, Den>(num: Num, den: Den) -> Self
where
Integer: From<Num> + From<Den>,
{
let (num, den) = (Integer::from(num), Integer::from(den));
let mut dst = MaybeUninit::uninit();
unsafe {
xmpq::write_num_den_unchecked(&mut dst, num, den);
dst.assume_init()
}
}
pub unsafe fn assign_canonical<Num, Den>(&mut self, num: Num, den: Den)
where
Integer: Assign<Num> + Assign<Den>,
{
unsafe {
let (dst_num, dst_den) = self.as_mut_numer_denom_no_canonicalization();
dst_num.assign(num);
dst_den.assign(den);
}
}
#[inline]
pub const fn numer(&self) -> &Integer {
xmpq::numref_const(self)
}
#[inline]
pub const fn denom(&self) -> &Integer {
xmpq::denref_const(self)
}
pub fn mutate_numer_denom<F>(&mut self, func: F)
where
F: FnOnce(&mut Integer, &mut Integer),
{
struct CanonicalizeOnDrop<'a>(&'a mut Rational);
impl Drop for CanonicalizeOnDrop<'_> {
fn drop(&mut self) {
xmpq::canonicalize(self.0);
}
}
let guard = CanonicalizeOnDrop(self);
unsafe {
let (num, den) = xmpq::numref_denref(guard.0);
func(num, den);
}
}
#[inline]
pub unsafe fn as_mut_numer_denom_no_canonicalization(
&mut self,
) -> (&mut Integer, &mut Integer) {
unsafe { xmpq::numref_denref(self) }
}
#[inline]
pub const fn into_numer_denom(self) -> (Integer, Integer) {
let raw = self.into_raw();
unsafe { (Integer::from_raw(raw.num), Integer::from_raw(raw.den)) }
}
pub const fn as_neg(&self) -> BorrowRational<'_> {
let mut raw = self.inner;
raw.num.size = match raw.num.size.checked_neg() {
Some(s) => s,
None => panic!("overflow"),
};
unsafe { BorrowRational::from_raw(raw) }
}
pub const fn as_abs(&self) -> BorrowRational<'_> {
let mut raw = self.inner;
raw.num.size = match raw.num.size.checked_abs() {
Some(s) => s,
None => panic!("overflow"),
};
unsafe { BorrowRational::from_raw(raw) }
}
pub const fn as_recip(&self) -> BorrowRational<'_> {
assert!(!self.is_zero(), "division by zero");
let mut raw = mpq_t {
num: self.inner.den,
den: self.inner.num,
};
if raw.den.size < 0 {
raw.den.size = raw.den.size.wrapping_neg();
raw.num.size = match raw.num.size.checked_neg() {
Some(s) => s,
None => panic!("overflow"),
};
}
unsafe { BorrowRational::from_raw(raw) }
}
#[inline]
pub const fn is_zero(&self) -> bool {
matches!(self.cmp0(), Ordering::Equal)
}
#[inline]
pub const fn is_positive(&self) -> bool {
matches!(self.cmp0(), Ordering::Greater)
}
#[inline]
pub const fn is_negative(&self) -> bool {
matches!(self.cmp0(), Ordering::Less)
}
#[inline]
pub const fn cmp0(&self) -> Ordering {
self.numer().cmp0()
}
#[inline]
pub fn cmp_abs(&self, other: &Self) -> Ordering {
self.as_abs().cmp(&*other.as_abs())
}
#[inline]
pub const fn is_integer(&self) -> bool {
xmpq::is_integer(self)
}
#[inline]
pub fn sum<'a, I>(values: I) -> SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Self>,
{
SumIncomplete { values }
}
#[inline]
pub fn dot<'a, I>(values: I) -> DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
DotIncomplete { values }
}
#[inline]
pub fn product<'a, I>(values: I) -> ProductIncomplete<'a, I>
where
I: Iterator<Item = &'a Self>,
{
ProductIncomplete { values }
}
#[inline]
#[must_use]
pub fn abs(mut self) -> Self {
self.abs_mut();
self
}
#[inline]
pub fn abs_mut(&mut self) {
xmpq::abs(self, ());
}
#[inline]
pub fn abs_ref(&self) -> AbsIncomplete<'_> {
AbsIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn signum(mut self) -> Self {
self.signum_mut();
self
}
#[inline]
pub fn signum_mut(&mut self) {
xmpq::signum(self);
}
#[inline]
pub fn signum_ref(&self) -> SignumIncomplete<'_> {
SignumIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn clamp<Min, Max>(mut self, min: &Min, max: &Max) -> Self
where
Self: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
self.clamp_mut(min, max);
self
}
pub fn clamp_mut<Min, Max>(&mut self, min: &Min, max: &Max)
where
Self: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
if (*self).lt(min) {
self.assign(min);
assert!(!(*self).gt(max), "minimum larger than maximum");
} else if (*self).gt(max) {
self.assign(max);
assert!(!(*self).lt(min), "minimum larger than maximum");
}
}
#[inline]
pub fn clamp_ref<'min, 'max, Min, Max>(
&self,
min: &'min Min,
max: &'max Max,
) -> ClampIncomplete<'_, 'min, 'max, Min, Max>
where
Self: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
ClampIncomplete {
ref_self: self,
min,
max,
}
}
#[inline]
#[must_use]
pub fn recip(mut self) -> Self {
self.recip_mut();
self
}
#[inline]
pub fn recip_mut(&mut self) {
xmpq::inv(self, ());
}
#[inline]
pub fn recip_ref(&self) -> RecipIncomplete<'_> {
RecipIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn trunc(mut self) -> Self {
self.trunc_mut();
self
}
#[inline]
pub fn trunc_mut(&mut self) {
xmpq::trunc(self);
}
#[inline]
pub fn trunc_ref(&self) -> TruncIncomplete<'_> {
TruncIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn rem_trunc(mut self) -> Self {
self.rem_trunc_mut();
self
}
#[inline]
pub fn rem_trunc_mut(&mut self) {
xmpq::trunc_fract(self, ());
}
#[inline]
pub fn rem_trunc_ref(&self) -> RemTruncIncomplete<'_> {
RemTruncIncomplete { ref_self: self }
}
#[inline]
pub fn fract_trunc(mut self, mut trunc: Integer) -> (Self, Integer) {
self.fract_trunc_mut(&mut trunc);
(self, trunc)
}
#[inline]
pub fn fract_trunc_mut(&mut self, trunc: &mut Integer) {
xmpq::trunc_fract_whole(self, trunc, ());
}
#[inline]
pub fn fract_trunc_ref(&self) -> FractTruncIncomplete<'_> {
FractTruncIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn ceil(mut self) -> Self {
self.ceil_mut();
self
}
#[inline]
pub fn ceil_mut(&mut self) {
xmpq::ceil(self);
}
#[inline]
pub fn ceil_ref(&self) -> CeilIncomplete<'_> {
CeilIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn rem_ceil(mut self) -> Self {
self.rem_ceil_mut();
self
}
#[inline]
pub fn rem_ceil_mut(&mut self) {
xmpq::ceil_fract(self, ());
}
#[inline]
pub fn rem_ceil_ref(&self) -> RemCeilIncomplete<'_> {
RemCeilIncomplete { ref_self: self }
}
#[inline]
pub fn fract_ceil(mut self, mut ceil: Integer) -> (Self, Integer) {
self.fract_ceil_mut(&mut ceil);
(self, ceil)
}
#[inline]
pub fn fract_ceil_mut(&mut self, ceil: &mut Integer) {
xmpq::ceil_fract_whole(self, ceil, ());
}
#[inline]
pub fn fract_ceil_ref(&self) -> FractCeilIncomplete<'_> {
FractCeilIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn floor(mut self) -> Self {
self.floor_mut();
self
}
#[inline]
pub fn floor_mut(&mut self) {
xmpq::floor(self);
}
#[inline]
pub fn floor_ref(&self) -> FloorIncomplete<'_> {
FloorIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn rem_floor(mut self) -> Self {
self.rem_floor_mut();
self
}
#[inline]
pub fn rem_floor_mut(&mut self) {
xmpq::floor_fract(self, ());
}
#[inline]
pub fn rem_floor_ref(&self) -> RemFloorIncomplete<'_> {
RemFloorIncomplete { ref_self: self }
}
#[inline]
pub fn fract_floor(mut self, mut floor: Integer) -> (Self, Integer) {
self.fract_floor_mut(&mut floor);
(self, floor)
}
#[inline]
pub fn fract_floor_mut(&mut self, floor: &mut Integer) {
xmpq::floor_fract_whole(self, floor, ());
}
#[inline]
pub fn fract_floor_ref(&self) -> FractFloorIncomplete<'_> {
FractFloorIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn round(mut self) -> Self {
self.round_mut();
self
}
#[inline]
pub fn round_mut(&mut self) {
xmpq::round(self);
}
#[inline]
pub fn round_ref(&self) -> RoundIncomplete<'_> {
RoundIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn rem_round(mut self) -> Self {
self.rem_round_mut();
self
}
#[inline]
pub fn rem_round_mut(&mut self) {
xmpq::round_fract(self, ());
}
#[inline]
pub fn rem_round_ref(&self) -> RemRoundIncomplete<'_> {
RemRoundIncomplete { ref_self: self }
}
#[inline]
pub fn fract_round(mut self, mut round: Integer) -> (Self, Integer) {
self.fract_round_mut(&mut round);
(self, round)
}
#[inline]
pub fn fract_round_mut(&mut self, round: &mut Integer) {
xmpq::round_fract_whole(self, round, ());
}
#[inline]
pub fn fract_round_ref(&self) -> FractRoundIncomplete<'_> {
FractRoundIncomplete { ref_self: self }
}
#[inline]
#[must_use]
pub fn square(mut self) -> Self {
self.square_mut();
self
}
#[inline]
pub fn square_mut(&mut self) {
xmpq::mul(self, (), ());
}
#[inline]
pub fn square_ref(&self) -> MulIncomplete<'_> {
self * self
}
}
#[derive(Debug)]
pub struct SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
values: I,
}
impl<'a, I> Assign<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn assign(&mut self, mut src: SumIncomplete<'a, I>) {
if let Some(first) = src.values.next() {
self.assign(first);
} else {
self.assign(0u32);
return;
}
self.add_assign(src);
}
}
impl<'a, I> From<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn from(mut src: SumIncomplete<'a, I>) -> Self {
let mut dst = match src.values.next() {
Some(first) => first.clone(),
None => return Rational::new(),
};
dst.add_assign(src);
dst
}
}
impl<'a, I> Complete for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
type Completed = Rational;
#[inline]
fn complete(self) -> Rational {
Rational::from(self)
}
}
impl<'a, I> Add<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.add_assign(rhs);
self
}
}
impl<'a, I> Add<Rational> for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
type Output = Rational;
#[inline]
fn add(self, mut rhs: Rational) -> Rational {
rhs.add_assign(self);
rhs
}
}
impl<'a, I> AddAssign<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn add_assign(&mut self, src: SumIncomplete<'a, I>) {
for i in src.values {
self.add_assign(i);
}
}
}
impl<'a, I> Sub<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn sub(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.sub_assign(rhs);
self
}
}
impl<'a, I> Sub<Rational> for SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
type Output = Rational;
#[inline]
fn sub(self, mut rhs: Rational) -> Rational {
rhs.neg_assign();
rhs.add_assign(self);
rhs
}
}
impl<'a, I> SubAssign<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn sub_assign(&mut self, src: SumIncomplete<'a, I>) {
for i in src.values {
self.sub_assign(i);
}
}
}
impl<'a, I> SubFrom<SumIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn sub_from(&mut self, src: SumIncomplete<'a, I>) {
self.neg_assign();
self.add_assign(src);
}
}
#[derive(Debug)]
pub struct DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
values: I,
}
impl<'a, I> Assign<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
fn assign(&mut self, mut src: DotIncomplete<'a, I>) {
if let Some(first) = src.values.next() {
self.assign(first.0 * first.1);
} else {
self.assign(0u32);
return;
}
self.add_assign(src);
}
}
impl<'a, I> From<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
fn from(mut src: DotIncomplete<'a, I>) -> Self {
let mut dst = match src.values.next() {
Some(first) => Rational::from(first.0 * first.1),
None => return Rational::new(),
};
dst.add_assign(src);
dst
}
}
impl<'a, I> Complete for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
type Completed = Rational;
#[inline]
fn complete(self) -> Rational {
Rational::from(self)
}
}
impl<'a, I> Add<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.add_assign(rhs);
self
}
}
impl<'a, I> Add<Rational> for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
type Output = Rational;
#[inline]
fn add(self, mut rhs: Rational) -> Rational {
rhs.add_assign(self);
rhs
}
}
impl<'a, I> AddAssign<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
fn add_assign(&mut self, src: DotIncomplete<'a, I>) {
let mut mul = Rational::new();
for i in src.values {
#[allow(clippy::suspicious_op_assign_impl)]
mul.assign(i.0 * i.1);
AddAssign::add_assign(self, &mul);
}
}
}
impl<'a, I> Sub<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
type Output = Self;
#[inline]
fn sub(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.sub_assign(rhs);
self
}
}
impl<'a, I> Sub<Rational> for DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
type Output = Rational;
#[inline]
fn sub(self, mut rhs: Rational) -> Rational {
rhs.neg_assign();
rhs.add_assign(self);
rhs
}
}
impl<'a, I> SubAssign<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
fn sub_assign(&mut self, src: DotIncomplete<'a, I>) {
let mut mul = Rational::new();
for i in src.values {
#[allow(clippy::suspicious_op_assign_impl)]
mul.assign(i.0 * i.1);
SubAssign::sub_assign(self, &mul);
}
}
}
impl<'a, I> SubFrom<DotIncomplete<'a, I>> for Rational
where
I: Iterator<Item = (&'a Rational, &'a Rational)>,
{
fn sub_from(&mut self, src: DotIncomplete<'a, I>) {
self.neg_assign();
self.add_assign(src);
}
}
#[derive(Debug)]
pub struct ProductIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
values: I,
}
impl<'a, I> Assign<ProductIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn assign(&mut self, mut src: ProductIncomplete<'a, I>) {
if let Some(first) = src.values.next() {
self.assign(first);
} else {
self.assign(1u32);
return;
}
self.mul_assign(src);
}
}
impl<'a, I> From<ProductIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn from(mut src: ProductIncomplete<'a, I>) -> Self {
let mut dst = match src.values.next() {
Some(first) => first.clone(),
None => return Rational::from(1),
};
dst.mul_assign(src);
dst
}
}
impl<'a, I> Complete for ProductIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
type Completed = Rational;
#[inline]
fn complete(self) -> Rational {
Rational::from(self)
}
}
impl<'a, I> Mul<ProductIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn mul(mut self, rhs: ProductIncomplete<'a, I>) -> Self {
self.mul_assign(rhs);
self
}
}
impl<'a, I> Mul<Rational> for ProductIncomplete<'a, I>
where
I: Iterator<Item = &'a Rational>,
{
type Output = Rational;
#[inline]
fn mul(self, mut rhs: Rational) -> Rational {
rhs.mul_assign(self);
rhs
}
}
impl<'a, I> MulAssign<ProductIncomplete<'a, I>> for Rational
where
I: Iterator<Item = &'a Self>,
{
fn mul_assign(&mut self, mut src: ProductIncomplete<'a, I>) {
let mut other = match src.values.next() {
Some(next) => Rational::from(&*self * next),
None => return,
};
loop {
if let Some(next) = src.values.next() {
self.assign(&other * next);
} else {
self.assign(other);
return;
}
match src.values.next() {
Some(next) => {
other.assign(&*self * next);
}
None => {
return;
}
}
if self.is_zero() {
return;
}
}
}
}
ref_math_op1! { Rational; xmpq::abs; struct AbsIncomplete {} }
ref_rat_op_int! { xmpq::signum_int; struct SignumIncomplete {} }
#[derive(Debug)]
pub struct ClampIncomplete<'s, 'min, 'max, Min, Max>
where
Rational: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
ref_self: &'s Rational,
min: &'min Min,
max: &'max Max,
}
impl<Min, Max> Assign<ClampIncomplete<'_, '_, '_, Min, Max>> for Rational
where
Self: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
#[inline]
fn assign(&mut self, src: ClampIncomplete<Min, Max>) {
if src.ref_self.lt(src.min) {
self.assign(src.min);
assert!(!(*self).gt(src.max), "minimum larger than maximum");
} else if src.ref_self.gt(src.max) {
self.assign(src.max);
assert!(!(*self).lt(src.min), "minimum larger than maximum");
} else {
self.assign(src.ref_self);
}
}
}
impl<Min, Max> From<ClampIncomplete<'_, '_, '_, Min, Max>> for Rational
where
Self: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
#[inline]
fn from(src: ClampIncomplete<Min, Max>) -> Self {
let mut dst = Rational::new();
dst.assign(src);
dst
}
}
impl<Min, Max> Complete for ClampIncomplete<'_, '_, '_, Min, Max>
where
Rational: PartialOrd<Min> + PartialOrd<Max> + for<'a> Assign<&'a Min> + for<'a> Assign<&'a Max>,
{
type Completed = Rational;
#[inline]
fn complete(self) -> Rational {
Rational::from(self)
}
}
ref_math_op1! { Rational; xmpq::inv; struct RecipIncomplete {} }
ref_rat_op_int! { xmpq::trunc_int; struct TruncIncomplete {} }
ref_math_op1! { Rational; xmpq::trunc_fract; struct RemTruncIncomplete {} }
ref_rat_op_rat_int! { xmpq::trunc_fract_whole; struct FractTruncIncomplete {} }
ref_rat_op_int! { xmpq::ceil_int; struct CeilIncomplete {} }
ref_math_op1! { Rational; xmpq::ceil_fract; struct RemCeilIncomplete {} }
ref_rat_op_rat_int! { xmpq::ceil_fract_whole; struct FractCeilIncomplete {} }
ref_rat_op_int! { xmpq::floor_int; struct FloorIncomplete {} }
ref_math_op1! { Rational; xmpq::floor_fract; struct RemFloorIncomplete {} }
ref_rat_op_rat_int! { xmpq::floor_fract_whole; struct FractFloorIncomplete {} }
ref_rat_op_int! { xmpq::round_int; struct RoundIncomplete {} }
ref_math_op1! { Rational; xmpq::round_fract; struct RemRoundIncomplete {} }
ref_rat_op_rat_int! { xmpq::round_fract_whole; struct FractRoundIncomplete {} }
pub(crate) fn append_to_string(s: &mut StringLike, r: &Rational, radix: i32, to_upper: bool) {
let (num, den) = (r.numer(), r.denom());
let is_whole = *den == 1;
if !is_whole {
let cap_for_den_nul = big_integer::req_chars(den, radix, 2);
let cap = big_integer::req_chars(num, radix, cap_for_den_nul);
s.reserve(cap);
};
let reserved_ptr = s.as_str().as_ptr();
big_integer::append_to_string(s, num, radix, to_upper);
if !is_whole {
s.push_str("/");
big_integer::append_to_string(s, den, radix, to_upper);
debug_assert_eq!(reserved_ptr, s.as_str().as_ptr());
}
}
#[derive(Debug)]
pub struct ParseIncomplete {
is_negative: bool,
digits: VecLike<u8>,
den_start: usize,
radix: i32,
}
impl Assign<ParseIncomplete> for Rational {
fn assign(&mut self, src: ParseIncomplete) {
let num_len = src.den_start;
if num_len == 0 {
xmpq::set_0(self);
return;
}
let den_len = src.digits.as_slice().len() - num_len;
let num_str = src.digits.as_slice().as_ptr();
unsafe {
let (num, den) = self.as_mut_numer_denom_no_canonicalization();
xmpz::realloc_for_mpn_set_str(num, num_len, src.radix);
let size = gmp::mpn_set_str(num.inner_mut().d.as_ptr(), num_str, num_len, src.radix);
num.inner_mut().size = (if src.is_negative { -size } else { size }).strict_cast();
if den_len == 0 {
xmpz::set_1(den);
return;
}
let den_str = num_str.offset(num_len.strict_cast());
xmpz::realloc_for_mpn_set_str(den, den_len, src.radix);
let size = gmp::mpn_set_str(den.inner_mut().d.as_ptr(), den_str, den_len, src.radix);
den.inner_mut().size = size.strict_cast();
xmpq::canonicalize(self);
}
}
}
from_assign! { ParseIncomplete => Rational }
fn parse(bytes: &[u8], radix: i32) -> Result<ParseIncomplete, ParseRationalError> {
use self::{ParseErrorKind as Kind, ParseRationalError as Error};
assert!((2..=36).contains(&radix), "radix out of range");
let bradix = radix.strict_as::<u8>();
let mut digits = VecLike::new();
digits.reserve(bytes.len() + 1);
let mut has_sign = false;
let mut is_negative = false;
let mut has_digits = false;
let mut den_start = None;
for &b in bytes {
if b == b'/' {
if den_start.is_some() {
return Err(Error {
kind: Kind::TooManySlashes,
});
}
if !has_digits {
return Err(Error {
kind: Kind::NumerNoDigits,
});
}
has_digits = false;
den_start = Some(digits.as_slice().len());
continue;
}
let digit = match b {
b'+' if den_start.is_none() && !has_sign && !has_digits => {
has_sign = true;
continue;
}
b'-' if den_start.is_none() && !has_sign && !has_digits => {
is_negative = true;
has_sign = true;
continue;
}
b'_' if has_digits => continue,
b' ' | b'\t' | b'\n' | 0x0b | 0x0c | 0x0d => continue,
b'0'..=b'9' => b - b'0',
b'a'..=b'z' => b - b'a' + 10,
b'A'..=b'Z' => b - b'A' + 10,
_ => bradix,
};
if digit >= bradix {
return Err(Error {
kind: Kind::InvalidDigit,
});
}
has_digits = true;
if digit > 0
|| (!digits.as_slice().is_empty() && den_start != Some(digits.as_slice().len()))
{
digits.push(digit);
}
}
if !has_digits {
return Err(Error {
kind: if den_start.is_some() {
Kind::DenomNoDigits
} else {
Kind::NoDigits
},
});
}
if den_start == Some(digits.as_slice().len()) {
return Err(Error {
kind: Kind::DenomZero,
});
}
let den_start = den_start.unwrap_or(digits.as_slice().len());
Ok(ParseIncomplete {
is_negative,
digits,
den_start,
radix,
})
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ParseRationalError {
kind: ParseErrorKind,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum ParseErrorKind {
InvalidDigit,
NoDigits,
NumerNoDigits,
DenomNoDigits,
TooManySlashes,
DenomZero,
}
impl ParseRationalError {
fn desc(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
InvalidDigit => "invalid digit found in string",
NoDigits => "string has no digits",
NumerNoDigits => "string has no digits for numerator",
DenomNoDigits => "string has no digits for denominator",
TooManySlashes => "more than one / found in string",
DenomZero => "string has zero denominator",
}
}
}
impl Display for ParseRationalError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
Display::fmt(self.desc(), f)
}
}
impl Error for ParseRationalError {
#[allow(deprecated)]
fn description(&self) -> &str {
self.desc()
}
}