1 use crate::error::{FendError, Interrupt}; 2 use crate::format::Format; 3 use crate::interrupt::test_int; 4 use crate::num::biguint::BigUint; 5 use crate::num::{Base, Exact, FormattingStyle, Range, RangeBound}; 6 use crate::result::FResult; 7 use std::{cmp, fmt, hash, io, ops}; 8 9 pub(crate) mod sign { 10 use crate::{ 11 error::FendError, 12 result::FResult, 13 serialize::{Deserialize, Serialize}, 14 }; 15 use std::io; 16 17 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 18 pub(crate) enum Sign { 19 Negative = 1, 20 Positive = 2, 21 } 22 23 impl Sign { flip(self) -> Self24 pub(crate) const fn flip(self) -> Self { 25 match self { 26 Self::Positive => Self::Negative, 27 Self::Negative => Self::Positive, 28 } 29 } 30 sign_of_product(a: Self, b: Self) -> Self31 pub(crate) const fn sign_of_product(a: Self, b: Self) -> Self { 32 match (a, b) { 33 (Self::Positive, Self::Positive) | (Self::Negative, Self::Negative) => { 34 Self::Positive 35 } 36 (Self::Positive, Self::Negative) | (Self::Negative, Self::Positive) => { 37 Self::Negative 38 } 39 } 40 } 41 serialize(self, write: &mut impl io::Write) -> FResult<()>42 pub(crate) fn serialize(self, write: &mut impl io::Write) -> FResult<()> { 43 (self as u8).serialize(write) 44 } 45 deserialize(read: &mut impl io::Read) -> FResult<Self>46 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> { 47 Ok(match u8::deserialize(read)? { 48 1 => Self::Positive, 49 2 => Self::Negative, 50 _ => return Err(FendError::DeserializationError), 51 }) 52 } 53 } 54 } 55 56 use super::biguint::{self, FormattedBigUint}; 57 use super::out_of_range; 58 use sign::Sign; 59 60 #[derive(Clone)] 61 pub(crate) struct BigRat { 62 sign: Sign, 63 num: BigUint, 64 den: BigUint, 65 } 66 67 impl fmt::Debug for BigRat { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 69 if self.sign == Sign::Negative { 70 write!(f, "-")?; 71 } 72 write!(f, "{:?}", self.num)?; 73 if !self.den.is_definitely_one() { 74 write!(f, "/{:?}", self.den)?; 75 } 76 Ok(()) 77 } 78 } 79 80 impl Ord for BigRat { cmp(&self, other: &Self) -> cmp::Ordering81 fn cmp(&self, other: &Self) -> cmp::Ordering { 82 let int = &crate::interrupt::Never; 83 let diff = self.clone().add(-other.clone(), int).unwrap(); 84 if diff.num == 0.into() { 85 cmp::Ordering::Equal 86 } else if diff.sign == Sign::Positive { 87 cmp::Ordering::Greater 88 } else { 89 cmp::Ordering::Less 90 } 91 } 92 } 93 94 impl PartialOrd for BigRat { partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>95 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 96 Some(self.cmp(other)) 97 } 98 } 99 100 impl PartialEq for BigRat { eq(&self, other: &Self) -> bool101 fn eq(&self, other: &Self) -> bool { 102 self.cmp(other) == cmp::Ordering::Equal 103 } 104 } 105 106 impl Eq for BigRat {} 107 108 impl hash::Hash for BigRat { hash<H: hash::Hasher>(&self, state: &mut H)109 fn hash<H: hash::Hasher>(&self, state: &mut H) { 110 let int = &crate::interrupt::Never; 111 if let Ok(res) = self.clone().simplify(int) { 112 // don't hash the sign 113 res.num.hash(state); 114 res.den.hash(state); 115 } 116 } 117 } 118 119 impl BigRat { serialize(&self, write: &mut impl io::Write) -> FResult<()>120 pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> { 121 self.sign.serialize(write)?; 122 self.num.serialize(write)?; 123 self.den.serialize(write)?; 124 Ok(()) 125 } 126 deserialize(read: &mut impl io::Read) -> FResult<Self>127 pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> { 128 Ok(Self { 129 sign: Sign::deserialize(read)?, 130 num: BigUint::deserialize(read)?, 131 den: BigUint::deserialize(read)?, 132 }) 133 } 134 is_integer(&self) -> bool135 pub(crate) fn is_integer(&self) -> bool { 136 self.den == 1.into() 137 } 138 try_as_usize<I: Interrupt>(mut self, int: &I) -> FResult<usize>139 pub(crate) fn try_as_usize<I: Interrupt>(mut self, int: &I) -> FResult<usize> { 140 if self.sign == Sign::Negative && self.num != 0.into() { 141 return Err(FendError::NegativeNumbersNotAllowed); 142 } 143 self = self.simplify(int)?; 144 if self.den != 1.into() { 145 return Err(FendError::FractionToInteger); 146 } 147 self.num.try_as_usize(int) 148 } 149 try_as_i64<I: Interrupt>(mut self, int: &I) -> FResult<i64>150 pub(crate) fn try_as_i64<I: Interrupt>(mut self, int: &I) -> FResult<i64> { 151 self = self.simplify(int)?; 152 if self.den != 1.into() { 153 return Err(FendError::FractionToInteger); 154 } 155 let res = self.num.try_as_usize(int)?; 156 let res: i64 = res.try_into().map_err(|_| FendError::OutOfRange { 157 value: Box::new(res), 158 range: Range { 159 start: RangeBound::None, 160 end: RangeBound::Open(Box::new(i64::MAX)), 161 }, 162 })?; 163 Ok(match self.sign { 164 Sign::Positive => res, 165 Sign::Negative => -res, 166 }) 167 } 168 into_f64<I: Interrupt>(mut self, int: &I) -> FResult<f64>169 pub(crate) fn into_f64<I: Interrupt>(mut self, int: &I) -> FResult<f64> { 170 if self.is_definitely_zero() { 171 return Ok(0.0); 172 } 173 self = self.simplify(int)?; 174 let positive_result = self.num.as_f64() / self.den.as_f64(); 175 if self.sign == Sign::Negative { 176 Ok(-positive_result) 177 } else { 178 Ok(positive_result) 179 } 180 } 181 182 #[allow( 183 clippy::cast_possible_truncation, 184 clippy::cast_sign_loss, 185 clippy::cast_precision_loss 186 )] from_f64<I: Interrupt>(mut f: f64, int: &I) -> FResult<Self>187 pub(crate) fn from_f64<I: Interrupt>(mut f: f64, int: &I) -> FResult<Self> { 188 let negative = f < 0.0; 189 if negative { 190 f = -f; 191 } 192 let i = (f * u64::MAX as f64) as u128; 193 let part1 = i as u64; 194 let part2 = (i >> 64) as u64; 195 Ok(Self { 196 sign: if negative { 197 Sign::Negative 198 } else { 199 Sign::Positive 200 }, 201 num: BigUint::from(part1) 202 .add(&BigUint::from(part2).mul(&BigUint::from(u64::MAX), int)?), 203 den: BigUint::from(u64::MAX), 204 }) 205 } 206 207 // sin works for all real numbers sin<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>>208 pub(crate) fn sin<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> { 209 Ok(if self == 0.into() { 210 Exact::new(Self::from(0), true) 211 } else { 212 Exact::new(Self::from_f64(f64::sin(self.into_f64(int)?), int)?, false) 213 }) 214 } 215 216 // asin, acos and atan only work for values between -1 and 1 asin<I: Interrupt>(self, int: &I) -> FResult<Self>217 pub(crate) fn asin<I: Interrupt>(self, int: &I) -> FResult<Self> { 218 let one = Self::from(1); 219 if self > one || self < -one { 220 return Err(out_of_range(self.fm(int)?, Range::open(-1, 1))); 221 } 222 Self::from_f64(f64::asin(self.into_f64(int)?), int) 223 } 224 acos<I: Interrupt>(self, int: &I) -> FResult<Self>225 pub(crate) fn acos<I: Interrupt>(self, int: &I) -> FResult<Self> { 226 let one = Self::from(1); 227 if self > one || self < -one { 228 return Err(out_of_range(self.fm(int)?, Range::open(-1, 1))); 229 } 230 Self::from_f64(f64::acos(self.into_f64(int)?), int) 231 } 232 233 // note that this works for any real number, unlike asin and acos atan<I: Interrupt>(self, int: &I) -> FResult<Self>234 pub(crate) fn atan<I: Interrupt>(self, int: &I) -> FResult<Self> { 235 Self::from_f64(f64::atan(self.into_f64(int)?), int) 236 } 237 atan2<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>238 pub(crate) fn atan2<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> { 239 Self::from_f64(f64::atan2(self.into_f64(int)?, rhs.into_f64(int)?), int) 240 } 241 sinh<I: Interrupt>(self, int: &I) -> FResult<Self>242 pub(crate) fn sinh<I: Interrupt>(self, int: &I) -> FResult<Self> { 243 Self::from_f64(f64::sinh(self.into_f64(int)?), int) 244 } 245 cosh<I: Interrupt>(self, int: &I) -> FResult<Self>246 pub(crate) fn cosh<I: Interrupt>(self, int: &I) -> FResult<Self> { 247 Self::from_f64(f64::cosh(self.into_f64(int)?), int) 248 } 249 tanh<I: Interrupt>(self, int: &I) -> FResult<Self>250 pub(crate) fn tanh<I: Interrupt>(self, int: &I) -> FResult<Self> { 251 Self::from_f64(f64::tanh(self.into_f64(int)?), int) 252 } 253 asinh<I: Interrupt>(self, int: &I) -> FResult<Self>254 pub(crate) fn asinh<I: Interrupt>(self, int: &I) -> FResult<Self> { 255 Self::from_f64(f64::asinh(self.into_f64(int)?), int) 256 } 257 258 // value must not be less than 1 acosh<I: Interrupt>(self, int: &I) -> FResult<Self>259 pub(crate) fn acosh<I: Interrupt>(self, int: &I) -> FResult<Self> { 260 if self < 1.into() { 261 return Err(out_of_range( 262 self.fm(int)?, 263 Range { 264 start: RangeBound::Closed(1), 265 end: RangeBound::None, 266 }, 267 )); 268 } 269 Self::from_f64(f64::acosh(self.into_f64(int)?), int) 270 } 271 272 // value must be between -1 and 1. atanh<I: Interrupt>(self, int: &I) -> FResult<Self>273 pub(crate) fn atanh<I: Interrupt>(self, int: &I) -> FResult<Self> { 274 let one: Self = 1.into(); 275 if self >= one || self <= -one { 276 return Err(out_of_range(self.fm(int)?, Range::open(-1, 1))); 277 } 278 Self::from_f64(f64::atanh(self.into_f64(int)?), int) 279 } 280 281 // For all logs: value must be greater than 0 ln<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>>282 pub(crate) fn ln<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> { 283 if self <= 0.into() { 284 return Err(out_of_range( 285 self.fm(int)?, 286 Range { 287 start: RangeBound::Open(0), 288 end: RangeBound::None, 289 }, 290 )); 291 } 292 if self == 1.into() { 293 return Ok(Exact::new(0.into(), true)); 294 } 295 Ok(Exact::new( 296 Self::from_f64(f64::ln(self.into_f64(int)?), int)?, 297 false, 298 )) 299 } 300 log2<I: Interrupt>(self, int: &I) -> FResult<Self>301 pub(crate) fn log2<I: Interrupt>(self, int: &I) -> FResult<Self> { 302 if self <= 0.into() { 303 return Err(out_of_range( 304 self.fm(int)?, 305 Range { 306 start: RangeBound::Open(0), 307 end: RangeBound::None, 308 }, 309 )); 310 } 311 Self::from_f64(f64::log2(self.into_f64(int)?), int) 312 } 313 log10<I: Interrupt>(self, int: &I) -> FResult<Self>314 pub(crate) fn log10<I: Interrupt>(self, int: &I) -> FResult<Self> { 315 if self <= 0.into() { 316 return Err(out_of_range( 317 self.fm(int)?, 318 Range { 319 start: RangeBound::Open(0), 320 end: RangeBound::None, 321 }, 322 )); 323 } 324 Self::from_f64(f64::log10(self.into_f64(int)?), int) 325 } 326 apply_uint_op<I: Interrupt, R>( mut self, f: impl FnOnce(BigUint, &I) -> FResult<R>, int: &I, ) -> FResult<R>327 fn apply_uint_op<I: Interrupt, R>( 328 mut self, 329 f: impl FnOnce(BigUint, &I) -> FResult<R>, 330 int: &I, 331 ) -> FResult<R> { 332 self = self.simplify(int)?; 333 if self.den != 1.into() { 334 let n = self.fm(int)?; 335 return Err(FendError::MustBeAnInteger(Box::new(n))); 336 } 337 if self.sign == Sign::Negative && self.num != 0.into() { 338 return Err(out_of_range(self.fm(int)?, Range::ZERO_OR_GREATER)); 339 } 340 f(self.num, int) 341 } 342 factorial<I: Interrupt>(self, int: &I) -> FResult<Self>343 pub(crate) fn factorial<I: Interrupt>(self, int: &I) -> FResult<Self> { 344 Ok(self.apply_uint_op(BigUint::factorial, int)?.into()) 345 } 346 floor<I: Interrupt>(self, int: &I) -> FResult<Self>347 pub(crate) fn floor<I: Interrupt>(self, int: &I) -> FResult<Self> { 348 let float = self.into_f64(int)?.floor(); 349 Self::from_f64(float, int) 350 } 351 ceil<I: Interrupt>(self, int: &I) -> FResult<Self>352 pub(crate) fn ceil<I: Interrupt>(self, int: &I) -> FResult<Self> { 353 let float = self.into_f64(int)?.ceil(); 354 Self::from_f64(float, int) 355 } 356 round<I: Interrupt>(self, int: &I) -> FResult<Self>357 pub(crate) fn round<I: Interrupt>(self, int: &I) -> FResult<Self> { 358 let float = self.into_f64(int)?.round(); 359 Self::from_f64(float, int) 360 } 361 bitwise<I: Interrupt>( self, rhs: Self, op: crate::ast::BitwiseBop, int: &I, ) -> FResult<Self>362 pub(crate) fn bitwise<I: Interrupt>( 363 self, 364 rhs: Self, 365 op: crate::ast::BitwiseBop, 366 int: &I, 367 ) -> FResult<Self> { 368 use crate::ast::BitwiseBop; 369 370 Ok(self 371 .apply_uint_op( 372 |lhs, int| { 373 let rhs = rhs.apply_uint_op(|rhs, _int| Ok(rhs), int)?; 374 let result = match op { 375 BitwiseBop::And => lhs.bitwise_and(&rhs), 376 BitwiseBop::Or => lhs.bitwise_or(&rhs), 377 BitwiseBop::Xor => lhs.bitwise_xor(&rhs), 378 BitwiseBop::LeftShift => lhs.lshift_n(&rhs, int)?, 379 BitwiseBop::RightShift => lhs.rshift_n(&rhs, int)?, 380 }; 381 Ok(result) 382 }, 383 int, 384 )? 385 .into()) 386 } 387 388 /// compute a + b add_internal<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>389 fn add_internal<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> { 390 // a + b == -((-a) + (-b)) 391 if self.sign == Sign::Negative { 392 return Ok(-((-self).add_internal(-rhs, int)?)); 393 } 394 395 assert_eq!(self.sign, Sign::Positive); 396 397 Ok(if self.den == rhs.den { 398 if rhs.sign == Sign::Negative && self.num < rhs.num { 399 Self { 400 sign: Sign::Negative, 401 num: rhs.num.sub(&self.num), 402 den: self.den, 403 } 404 } else { 405 Self { 406 sign: Sign::Positive, 407 num: if rhs.sign == Sign::Positive { 408 self.num.add(&rhs.num) 409 } else { 410 self.num.sub(&rhs.num) 411 }, 412 den: self.den, 413 } 414 } 415 } else { 416 let gcd = BigUint::gcd(self.den.clone(), rhs.den.clone(), int)?; 417 let new_denominator = self.den.clone().mul(&rhs.den, int)?.div(&gcd, int)?; 418 let a = self.num.mul(&rhs.den, int)?.div(&gcd, int)?; 419 let b = rhs.num.mul(&self.den, int)?.div(&gcd, int)?; 420 421 if rhs.sign == Sign::Negative && a < b { 422 Self { 423 sign: Sign::Negative, 424 num: b.sub(&a), 425 den: new_denominator, 426 } 427 } else { 428 Self { 429 sign: Sign::Positive, 430 num: if rhs.sign == Sign::Positive { 431 a.add(&b) 432 } else { 433 a.sub(&b) 434 }, 435 den: new_denominator, 436 } 437 } 438 }) 439 } 440 simplify<I: Interrupt>(mut self, int: &I) -> FResult<Self>441 fn simplify<I: Interrupt>(mut self, int: &I) -> FResult<Self> { 442 if self.den == 1.into() { 443 return Ok(self); 444 } 445 let gcd = BigUint::gcd(self.num.clone(), self.den.clone(), int)?; 446 self.num = self.num.div(&gcd, int)?; 447 self.den = self.den.div(&gcd, int)?; 448 Ok(self) 449 } 450 div<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self>451 pub(crate) fn div<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self> { 452 if rhs.num == 0.into() { 453 return Err(FendError::DivideByZero); 454 } 455 Ok(Self { 456 sign: Sign::sign_of_product(self.sign, rhs.sign), 457 num: self.num.mul(&rhs.den, int)?, 458 den: self.den.mul(&rhs.num, int)?, 459 }) 460 } 461 modulo<I: Interrupt>(mut self, mut rhs: Self, int: &I) -> FResult<Self>462 pub(crate) fn modulo<I: Interrupt>(mut self, mut rhs: Self, int: &I) -> FResult<Self> { 463 if rhs.num == 0.into() { 464 return Err(FendError::ModuloByZero); 465 } 466 self = self.simplify(int)?; 467 rhs = rhs.simplify(int)?; 468 if (self.sign == Sign::Negative && self.num != 0.into()) 469 || rhs.sign == Sign::Negative 470 || self.den != 1.into() 471 || rhs.den != 1.into() 472 { 473 return Err(FendError::ModuloForPositiveInts); 474 } 475 Ok(Self { 476 sign: Sign::Positive, 477 num: self.num.divmod(&rhs.num, int)?.1, 478 den: 1.into(), 479 }) 480 } 481 482 // test if this fraction has a terminating representation 483 // e.g. in base 10: 1/4 = 0.25, but not 1/3 terminates_in_base<I: Interrupt>(&self, base: Base, int: &I) -> FResult<bool>484 fn terminates_in_base<I: Interrupt>(&self, base: Base, int: &I) -> FResult<bool> { 485 let mut x = self.clone(); 486 let base_as_u64: u64 = base.base_as_u8().into(); 487 let base = Self { 488 sign: Sign::Positive, 489 num: base_as_u64.into(), 490 den: 1.into(), 491 }; 492 loop { 493 let old_den = x.den.clone(); 494 x = x.mul(&base, int)?.simplify(int)?; 495 let new_den = x.den.clone(); 496 if new_den == old_den { 497 break; 498 } 499 } 500 Ok(x.den == 1.into()) 501 } 502 format_as_integer<I: Interrupt>( num: &BigUint, base: Base, sign: Sign, term: &'static str, use_parens_if_product: bool, sf_limit: Option<usize>, int: &I, ) -> FResult<Exact<FormattedBigRat>>503 fn format_as_integer<I: Interrupt>( 504 num: &BigUint, 505 base: Base, 506 sign: Sign, 507 term: &'static str, 508 use_parens_if_product: bool, 509 sf_limit: Option<usize>, 510 int: &I, 511 ) -> FResult<Exact<FormattedBigRat>> { 512 let (ty, exact) = if !term.is_empty() && !base.has_prefix() && num == &1.into() { 513 (FormattedBigRatType::Integer(None, false, term, false), true) 514 } else { 515 let formatted_int = num.format( 516 &biguint::FormatOptions { 517 base, 518 write_base_prefix: true, 519 sf_limit, 520 }, 521 int, 522 )?; 523 ( 524 FormattedBigRatType::Integer( 525 Some(formatted_int.value), 526 !term.is_empty() && base.base_as_u8() > 10, 527 term, 528 // print surrounding parentheses if the number is imaginary 529 use_parens_if_product && !term.is_empty(), 530 ), 531 formatted_int.exact, 532 ) 533 }; 534 Ok(Exact::new(FormattedBigRat { sign, ty }, exact)) 535 } 536 format_as_fraction<I: Interrupt>( &self, base: Base, sign: Sign, term: &'static str, mixed: bool, use_parens: bool, int: &I, ) -> FResult<Exact<FormattedBigRat>>537 fn format_as_fraction<I: Interrupt>( 538 &self, 539 base: Base, 540 sign: Sign, 541 term: &'static str, 542 mixed: bool, 543 use_parens: bool, 544 int: &I, 545 ) -> FResult<Exact<FormattedBigRat>> { 546 let format_options = biguint::FormatOptions { 547 base, 548 write_base_prefix: true, 549 sf_limit: None, 550 }; 551 let formatted_den = self.den.format(&format_options, int)?; 552 let (pref, num, prefix_exact) = if mixed { 553 let (prefix, num) = self.num.divmod(&self.den, int)?; 554 if prefix == 0.into() { 555 (None, num, true) 556 } else { 557 let formatted_prefix = prefix.format(&format_options, int)?; 558 (Some(formatted_prefix.value), num, formatted_prefix.exact) 559 } 560 } else { 561 (None, self.num.clone(), true) 562 }; 563 // mixed fractions without a prefix aren't really mixed 564 let actually_mixed = pref.is_some(); 565 let (ty, num_exact) = 566 if !term.is_empty() && !actually_mixed && !base.has_prefix() && num == 1.into() { 567 ( 568 FormattedBigRatType::Fraction( 569 pref, 570 None, 571 false, 572 term, 573 formatted_den.value, 574 "", 575 use_parens, 576 ), 577 true, 578 ) 579 } else { 580 let formatted_num = num.format(&format_options, int)?; 581 let i_suffix = term; 582 let space = !term.is_empty() && (base.base_as_u8() >= 19 || actually_mixed); 583 let (isuf1, isuf2) = if actually_mixed { 584 ("", i_suffix) 585 } else { 586 (i_suffix, "") 587 }; 588 ( 589 FormattedBigRatType::Fraction( 590 pref, 591 Some(formatted_num.value), 592 space, 593 isuf1, 594 formatted_den.value, 595 isuf2, 596 use_parens, 597 ), 598 formatted_num.exact, 599 ) 600 }; 601 Ok(Exact::new( 602 FormattedBigRat { sign, ty }, 603 formatted_den.exact && prefix_exact && num_exact, 604 )) 605 } 606 format_as_decimal<I: Interrupt>( &self, style: FormattingStyle, base: Base, sign: Sign, term: &'static str, mut terminating: impl FnMut() -> FResult<bool>, int: &I, ) -> FResult<Exact<FormattedBigRat>>607 fn format_as_decimal<I: Interrupt>( 608 &self, 609 style: FormattingStyle, 610 base: Base, 611 sign: Sign, 612 term: &'static str, 613 mut terminating: impl FnMut() -> FResult<bool>, 614 int: &I, 615 ) -> FResult<Exact<FormattedBigRat>> { 616 let integer_part = self.clone().num.div(&self.den, int)?; 617 let sf_limit = if let FormattingStyle::SignificantFigures(sf) = style { 618 Some(sf) 619 } else { 620 None 621 }; 622 let formatted_integer_part = integer_part.format( 623 &biguint::FormatOptions { 624 base, 625 write_base_prefix: true, 626 sf_limit, 627 }, 628 int, 629 )?; 630 631 let num_trailing_digits_to_print = if style == FormattingStyle::ExactFloat 632 || (style == FormattingStyle::Auto && terminating()?) 633 || style == FormattingStyle::Exact 634 { 635 MaxDigitsToPrint::AllDigits 636 } else if let FormattingStyle::DecimalPlaces(n) = style { 637 MaxDigitsToPrint::DecimalPlaces(n) 638 } else if let FormattingStyle::SignificantFigures(sf) = style { 639 let num_digits_of_int_part = formatted_integer_part.value.num_digits(); 640 let dp = if sf > num_digits_of_int_part { 641 // we want more significant figures than what was printed 642 // in the int component 643 sf - num_digits_of_int_part 644 } else { 645 // no more digits, we already exhausted the number of significant 646 // figures 647 0 648 }; 649 if integer_part == 0.into() { 650 // if the integer part is 0, we don't want leading zeroes 651 // after the decimal point to affect the number of non-zero 652 // digits printed 653 654 // we add 1 to the number of decimal places in this case because 655 // the integer component of '0' shouldn't count against the 656 // number of significant figures 657 MaxDigitsToPrint::DpButIgnoreLeadingZeroes(dp + 1) 658 } else { 659 MaxDigitsToPrint::DecimalPlaces(dp) 660 } 661 } else { 662 MaxDigitsToPrint::DecimalPlaces(10) 663 }; 664 let print_integer_part = |ignore_minus_if_zero: bool| { 665 let sign = 666 if sign == Sign::Negative && (!ignore_minus_if_zero || integer_part != 0.into()) { 667 Sign::Negative 668 } else { 669 Sign::Positive 670 }; 671 Ok((sign, formatted_integer_part.value.to_string())) 672 }; 673 let integer_as_rational = Self { 674 sign: Sign::Positive, 675 num: integer_part.clone(), 676 den: 1.into(), 677 }; 678 let remaining_fraction = self.clone().add(-integer_as_rational, int)?; 679 let (sign, formatted_trailing_digits) = Self::format_trailing_digits( 680 base, 681 &remaining_fraction.num, 682 &remaining_fraction.den, 683 num_trailing_digits_to_print, 684 terminating, 685 print_integer_part, 686 int, 687 )?; 688 Ok(Exact::new( 689 FormattedBigRat { 690 sign, 691 ty: FormattedBigRatType::Decimal( 692 formatted_trailing_digits.value, 693 !term.is_empty() && base.base_as_u8() > 10, 694 term, 695 ), 696 }, 697 formatted_integer_part.exact && formatted_trailing_digits.exact, 698 )) 699 } 700 701 /// Prints the decimal expansion of num/den, where num < den, in the given base. format_trailing_digits<I: Interrupt>( base: Base, numerator: &BigUint, denominator: &BigUint, max_digits: MaxDigitsToPrint, mut terminating: impl FnMut() -> FResult<bool>, print_integer_part: impl Fn(bool) -> FResult<(Sign, String)>, int: &I, ) -> FResult<(Sign, Exact<String>)>702 fn format_trailing_digits<I: Interrupt>( 703 base: Base, 704 numerator: &BigUint, 705 denominator: &BigUint, 706 max_digits: MaxDigitsToPrint, 707 mut terminating: impl FnMut() -> FResult<bool>, 708 print_integer_part: impl Fn(bool) -> FResult<(Sign, String)>, 709 int: &I, 710 ) -> FResult<(Sign, Exact<String>)> { 711 let base_as_u64: u64 = base.base_as_u8().into(); 712 let b: BigUint = base_as_u64.into(); 713 let next_digit = 714 |i: usize, num: BigUint, base: &BigUint| -> Result<(BigUint, BigUint), NextDigitErr> { 715 test_int(int)?; 716 if num == 0.into() 717 || max_digits == MaxDigitsToPrint::DecimalPlaces(i) 718 || max_digits == MaxDigitsToPrint::DpButIgnoreLeadingZeroes(i) 719 { 720 return Err(NextDigitErr::Terminated); 721 } 722 // digit = base * numerator / denominator 723 // next_numerator = base * numerator - digit * denominator 724 let bnum = num.mul(base, int)?; 725 let digit = bnum.clone().div(denominator, int)?; 726 let next_num = bnum.sub(&digit.clone().mul(denominator, int)?); 727 Ok((next_num, digit)) 728 }; 729 let fold_digits = |mut s: String, digit: BigUint| -> FResult<String> { 730 let digit_str = digit 731 .format( 732 &biguint::FormatOptions { 733 base, 734 write_base_prefix: false, 735 sf_limit: None, 736 }, 737 int, 738 )? 739 .value 740 .to_string(); 741 s.push_str(digit_str.as_str()); 742 Ok(s) 743 }; 744 let skip_cycle_detection = max_digits != MaxDigitsToPrint::AllDigits || terminating()?; 745 if skip_cycle_detection { 746 let ignore_number_of_leading_zeroes = 747 matches!(max_digits, MaxDigitsToPrint::DpButIgnoreLeadingZeroes(_)); 748 return Self::format_nonrecurring( 749 numerator, 750 base, 751 ignore_number_of_leading_zeroes, 752 next_digit, 753 print_integer_part, 754 int, 755 ); 756 } 757 match Self::brents_algorithm( 758 next_digit, 759 fold_digits, 760 numerator.clone(), 761 &b, 762 String::new(), 763 ) { 764 Ok((cycle_length, location, output)) => { 765 let (ab, _) = output.split_at(location + cycle_length); 766 let (a, b) = ab.split_at(location); 767 let (sign, formatted_int) = print_integer_part(false)?; 768 let mut trailing_digits = String::new(); 769 trailing_digits.push_str(&formatted_int); 770 trailing_digits.push('.'); 771 trailing_digits.push_str(a); 772 trailing_digits.push('('); 773 trailing_digits.push_str(b); 774 trailing_digits.push(')'); 775 Ok((sign, Exact::new(trailing_digits, true))) // the recurring decimal is exact 776 } 777 Err(NextDigitErr::Terminated) => { 778 panic!("decimal number terminated unexpectedly"); 779 } 780 Err(NextDigitErr::Error(e)) => Err(e), 781 } 782 } 783 format_nonrecurring<I: Interrupt>( numerator: &BigUint, base: Base, ignore_number_of_leading_zeroes: bool, mut next_digit: impl FnMut(usize, BigUint, &BigUint) -> Result<(BigUint, BigUint), NextDigitErr>, print_integer_part: impl Fn(bool) -> FResult<(Sign, String)>, int: &I, ) -> FResult<(Sign, Exact<String>)>784 fn format_nonrecurring<I: Interrupt>( 785 numerator: &BigUint, 786 base: Base, 787 ignore_number_of_leading_zeroes: bool, 788 mut next_digit: impl FnMut(usize, BigUint, &BigUint) -> Result<(BigUint, BigUint), NextDigitErr>, 789 print_integer_part: impl Fn(bool) -> FResult<(Sign, String)>, 790 int: &I, 791 ) -> FResult<(Sign, Exact<String>)> { 792 let mut current_numerator = numerator.clone(); 793 let mut i = 0; 794 let mut trailing_zeroes = 0; 795 // this becomes Some(_) when we write the decimal point 796 let mut actual_sign = None; 797 let mut trailing_digits = String::new(); 798 let b: BigUint = u64::from(base.base_as_u8()).into(); 799 loop { 800 match next_digit(i, current_numerator.clone(), &b) { 801 Ok((next_n, digit)) => { 802 current_numerator = next_n; 803 if digit == 0.into() { 804 trailing_zeroes += 1; 805 if !(i == 0 && ignore_number_of_leading_zeroes) { 806 i += 1; 807 } 808 } else { 809 if actual_sign.is_none() { 810 // always print leading minus because we have non-zero digits 811 let (sign, formatted_int) = print_integer_part(false)?; 812 actual_sign = Some(sign); 813 trailing_digits.push_str(&formatted_int); 814 trailing_digits.push('.'); 815 } 816 for _ in 0..trailing_zeroes { 817 trailing_digits.push('0'); 818 } 819 trailing_zeroes = 0; 820 trailing_digits.push_str( 821 &digit 822 .format( 823 &biguint::FormatOptions { 824 base, 825 write_base_prefix: false, 826 sf_limit: None, 827 }, 828 int, 829 )? 830 .value 831 .to_string(), 832 ); 833 i += 1; 834 } 835 } 836 Err(NextDigitErr::Terminated) => { 837 let sign = if let Some(actual_sign) = actual_sign { 838 actual_sign 839 } else { 840 // if we reach this point we haven't printed any non-zero digits, 841 // so we can skip the leading minus sign if the integer part is also zero 842 let (sign, formatted_int) = print_integer_part(true)?; 843 trailing_digits.push_str(&formatted_int); 844 sign 845 }; 846 // is the number exact, or did we need to truncate? 847 let exact = current_numerator == 0.into(); 848 return Ok((sign, Exact::new(trailing_digits, exact))); 849 } 850 Err(NextDigitErr::Error(e)) => { 851 return Err(e); 852 } 853 } 854 } 855 } 856 857 // Brent's cycle detection algorithm (based on pseudocode from Wikipedia) 858 // returns (length of cycle, index of first element of cycle, collected result) brents_algorithm<T: Clone + Eq, R, U, E1: From<E2>, E2>( f: impl Fn(usize, T, &T) -> Result<(T, U), E1>, g: impl Fn(R, U) -> Result<R, E2>, x0: T, state: &T, r0: R, ) -> Result<(usize, usize, R), E1>859 fn brents_algorithm<T: Clone + Eq, R, U, E1: From<E2>, E2>( 860 f: impl Fn(usize, T, &T) -> Result<(T, U), E1>, 861 g: impl Fn(R, U) -> Result<R, E2>, 862 x0: T, 863 state: &T, 864 r0: R, 865 ) -> Result<(usize, usize, R), E1> { 866 // main phase: search successive powers of two 867 let mut power = 1; 868 // lam is the length of the cycle 869 let mut lam = 1; 870 let mut tortoise = x0.clone(); 871 let mut depth = 0; 872 let (mut hare, _) = f(depth, x0.clone(), state)?; 873 depth += 1; 874 while tortoise != hare { 875 if power == lam { 876 tortoise = hare.clone(); 877 power *= 2; 878 lam = 0; 879 } 880 hare = f(depth, hare, state)?.0; 881 depth += 1; 882 lam += 1; 883 } 884 885 // Find the position of the first repetition of length lam 886 tortoise = x0.clone(); 887 hare = x0; 888 let mut collected_res = r0; 889 let mut hare_depth = 0; 890 for _ in 0..lam { 891 let (new_hare, u) = f(hare_depth, hare, state)?; 892 hare_depth += 1; 893 hare = new_hare; 894 collected_res = g(collected_res, u)?; 895 } 896 // The distance between the hare and tortoise is now lam. 897 898 // Next, the hare and tortoise move at same speed until they agree 899 // mu will be the length of the initial sequence, before the cycle 900 let mut mu = 0; 901 let mut tortoise_depth = 0; 902 while tortoise != hare { 903 tortoise = f(tortoise_depth, tortoise, state)?.0; 904 tortoise_depth += 1; 905 let (new_hare, u) = f(hare_depth, hare, state)?; 906 hare_depth += 1; 907 hare = new_hare; 908 collected_res = g(collected_res, u)?; 909 mu += 1; 910 } 911 Ok((lam, mu, collected_res)) 912 } 913 pow<I: Interrupt>(mut self, mut rhs: Self, int: &I) -> FResult<Exact<Self>>914 pub(crate) fn pow<I: Interrupt>(mut self, mut rhs: Self, int: &I) -> FResult<Exact<Self>> { 915 self = self.simplify(int)?; 916 rhs = rhs.simplify(int)?; 917 if self.num != 0.into() && self.sign == Sign::Negative && rhs.den != 1.into() { 918 return Err(FendError::RootsOfNegativeNumbers); 919 } 920 if rhs.sign == Sign::Negative { 921 // a^-b => 1/a^b 922 rhs.sign = Sign::Positive; 923 let inverse_res = self.pow(rhs, int)?; 924 return Ok(Exact::new( 925 Self::from(1).div(&inverse_res.value, int)?, 926 inverse_res.exact, 927 )); 928 } 929 let result_sign = if self.sign == Sign::Positive || rhs.num.is_even(int)? { 930 Sign::Positive 931 } else { 932 Sign::Negative 933 }; 934 let pow_res = Self { 935 sign: result_sign, 936 num: BigUint::pow(&self.num, &rhs.num, int)?, 937 den: BigUint::pow(&self.den, &rhs.num, int)?, 938 }; 939 if rhs.den == 1.into() { 940 Ok(Exact::new(pow_res, true)) 941 } else { 942 Ok(pow_res.root_n( 943 &Self { 944 sign: Sign::Positive, 945 num: rhs.den, 946 den: 1.into(), 947 }, 948 int, 949 )?) 950 } 951 } 952 953 /// n must be an integer iter_root_n<I: Interrupt>( mut low_bound: Self, val: &Self, n: &Self, int: &I, ) -> FResult<Self>954 fn iter_root_n<I: Interrupt>( 955 mut low_bound: Self, 956 val: &Self, 957 n: &Self, 958 int: &I, 959 ) -> FResult<Self> { 960 let mut high_bound = low_bound.clone().add(1.into(), int)?; 961 for _ in 0..30 { 962 let guess = low_bound 963 .clone() 964 .add(high_bound.clone(), int)? 965 .div(&2.into(), int)?; 966 if &guess.clone().pow(n.clone(), int)?.value < val { 967 low_bound = guess; 968 } else { 969 high_bound = guess; 970 } 971 } 972 low_bound.add(high_bound, int)?.div(&2.into(), int) 973 } 974 exp<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>>975 pub(crate) fn exp<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> { 976 if self.num == 0.into() { 977 return Ok(Exact::new(Self::from(1), true)); 978 } 979 Ok(Exact::new( 980 Self::from_f64(self.into_f64(int)?.exp(), int)?, 981 false, 982 )) 983 } 984 985 // the boolean indicates whether or not the result is exact 986 // n must be an integer root_n<I: Interrupt>(self, n: &Self, int: &I) -> FResult<Exact<Self>>987 pub(crate) fn root_n<I: Interrupt>(self, n: &Self, int: &I) -> FResult<Exact<Self>> { 988 if self.num != 0.into() && self.sign == Sign::Negative { 989 return Err(FendError::RootsOfNegativeNumbers); 990 } 991 let n = n.clone().simplify(int)?; 992 if n.den != 1.into() || n.sign == Sign::Negative { 993 return Err(FendError::NonIntegerNegRoots); 994 } 995 let n = &n.num; 996 if self.num == 0.into() { 997 return Ok(Exact::new(self, true)); 998 } 999 let num = self.clone().num.root_n(n, int)?; 1000 let den = self.clone().den.root_n(n, int)?; 1001 if num.exact && den.exact { 1002 return Ok(Exact::new( 1003 Self { 1004 sign: Sign::Positive, 1005 num: num.value, 1006 den: den.value, 1007 }, 1008 true, 1009 )); 1010 } 1011 // TODO check in which cases this might still be exact 1012 let num_rat = if num.exact { 1013 Self::from(num.value) 1014 } else { 1015 Self::iter_root_n( 1016 Self::from(num.value), 1017 &Self::from(self.num), 1018 &Self::from(n.clone()), 1019 int, 1020 )? 1021 }; 1022 let den_rat = if den.exact { 1023 Self::from(den.value) 1024 } else { 1025 Self::iter_root_n( 1026 Self::from(den.value), 1027 &Self::from(self.den), 1028 &Self::from(n.clone()), 1029 int, 1030 )? 1031 }; 1032 Ok(Exact::new(num_rat.div(&den_rat, int)?, false)) 1033 } 1034 mul<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self>1035 pub(crate) fn mul<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self> { 1036 Ok(Self { 1037 sign: Sign::sign_of_product(self.sign, rhs.sign), 1038 num: self.num.mul(&rhs.num, int)?, 1039 den: self.den.mul(&rhs.den, int)?, 1040 }) 1041 } 1042 add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>1043 pub(crate) fn add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> { 1044 self.add_internal(rhs, int) 1045 } 1046 is_definitely_zero(&self) -> bool1047 pub(crate) fn is_definitely_zero(&self) -> bool { 1048 self.num.is_definitely_zero() 1049 } 1050 is_definitely_one(&self) -> bool1051 pub(crate) fn is_definitely_one(&self) -> bool { 1052 self.sign == Sign::Positive && self.num.is_definitely_one() && self.den.is_definitely_one() 1053 } 1054 combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>1055 pub(crate) fn combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> { 1056 let n_factorial = self.clone().factorial(int)?; 1057 let r_factorial = rhs.clone().factorial(int)?; 1058 let n_minus_r_factorial = self.add(-rhs, int)?.factorial(int)?; 1059 let denominator = r_factorial.mul(&n_minus_r_factorial, int)?; 1060 n_factorial.div(&denominator, int) 1061 } 1062 permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self>1063 pub(crate) fn permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> { 1064 let n_factorial = self.clone().factorial(int)?; 1065 let n_minus_r_factorial = self.add(-rhs, int)?.factorial(int)?; 1066 n_factorial.div(&n_minus_r_factorial, int) 1067 } 1068 } 1069 enum NextDigitErr { 1070 Error(FendError), 1071 Terminated, 1072 } 1073 1074 impl From<FendError> for NextDigitErr { from(e: FendError) -> Self1075 fn from(e: FendError) -> Self { 1076 Self::Error(e) 1077 } 1078 } 1079 1080 #[derive(Copy, Clone, Eq, PartialEq, Debug)] 1081 enum MaxDigitsToPrint { 1082 /// Print all digits, possibly by writing recurring decimals in parentheses 1083 AllDigits, 1084 /// Print only the given number of decimal places, omitting any trailing zeroes 1085 DecimalPlaces(usize), 1086 /// Print only the given number of dps, but ignore leading zeroes after the decimal point 1087 DpButIgnoreLeadingZeroes(usize), 1088 } 1089 1090 impl ops::Neg for BigRat { 1091 type Output = Self; 1092 neg(self) -> Self1093 fn neg(self) -> Self { 1094 Self { 1095 sign: self.sign.flip(), 1096 ..self 1097 } 1098 } 1099 } 1100 1101 impl From<u64> for BigRat { from(i: u64) -> Self1102 fn from(i: u64) -> Self { 1103 Self { 1104 sign: Sign::Positive, 1105 num: i.into(), 1106 den: 1.into(), 1107 } 1108 } 1109 } 1110 1111 impl From<BigUint> for BigRat { from(n: BigUint) -> Self1112 fn from(n: BigUint) -> Self { 1113 Self { 1114 sign: Sign::Positive, 1115 num: n, 1116 den: BigUint::from(1), 1117 } 1118 } 1119 } 1120 1121 #[derive(Default)] 1122 pub(crate) struct FormatOptions { 1123 pub(crate) base: Base, 1124 pub(crate) style: FormattingStyle, 1125 pub(crate) term: &'static str, 1126 pub(crate) use_parens_if_fraction: bool, 1127 } 1128 1129 impl Format for BigRat { 1130 type Params = FormatOptions; 1131 type Out = FormattedBigRat; 1132 1133 // Formats as an integer if possible, or a terminating float, otherwise as 1134 // either a fraction or a potentially approximated floating-point number. 1135 // The result 'exact' field indicates whether the number was exact or not. format<I: Interrupt>(&self, params: &Self::Params, int: &I) -> FResult<Exact<Self::Out>>1136 fn format<I: Interrupt>(&self, params: &Self::Params, int: &I) -> FResult<Exact<Self::Out>> { 1137 let base = params.base; 1138 let style = params.style; 1139 let term = params.term; 1140 let use_parens_if_fraction = params.use_parens_if_fraction; 1141 1142 let mut x = self.clone().simplify(int)?; 1143 let sign = if x.sign == Sign::Positive || x == 0.into() { 1144 Sign::Positive 1145 } else { 1146 Sign::Negative 1147 }; 1148 x.sign = Sign::Positive; 1149 1150 // try as integer if possible 1151 if x.den == 1.into() { 1152 let sf_limit = if let FormattingStyle::SignificantFigures(sf) = style { 1153 Some(sf) 1154 } else { 1155 None 1156 }; 1157 return Self::format_as_integer( 1158 &x.num, 1159 base, 1160 sign, 1161 term, 1162 use_parens_if_fraction, 1163 sf_limit, 1164 int, 1165 ); 1166 } 1167 1168 let mut terminating_res = None; 1169 let mut terminating = || match terminating_res { 1170 None => { 1171 let t = x.terminates_in_base(base, int)?; 1172 terminating_res = Some(t); 1173 Ok(t) 1174 } 1175 Some(t) => Ok(t), 1176 }; 1177 let fraction = style == FormattingStyle::ImproperFraction 1178 || style == FormattingStyle::MixedFraction 1179 || (style == FormattingStyle::Exact && !terminating()?); 1180 if fraction { 1181 let mixed = style == FormattingStyle::MixedFraction || style == FormattingStyle::Exact; 1182 return x.format_as_fraction(base, sign, term, mixed, use_parens_if_fraction, int); 1183 } 1184 1185 // not a fraction, will be printed as a decimal 1186 x.format_as_decimal(style, base, sign, term, terminating, int) 1187 } 1188 } 1189 1190 #[derive(Debug)] 1191 enum FormattedBigRatType { 1192 // optional int, 1193 // bool whether to add a space before the string 1194 // followed by a string (empty, "i" or "pi"), 1195 // followed by whether to wrap the number in parentheses 1196 Integer(Option<FormattedBigUint>, bool, &'static str, bool), 1197 // optional int (for mixed fractions) 1198 // optional int (numerator) 1199 // space 1200 // string (empty, "i", "pi", etc.) 1201 // '/' 1202 // int (denominator) 1203 // string (empty, "i", "pi", etc.) (used for mixed fractions, e.g. 1 2/3 i) 1204 // bool (whether or not to wrap the fraction in parentheses) 1205 Fraction( 1206 Option<FormattedBigUint>, 1207 Option<FormattedBigUint>, 1208 bool, 1209 &'static str, 1210 FormattedBigUint, 1211 &'static str, 1212 bool, 1213 ), 1214 // string representation of decimal number (may or may not contain recurring digits) 1215 // space 1216 // string (empty, "i", "pi", etc.) 1217 Decimal(String, bool, &'static str), 1218 } 1219 1220 #[must_use] 1221 #[derive(Debug)] 1222 pub(crate) struct FormattedBigRat { 1223 // whether or not to print a minus sign 1224 sign: Sign, 1225 ty: FormattedBigRatType, 1226 } 1227 1228 impl fmt::Display for FormattedBigRat { fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>1229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 1230 if self.sign == Sign::Negative { 1231 write!(f, "-")?; 1232 } 1233 match &self.ty { 1234 FormattedBigRatType::Integer(int, space, isuf, use_parens) => { 1235 if *use_parens { 1236 write!(f, "(")?; 1237 } 1238 if let Some(int) = int { 1239 write!(f, "{int}")?; 1240 } 1241 if *space { 1242 write!(f, " ")?; 1243 } 1244 write!(f, "{isuf}")?; 1245 if *use_parens { 1246 write!(f, ")")?; 1247 } 1248 } 1249 FormattedBigRatType::Fraction(integer, num, space, isuf, den, isuf2, use_parens) => { 1250 if *use_parens { 1251 write!(f, "(")?; 1252 } 1253 if let Some(integer) = integer { 1254 write!(f, "{integer} ")?; 1255 } 1256 if let Some(num) = num { 1257 write!(f, "{num}")?; 1258 } 1259 if *space && !isuf.is_empty() { 1260 write!(f, " ")?; 1261 } 1262 write!(f, "{isuf}/{den}")?; 1263 if *space && !isuf2.is_empty() { 1264 write!(f, " ")?; 1265 } 1266 write!(f, "{isuf2}")?; 1267 if *use_parens { 1268 write!(f, ")")?; 1269 } 1270 } 1271 FormattedBigRatType::Decimal(s, space, term) => { 1272 write!(f, "{s}")?; 1273 if *space { 1274 write!(f, " ")?; 1275 } 1276 write!(f, "{term}")?; 1277 } 1278 } 1279 Ok(()) 1280 } 1281 } 1282 1283 #[cfg(test)] 1284 mod tests { 1285 use super::sign::Sign; 1286 use super::BigRat; 1287 1288 use crate::num::biguint::BigUint; 1289 use crate::result::FResult; 1290 use std::mem; 1291 1292 #[test] test_bigrat_from()1293 fn test_bigrat_from() { 1294 mem::drop(BigRat::from(2)); 1295 mem::drop(BigRat::from(0)); 1296 mem::drop(BigRat::from(u64::MAX)); 1297 mem::drop(BigRat::from(u64::from(u32::MAX))); 1298 } 1299 1300 #[test] test_addition() -> FResult<()>1301 fn test_addition() -> FResult<()> { 1302 let int = &crate::interrupt::Never; 1303 let two = BigRat::from(2); 1304 assert_eq!(two.clone().add(two, int)?, BigRat::from(4)); 1305 Ok(()) 1306 } 1307 1308 #[test] test_cmp()1309 fn test_cmp() { 1310 assert!( 1311 BigRat { 1312 sign: Sign::Positive, 1313 num: BigUint::from(16), 1314 den: BigUint::from(9) 1315 } < BigRat::from(2) 1316 ); 1317 } 1318 1319 #[test] test_cmp_2()1320 fn test_cmp_2() { 1321 assert!( 1322 BigRat { 1323 sign: Sign::Positive, 1324 num: BigUint::from(36), 1325 den: BigUint::from(49) 1326 } < BigRat { 1327 sign: Sign::Positive, 1328 num: BigUint::from(3), 1329 den: BigUint::from(4) 1330 } 1331 ); 1332 } 1333 } 1334