fend_core/num/
real.rs

1use crate::DecimalSeparatorStyle;
2use crate::error::{FendError, Interrupt};
3use crate::format::Format;
4use crate::num::Exact;
5use crate::num::bigrat::{BigRat, FormattedBigRat};
6use crate::num::{Base, FormattingStyle};
7use crate::result::FResult;
8use crate::serialize::{Deserialize, Serialize};
9use std::cmp::Ordering;
10use std::ops::Neg;
11use std::{fmt, hash, io};
12
13use super::bigrat;
14use super::biguint::BigUint;
15
16#[derive(Clone)]
17pub(crate) struct Real {
18	pattern: Pattern,
19}
20
21impl fmt::Debug for Real {
22	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23		match &self.pattern {
24			Pattern::Simple(x) => write!(f, "{x:?}"),
25			Pattern::Pi(x) => {
26				if x.is_definitely_one() {
27					write!(f, "pi")
28				} else {
29					write!(f, "{x:?} * pi")
30				}
31			}
32		}
33	}
34}
35
36#[derive(Clone, Debug)]
37pub(crate) enum Pattern {
38	/// a simple fraction
39	Simple(BigRat),
40	// n * pi
41	Pi(BigRat),
42}
43
44impl hash::Hash for Real {
45	fn hash<H: hash::Hasher>(&self, state: &mut H) {
46		match &self.pattern {
47			Pattern::Simple(r) | Pattern::Pi(r) => r.hash(state),
48		}
49	}
50}
51
52impl Real {
53	pub(crate) fn compare<I: Interrupt>(&self, other: &Self, int: &I) -> FResult<Ordering> {
54		Ok(match (&self.pattern, &other.pattern) {
55			(Pattern::Simple(a), Pattern::Simple(b)) | (Pattern::Pi(a), Pattern::Pi(b)) => a.cmp(b),
56			_ => {
57				let a = self.clone().approximate(int)?;
58				let b = other.clone().approximate(int)?;
59				a.cmp(&b)
60			}
61		})
62	}
63
64	pub(crate) fn serialize(&self, write: &mut impl io::Write) -> FResult<()> {
65		match &self.pattern {
66			Pattern::Simple(s) => {
67				1u8.serialize(write)?;
68				s.serialize(write)?;
69			}
70			Pattern::Pi(n) => {
71				2u8.serialize(write)?;
72				n.serialize(write)?;
73			}
74		}
75		Ok(())
76	}
77
78	pub(crate) fn deserialize(read: &mut impl io::Read) -> FResult<Self> {
79		Ok(Self {
80			pattern: match u8::deserialize(read)? {
81				1 => Pattern::Simple(BigRat::deserialize(read)?),
82				2 => Pattern::Pi(BigRat::deserialize(read)?),
83				_ => return Err(FendError::DeserializationError),
84			},
85		})
86	}
87
88	pub(crate) fn is_integer(&self) -> bool {
89		match &self.pattern {
90			Pattern::Simple(s) => s.is_integer(),
91			Pattern::Pi(_) => false,
92		}
93	}
94
95	fn approximate<I: Interrupt>(self, int: &I) -> FResult<BigRat> {
96		match self.pattern {
97			Pattern::Simple(s) => Ok(s),
98			Pattern::Pi(n) => {
99				let required_accuracy_dp = 20;
100				let mut pi = BigRat::from(0);
101				for k in 0..=(required_accuracy_dp / 14) {
102					let mut term = BigRat::from(1);
103					if k % 2 == 1 {
104						term = -term;
105					}
106					let k = BigRat::from(k);
107					term = term.mul(&BigRat::from(6).mul(&k, int)?.factorial(int)?, int)?;
108					term = term.mul(
109						&BigRat::from(545_140_134)
110							.mul(&k, int)?
111							.add(BigRat::from(13_591_409), int)?,
112						int,
113					)?;
114					term = term.div(&BigRat::from(3).mul(&k, int)?.factorial(int)?, int)?;
115					term = term.div(
116						&k.clone().factorial(int)?.pow(BigRat::from(3), int)?.value,
117						int,
118					)?;
119					term = term.div(
120						&BigRat::from(640_320)
121							.pow(
122								BigRat::from(3)
123									.mul(&k, int)?
124									.add(BigRat::from(3).div(&BigRat::from(2), int)?, int)?,
125								int,
126							)?
127							.value,
128						int,
129					)?;
130					pi = pi.add(term, int)?;
131				}
132				pi = pi.mul(&BigRat::from(12), int)?;
133				pi = pi.pow(-BigRat::from(1), int)?.value;
134				Ok(n.mul(&pi, int)?)
135			}
136		}
137	}
138
139	pub(crate) fn try_as_biguint<I: Interrupt>(self, int: &I) -> FResult<BigUint> {
140		match self.pattern {
141			Pattern::Simple(s) => s.try_as_biguint(int),
142			Pattern::Pi(n) => {
143				if n == 0.into() {
144					Ok(BigUint::Small(0))
145				} else {
146					Err(FendError::CannotConvertToInteger)
147				}
148			}
149		}
150	}
151
152	pub(crate) fn try_as_i64<I: Interrupt>(self, int: &I) -> FResult<i64> {
153		match self.pattern {
154			Pattern::Simple(s) => s.try_as_i64(int),
155			Pattern::Pi(n) => {
156				if n == 0.into() {
157					Ok(0)
158				} else {
159					Err(FendError::CannotConvertToInteger)
160				}
161			}
162		}
163	}
164
165	pub(crate) fn try_as_usize<I: Interrupt>(self, int: &I) -> FResult<usize> {
166		match self.pattern {
167			Pattern::Simple(s) => s.try_as_usize(int),
168			Pattern::Pi(n) => {
169				if n == 0.into() {
170					Ok(0)
171				} else {
172					Err(FendError::CannotConvertToInteger)
173				}
174			}
175		}
176	}
177
178	// sin works for all real numbers
179	pub(crate) fn sin<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
180		Ok(match self.pattern {
181			Pattern::Simple(s) => s.sin(int)?.apply(Self::from),
182			Pattern::Pi(n) => {
183				if n < 0.into() {
184					let s = Self {
185						pattern: Pattern::Pi(n),
186					};
187					// sin(-x) == -sin(x)
188					return Ok(-Self::sin(-s, int)?);
189				}
190				if let Ok(integer) = n.clone().mul(&6.into(), int)?.try_as_usize(int) {
191					// values from https://en.wikipedia.org/wiki/Exact_trigonometric_values
192					if integer.is_multiple_of(6) {
193						return Ok(Exact::new(Self::from(0), true));
194					} else if integer % 12 == 3 {
195						return Ok(Exact::new(Self::from(1), true));
196					} else if integer % 12 == 9 {
197						return Ok(Exact::new(-Self::from(1), true));
198					} else if integer % 12 == 1 || integer % 12 == 5 {
199						return Exact::new(Self::from(1), true)
200							.div(&Exact::new(2.into(), true), int);
201					} else if integer % 12 == 7 || integer % 12 == 11 {
202						return Exact::new(-Self::from(1), true)
203							.div(&Exact::new(2.into(), true), int);
204					}
205				}
206				let s = Self {
207					pattern: Pattern::Pi(n),
208				};
209				s.approximate(int)?.sin(int)?.apply(Self::from)
210			}
211		})
212	}
213
214	pub(crate) fn cos<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
215		// cos(x) = sin(x + pi/2)
216		let half_pi = Exact::new(Self::pi(), true).div(&Exact::new(Self::from(2), true), int)?;
217		Exact::new(self, true).add(half_pi, int)?.value.sin(int)
218	}
219
220	pub(crate) fn asin<I: Interrupt>(self, int: &I) -> FResult<Self> {
221		Ok(Self::from(self.approximate(int)?.asin(int)?))
222	}
223
224	pub(crate) fn acos<I: Interrupt>(self, int: &I) -> FResult<Self> {
225		Ok(Self::from(self.approximate(int)?.acos(int)?))
226	}
227
228	pub(crate) fn atan<I: Interrupt>(self, int: &I) -> FResult<Self> {
229		Ok(Self::from(self.approximate(int)?.atan(int)?))
230	}
231
232	pub(crate) fn atan2<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
233		Ok(Self::from(
234			self.approximate(int)?.atan2(rhs.approximate(int)?, int)?,
235		))
236	}
237
238	pub(crate) fn sinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
239		Ok(Self::from(self.approximate(int)?.sinh(int)?))
240	}
241
242	pub(crate) fn cosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
243		Ok(Self::from(self.approximate(int)?.cosh(int)?))
244	}
245
246	pub(crate) fn tanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
247		Ok(Self::from(self.approximate(int)?.tanh(int)?))
248	}
249
250	pub(crate) fn asinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
251		Ok(Self::from(self.approximate(int)?.asinh(int)?))
252	}
253
254	pub(crate) fn acosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
255		Ok(Self::from(self.approximate(int)?.acosh(int)?))
256	}
257
258	pub(crate) fn atanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
259		Ok(Self::from(self.approximate(int)?.atanh(int)?))
260	}
261
262	// For all logs: value must be greater than 0
263	pub(crate) fn ln<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
264		Ok(self.approximate(int)?.ln(int)?.apply(Self::from))
265	}
266
267	pub(crate) fn log2<I: Interrupt>(self, int: &I) -> FResult<Self> {
268		Ok(Self::from(self.approximate(int)?.log2(int)?))
269	}
270
271	pub(crate) fn log10<I: Interrupt>(self, int: &I) -> FResult<Self> {
272		Ok(Self::from(self.approximate(int)?.log10(int)?))
273	}
274
275	pub(crate) fn factorial<I: Interrupt>(self, int: &I) -> FResult<Self> {
276		Ok(Self::from(self.approximate(int)?.factorial(int)?))
277	}
278
279	pub(crate) fn floor<I: Interrupt>(self, int: &I) -> FResult<Self> {
280		Ok(Self::from(self.approximate(int)?.floor(int)?))
281	}
282
283	pub(crate) fn ceil<I: Interrupt>(self, int: &I) -> FResult<Self> {
284		Ok(Self::from(self.approximate(int)?.ceil(int)?))
285	}
286
287	pub(crate) fn round<I: Interrupt>(self, int: &I) -> FResult<Self> {
288		Ok(Self::from(self.approximate(int)?.round(int)?))
289	}
290
291	pub(crate) fn format<I: Interrupt>(
292		&self,
293		base: Base,
294		mut style: FormattingStyle,
295		imag: bool,
296		use_parens_if_fraction: bool,
297		decimal_separator: DecimalSeparatorStyle,
298		int: &I,
299	) -> FResult<Exact<Formatted>> {
300		let mut pi = false;
301		if style == FormattingStyle::Exact
302			&& !self.is_zero()
303			&& let Pattern::Pi(_) = self.pattern
304		{
305			pi = true;
306		}
307
308		let term = match (imag, pi) {
309			(false, false) => "",
310			(false, true) => "\u{3c0}", // pi symbol
311			(true, false) => "i",
312			(true, true) => "\u{3c0}i",
313		};
314
315		let mut override_exact = true;
316
317		let rat = match &self.pattern {
318			Pattern::Simple(f) => f,
319			Pattern::Pi(f) => {
320				if pi {
321					f
322				} else {
323					override_exact = false;
324					if style == FormattingStyle::Auto {
325						style = FormattingStyle::DecimalPlaces(10);
326					}
327					&self.clone().approximate(int)?
328				}
329			}
330		};
331
332		let formatted = rat.format(
333			&bigrat::FormatOptions {
334				base,
335				style,
336				term,
337				use_parens_if_fraction,
338				decimal_separator,
339			},
340			int,
341		)?;
342		let exact = formatted.exact && override_exact;
343		Ok(Exact::new(
344			Formatted {
345				num: formatted.value,
346			},
347			exact,
348		))
349	}
350
351	pub(crate) fn exp<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
352		Ok(self.approximate(int)?.exp(int)?.apply(Self::from))
353	}
354
355	pub(crate) fn pow<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Exact<Self>> {
356		// x^1 == x
357		if let Pattern::Simple(n) = &rhs.pattern
358			&& n == &1.into()
359		{
360			return Ok(Exact::new(self, true));
361		}
362
363		// 1^x == 1
364		if let Pattern::Simple(n) = &self.pattern
365			&& n == &1.into()
366		{
367			return Ok(Exact::new(1.into(), true));
368		}
369
370		if let (Pattern::Simple(a), Pattern::Simple(b)) =
371			(self.clone().pattern, rhs.clone().pattern)
372		{
373			Ok(a.pow(b, int)?.apply(Self::from))
374		} else {
375			Ok(self
376				.approximate(int)?
377				.pow(rhs.approximate(int)?, int)?
378				.combine(false)
379				.apply(Self::from))
380		}
381	}
382
383	pub(crate) fn root_n<I: Interrupt>(self, n: &Self, int: &I) -> FResult<Exact<Self>> {
384		// TODO: Combining these match blocks is not currently possible because
385		// 'binding by-move and by-ref in the same pattern is unstable'
386		// https://github.com/rust-lang/rust/pull/76119
387		Ok(match self.pattern {
388			Pattern::Simple(a) => match &n.pattern {
389				Pattern::Simple(b) => a.root_n(b, int)?.apply(Self::from),
390				Pattern::Pi(_) => {
391					let b = n.clone().approximate(int)?;
392					a.root_n(&b, int)?.apply(Self::from).combine(false)
393				}
394			},
395			Pattern::Pi(_) => {
396				let a = self.clone().approximate(int)?;
397				let b = n.clone().approximate(int)?;
398				a.root_n(&b, int)?.apply(Self::from).combine(false)
399			}
400		})
401	}
402
403	pub(crate) fn pi() -> Self {
404		Self {
405			pattern: Pattern::Pi(1.into()),
406		}
407	}
408
409	pub(crate) fn is_zero(&self) -> bool {
410		match &self.pattern {
411			Pattern::Simple(a) | Pattern::Pi(a) => a.is_definitely_zero() || a == &0.into(),
412		}
413	}
414
415	pub(crate) fn is_pos(&self) -> bool {
416		match &self.pattern {
417			Pattern::Simple(a) | Pattern::Pi(a) => !a.is_definitely_zero() && a > &0.into(),
418		}
419	}
420
421	pub(crate) fn is_neg(&self) -> bool {
422		match &self.pattern {
423			Pattern::Simple(a) | Pattern::Pi(a) => !a.is_definitely_zero() && a < &0.into(),
424		}
425	}
426
427	pub(crate) fn between_plus_minus_one_incl<I: Interrupt>(&self, int: &I) -> FResult<bool> {
428		// -1 <= x <= 1
429		Ok(Self::from(1).neg().compare(self, int)? != Ordering::Greater
430			&& self.compare(&1.into(), int)? != Ordering::Greater)
431	}
432
433	pub(crate) fn between_plus_minus_one_excl<I: Interrupt>(&self, int: &I) -> FResult<bool> {
434		// -1 < x < 1
435		Ok(Self::from(1).neg().compare(self, int)? == Ordering::Less
436			&& self.compare(&1.into(), int)? == Ordering::Less)
437	}
438
439	pub(crate) fn is_definitely_zero(&self) -> bool {
440		match &self.pattern {
441			Pattern::Simple(a) | Pattern::Pi(a) => a.is_definitely_zero(),
442		}
443	}
444
445	pub(crate) fn is_definitely_one(&self) -> bool {
446		match &self.pattern {
447			Pattern::Simple(a) => a.is_definitely_one(),
448			Pattern::Pi(_) => false,
449		}
450	}
451
452	pub(crate) fn expect_rational(self) -> FResult<BigRat> {
453		match self.pattern {
454			Pattern::Simple(a) => Ok(a),
455			Pattern::Pi(_) => Err(FendError::ExpectedARationalNumber),
456		}
457	}
458
459	pub(crate) fn modulo<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
460		Ok(Self::from(
461			self.expect_rational()?
462				.modulo(rhs.expect_rational()?, int)?,
463		))
464	}
465
466	pub(crate) fn bitwise<I: Interrupt>(
467		self,
468		rhs: Self,
469		op: crate::ast::BitwiseBop,
470		int: &I,
471	) -> FResult<Self> {
472		Ok(Self::from(self.expect_rational()?.bitwise(
473			rhs.expect_rational()?,
474			op,
475			int,
476		)?))
477	}
478
479	pub(crate) fn combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
480		Ok(Self::from(
481			self.expect_rational()?
482				.combination(rhs.expect_rational()?, int)?,
483		))
484	}
485
486	pub(crate) fn permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
487		Ok(Self::from(
488			self.expect_rational()?
489				.permutation(rhs.expect_rational()?, int)?,
490		))
491	}
492}
493
494impl Exact<Real> {
495	pub(crate) fn add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
496		if self.exact && self.value.is_zero() {
497			return Ok(rhs);
498		} else if rhs.exact && rhs.value.is_zero() {
499			return Ok(self);
500		}
501		let args_exact = self.exact && rhs.exact;
502		Ok(
503			match (self.clone().value.pattern, rhs.clone().value.pattern) {
504				(Pattern::Simple(a), Pattern::Simple(b)) => {
505					Self::new(a.add(b, int)?.into(), args_exact)
506				}
507				(Pattern::Pi(a), Pattern::Pi(b)) => Self::new(
508					Real {
509						pattern: Pattern::Pi(a.add(b, int)?),
510					},
511					args_exact,
512				),
513				_ => {
514					let a = self.value.approximate(int)?;
515					let b = rhs.value.approximate(int)?;
516					Self::new(a.add(b, int)?.into(), false)
517				}
518			},
519		)
520	}
521
522	pub(crate) fn mul<I: Interrupt>(self, rhs: Exact<&Real>, int: &I) -> FResult<Self> {
523		if self.exact && self.value.is_zero() {
524			return Ok(self);
525		} else if rhs.exact && rhs.value.is_zero() {
526			return Ok(Self::new(rhs.value.clone(), rhs.exact));
527		}
528		let args_exact = self.exact && rhs.exact;
529		Ok(match self.value.pattern {
530			Pattern::Simple(a) => match &rhs.value.pattern {
531				Pattern::Simple(b) => Self::new(a.mul(b, int)?.into(), args_exact),
532				Pattern::Pi(b) => Self::new(
533					Real {
534						pattern: Pattern::Pi(a.mul(b, int)?),
535					},
536					args_exact,
537				),
538			},
539			Pattern::Pi(a) => match &rhs.value.pattern {
540				Pattern::Simple(b) => Self::new(
541					Real {
542						pattern: Pattern::Pi(a.mul(b, int)?),
543					},
544					args_exact,
545				),
546				Pattern::Pi(_) => Self::new(
547					Real {
548						pattern: Pattern::Pi(a.mul(&rhs.value.clone().approximate(int)?, int)?),
549					},
550					false,
551				),
552			},
553		})
554	}
555
556	pub(crate) fn div<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self> {
557		if rhs.value.is_zero() {
558			return Err(FendError::DivideByZero);
559		}
560		if self.exact && self.value.is_zero() {
561			return Ok(self);
562		}
563		Ok(match self.value.pattern {
564			Pattern::Simple(a) => match &rhs.value.pattern {
565				Pattern::Simple(b) => Self::new(a.div(b, int)?.into(), self.exact && rhs.exact),
566				Pattern::Pi(_) => Self::new(
567					a.div(&rhs.value.clone().approximate(int)?, int)?.into(),
568					false,
569				),
570			},
571			Pattern::Pi(a) => match &rhs.value.pattern {
572				Pattern::Simple(b) => Self::new(
573					Real {
574						pattern: Pattern::Pi(a.div(b, int)?),
575					},
576					self.exact && rhs.exact,
577				),
578				Pattern::Pi(b) => Self::new(a.div(b, int)?.into(), self.exact && rhs.exact),
579			},
580		})
581	}
582}
583
584impl Neg for Real {
585	type Output = Self;
586
587	fn neg(self) -> Self {
588		match self.pattern {
589			Pattern::Simple(s) => Self::from(-s),
590			Pattern::Pi(n) => Self {
591				pattern: Pattern::Pi(-n),
592			},
593		}
594	}
595}
596
597impl From<u64> for Real {
598	fn from(i: u64) -> Self {
599		Self {
600			pattern: Pattern::Simple(i.into()),
601		}
602	}
603}
604
605impl From<BigRat> for Real {
606	fn from(n: BigRat) -> Self {
607		Self {
608			pattern: Pattern::Simple(n),
609		}
610	}
611}
612
613#[derive(Debug)]
614pub(crate) struct Formatted {
615	num: FormattedBigRat,
616}
617
618impl fmt::Display for Formatted {
619	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620		write!(f, "{}", self.num)
621	}
622}