xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/fend-core-1.4.6/src/num/bigrat.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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