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::CborValue;
9use std::cmp::Ordering;
10use std::ops::Neg;
11use std::{fmt, hash};
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 Simple(BigRat),
40 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) -> CborValue {
65 match &self.pattern {
66 Pattern::Simple(s) => s.serialize(),
67 Pattern::Pi(n) => {
68 CborValue::Tag(80000, Box::new(n.serialize()))
70 }
71 }
72 }
73
74 pub(crate) fn deserialize(value: CborValue) -> FResult<Self> {
75 Ok(Self {
76 pattern: match value {
77 CborValue::Tag(80000, inner) => Pattern::Pi(BigRat::deserialize(*inner)?),
78 value => Pattern::Simple(BigRat::deserialize(value)?),
79 },
80 })
81 }
82
83 pub(crate) fn is_integer(&self) -> bool {
84 match &self.pattern {
85 Pattern::Simple(s) => s.is_integer(),
86 Pattern::Pi(_) => false,
87 }
88 }
89
90 fn approximate<I: Interrupt>(self, int: &I) -> FResult<BigRat> {
91 match self.pattern {
92 Pattern::Simple(s) => Ok(s),
93 Pattern::Pi(n) => {
94 let num = BigRat::from(2_646_693_125_139_304_345);
101 let den = BigRat::from(842_468_587_426_513_207);
102 let pi = num.div(&den, int)?;
103 Ok(n.mul(&pi, int)?)
104 }
105 }
106 }
107
108 pub(crate) fn try_as_biguint<I: Interrupt>(self, int: &I) -> FResult<BigUint> {
109 match self.pattern {
110 Pattern::Simple(s) => s.try_as_biguint(int),
111 Pattern::Pi(n) => {
112 if n == 0.into() {
113 Ok(BigUint::Small(0))
114 } else {
115 Err(FendError::CannotConvertToInteger)
116 }
117 }
118 }
119 }
120
121 pub(crate) fn try_as_i64<I: Interrupt>(self, int: &I) -> FResult<i64> {
122 match self.pattern {
123 Pattern::Simple(s) => s.try_as_i64(int),
124 Pattern::Pi(n) => {
125 if n == 0.into() {
126 Ok(0)
127 } else {
128 Err(FendError::CannotConvertToInteger)
129 }
130 }
131 }
132 }
133
134 pub(crate) fn try_as_usize<I: Interrupt>(self, int: &I) -> FResult<usize> {
135 match self.pattern {
136 Pattern::Simple(s) => s.try_as_usize(int),
137 Pattern::Pi(n) => {
138 if n == 0.into() {
139 Ok(0)
140 } else {
141 Err(FendError::CannotConvertToInteger)
142 }
143 }
144 }
145 }
146
147 pub(crate) fn sin<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
149 Ok(match self.pattern {
150 Pattern::Simple(s) => s.sin(int)?.apply(Self::from),
151 Pattern::Pi(n) => {
152 if n < 0.into() {
153 let s = Self {
154 pattern: Pattern::Pi(n),
155 };
156 return Ok(-Self::sin(-s, int)?);
158 }
159 if let Ok(n_times_6) = n.clone().mul(&6.into(), int)?.try_as_usize(int) {
160 match n_times_6 % 12 {
164 0 | 6 => return Ok(Exact::new(Self::from(0), true)),
166 1 | 5 => {
168 return Exact::new(Self::from(1), true)
169 .div(&Exact::new(2.into(), true), int);
170 }
171 3 => return Ok(Exact::new(Self::from(1), true)),
173 7 | 11 => {
175 return Exact::new(-Self::from(1), true)
176 .div(&Exact::new(2.into(), true), int);
177 }
178 9 => return Ok(Exact::new(-Self::from(1), true)),
180 _ => {}
181 }
182 }
183 let s = Self {
184 pattern: Pattern::Pi(n),
185 };
186 s.approximate(int)?.sin(int)?.apply(Self::from)
187 }
188 })
189 }
190
191 pub(crate) fn cos<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
193 Ok(match self.pattern {
194 Pattern::Simple(c) => c.cos(int)?.apply(Self::from),
195 Pattern::Pi(n) => {
196 if n < 0.into() {
197 let c = Self {
198 pattern: Pattern::Pi(n),
199 };
200 return Self::cos(-c, int);
202 }
203 if let Ok(n_times_6) = n.clone().mul(&6.into(), int)?.try_as_usize(int) {
204 match n_times_6 % 12 {
208 0 => return Ok(Exact::new(Self::from(1), true)),
210 2 | 10 => {
212 return Exact::new(Self::from(1), true)
213 .div(&Exact::new(2.into(), true), int);
214 }
215 3 | 9 => return Ok(Exact::new(Self::from(0), true)),
217 4 | 8 => {
219 return Exact::new(-Self::from(1), true)
220 .div(&Exact::new(2.into(), true), int);
221 }
222 6 => return Ok(Exact::new(-Self::from(1), true)),
224 _ => {}
225 }
226 }
227 let c = Self {
228 pattern: Pattern::Pi(n),
229 };
230 c.approximate(int)?.cos(int)?.apply(Self::from)
231 }
232 })
233 }
234
235 pub(crate) fn asin<I: Interrupt>(self, int: &I) -> FResult<Self> {
236 Ok(Self::from(self.approximate(int)?.asin(int)?))
237 }
238
239 pub(crate) fn acos<I: Interrupt>(self, int: &I) -> FResult<Self> {
240 Ok(Self::from(self.approximate(int)?.acos(int)?))
241 }
242
243 pub(crate) fn atan<I: Interrupt>(self, int: &I) -> FResult<Self> {
244 Ok(Self::from(self.approximate(int)?.atan(int)?))
245 }
246
247 pub(crate) fn atan2<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
248 Ok(Self::from(
249 self.approximate(int)?.atan2(rhs.approximate(int)?, int)?,
250 ))
251 }
252
253 pub(crate) fn sinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
254 Ok(Self::from(self.approximate(int)?.sinh(int)?))
255 }
256
257 pub(crate) fn cosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
258 Ok(Self::from(self.approximate(int)?.cosh(int)?))
259 }
260
261 pub(crate) fn tanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
262 Ok(Self::from(self.approximate(int)?.tanh(int)?))
263 }
264
265 pub(crate) fn asinh<I: Interrupt>(self, int: &I) -> FResult<Self> {
266 Ok(Self::from(self.approximate(int)?.asinh(int)?))
267 }
268
269 pub(crate) fn acosh<I: Interrupt>(self, int: &I) -> FResult<Self> {
270 Ok(Self::from(self.approximate(int)?.acosh(int)?))
271 }
272
273 pub(crate) fn atanh<I: Interrupt>(self, int: &I) -> FResult<Self> {
274 Ok(Self::from(self.approximate(int)?.atanh(int)?))
275 }
276
277 pub(crate) fn ln<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
279 Ok(self.approximate(int)?.ln(int)?.apply(Self::from))
280 }
281
282 pub(crate) fn log2<I: Interrupt>(self, int: &I) -> FResult<Self> {
283 Ok(Self::from(self.approximate(int)?.log2(int)?))
284 }
285
286 pub(crate) fn log10<I: Interrupt>(self, int: &I) -> FResult<Self> {
287 Ok(Self::from(self.approximate(int)?.log10(int)?))
288 }
289
290 pub(crate) fn factorial<I: Interrupt>(self, int: &I) -> FResult<Self> {
291 Ok(Self::from(self.approximate(int)?.factorial(int)?))
292 }
293
294 pub(crate) fn floor<I: Interrupt>(self, int: &I) -> FResult<Self> {
295 Ok(Self::from(self.approximate(int)?.floor(int)?))
296 }
297
298 pub(crate) fn ceil<I: Interrupt>(self, int: &I) -> FResult<Self> {
299 Ok(Self::from(self.approximate(int)?.ceil(int)?))
300 }
301
302 pub(crate) fn round<I: Interrupt>(self, int: &I) -> FResult<Self> {
303 Ok(Self::from(self.approximate(int)?.round(int)?))
304 }
305
306 pub(crate) fn format<I: Interrupt>(
307 &self,
308 base: Base,
309 mut style: FormattingStyle,
310 imag: bool,
311 use_parens_if_fraction: bool,
312 decimal_separator: DecimalSeparatorStyle,
313 int: &I,
314 ) -> FResult<Exact<Formatted>> {
315 let mut pi = false;
316 if style == FormattingStyle::Exact
317 && !self.is_zero()
318 && let Pattern::Pi(_) = self.pattern
319 {
320 pi = true;
321 }
322
323 let term = match (imag, pi) {
324 (false, false) => "",
325 (false, true) => "\u{3c0}", (true, false) => "i",
327 (true, true) => "\u{3c0}i",
328 };
329
330 let mut override_exact = true;
331
332 let rat = match &self.pattern {
333 Pattern::Simple(f) => f,
334 Pattern::Pi(f) => {
335 if pi {
336 f
337 } else {
338 override_exact = false;
339 if style == FormattingStyle::Auto {
340 style = FormattingStyle::DecimalPlaces(10);
341 }
342 &self.clone().approximate(int)?
343 }
344 }
345 };
346
347 let formatted = rat.format(
348 &bigrat::FormatOptions {
349 base,
350 style,
351 term,
352 use_parens_if_fraction,
353 decimal_separator,
354 },
355 int,
356 )?;
357 let exact = formatted.exact && override_exact;
358 Ok(Exact::new(
359 Formatted {
360 num: formatted.value,
361 },
362 exact,
363 ))
364 }
365
366 pub(crate) fn exp<I: Interrupt>(self, int: &I) -> FResult<Exact<Self>> {
367 Ok(self.approximate(int)?.exp(int)?.apply(Self::from))
368 }
369
370 pub(crate) fn pow<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Exact<Self>> {
371 if let Pattern::Simple(n) = &rhs.pattern
373 && n == &1.into()
374 {
375 return Ok(Exact::new(self, true));
376 }
377
378 if let Pattern::Simple(n) = &self.pattern
380 && n == &1.into()
381 {
382 return Ok(Exact::new(1.into(), true));
383 }
384
385 if let (Pattern::Simple(a), Pattern::Simple(b)) =
386 (self.clone().pattern, rhs.clone().pattern)
387 {
388 Ok(a.pow(b, int)?.apply(Self::from))
389 } else {
390 Ok(self
391 .approximate(int)?
392 .pow(rhs.approximate(int)?, int)?
393 .combine(false)
394 .apply(Self::from))
395 }
396 }
397
398 pub(crate) fn root_n<I: Interrupt>(self, n: &Self, int: &I) -> FResult<Exact<Self>> {
399 Ok(match self.pattern {
403 Pattern::Simple(a) => match &n.pattern {
404 Pattern::Simple(b) => a.root_n(b, int)?.apply(Self::from),
405 Pattern::Pi(_) => {
406 let b = n.clone().approximate(int)?;
407 a.root_n(&b, int)?.apply(Self::from).combine(false)
408 }
409 },
410 Pattern::Pi(_) => {
411 let a = self.clone().approximate(int)?;
412 let b = n.clone().approximate(int)?;
413 a.root_n(&b, int)?.apply(Self::from).combine(false)
414 }
415 })
416 }
417
418 pub(crate) fn pi() -> Self {
419 Self {
420 pattern: Pattern::Pi(1.into()),
421 }
422 }
423
424 pub(crate) fn is_zero(&self) -> bool {
425 match &self.pattern {
426 Pattern::Simple(a) | Pattern::Pi(a) => a.is_definitely_zero() || a == &0.into(),
427 }
428 }
429
430 pub(crate) fn is_pos(&self) -> bool {
431 match &self.pattern {
432 Pattern::Simple(a) | Pattern::Pi(a) => !a.is_definitely_zero() && a > &0.into(),
433 }
434 }
435
436 pub(crate) fn is_neg(&self) -> bool {
437 match &self.pattern {
438 Pattern::Simple(a) | Pattern::Pi(a) => !a.is_definitely_zero() && a < &0.into(),
439 }
440 }
441
442 pub(crate) fn between_plus_minus_one_incl<I: Interrupt>(&self, int: &I) -> FResult<bool> {
443 Ok(Self::from(1).neg().compare(self, int)? != Ordering::Greater
445 && self.compare(&1.into(), int)? != Ordering::Greater)
446 }
447
448 pub(crate) fn between_plus_minus_one_excl<I: Interrupt>(&self, int: &I) -> FResult<bool> {
449 Ok(Self::from(1).neg().compare(self, int)? == Ordering::Less
451 && self.compare(&1.into(), int)? == Ordering::Less)
452 }
453
454 pub(crate) fn is_definitely_zero(&self) -> bool {
455 match &self.pattern {
456 Pattern::Simple(a) | Pattern::Pi(a) => a.is_definitely_zero(),
457 }
458 }
459
460 pub(crate) fn is_definitely_one(&self) -> bool {
461 match &self.pattern {
462 Pattern::Simple(a) => a.is_definitely_one(),
463 Pattern::Pi(_) => false,
464 }
465 }
466
467 pub(crate) fn expect_rational(self) -> FResult<BigRat> {
468 match self.pattern {
469 Pattern::Simple(a) => Ok(a),
470 Pattern::Pi(_) => Err(FendError::ExpectedARationalNumber),
471 }
472 }
473
474 pub(crate) fn modulo<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
475 Ok(Self::from(
476 self.expect_rational()?
477 .modulo(rhs.expect_rational()?, int)?,
478 ))
479 }
480
481 pub(crate) fn bitwise<I: Interrupt>(
482 self,
483 rhs: Self,
484 op: crate::ast::BitwiseBop,
485 int: &I,
486 ) -> FResult<Self> {
487 Ok(Self::from(self.expect_rational()?.bitwise(
488 rhs.expect_rational()?,
489 op,
490 int,
491 )?))
492 }
493
494 pub(crate) fn combination<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
495 Ok(Self::from(
496 self.expect_rational()?
497 .combination(rhs.expect_rational()?, int)?,
498 ))
499 }
500
501 pub(crate) fn permutation<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
502 Ok(Self::from(
503 self.expect_rational()?
504 .permutation(rhs.expect_rational()?, int)?,
505 ))
506 }
507}
508
509impl Exact<Real> {
510 pub(crate) fn add<I: Interrupt>(self, rhs: Self, int: &I) -> FResult<Self> {
511 if self.exact && self.value.is_zero() {
512 return Ok(rhs);
513 } else if rhs.exact && rhs.value.is_zero() {
514 return Ok(self);
515 }
516 let args_exact = self.exact && rhs.exact;
517 Ok(
518 match (self.clone().value.pattern, rhs.clone().value.pattern) {
519 (Pattern::Simple(a), Pattern::Simple(b)) => {
520 Self::new(a.add(b, int)?.into(), args_exact)
521 }
522 (Pattern::Pi(a), Pattern::Pi(b)) => Self::new(
523 Real {
524 pattern: Pattern::Pi(a.add(b, int)?),
525 },
526 args_exact,
527 ),
528 _ => {
529 let a = self.value.approximate(int)?;
530 let b = rhs.value.approximate(int)?;
531 Self::new(a.add(b, int)?.into(), false)
532 }
533 },
534 )
535 }
536
537 pub(crate) fn mul<I: Interrupt>(self, rhs: Exact<&Real>, int: &I) -> FResult<Self> {
538 if self.exact && self.value.is_zero() {
539 return Ok(self);
540 } else if rhs.exact && rhs.value.is_zero() {
541 return Ok(Self::new(rhs.value.clone(), rhs.exact));
542 }
543 let args_exact = self.exact && rhs.exact;
544 Ok(match self.value.pattern {
545 Pattern::Simple(a) => match &rhs.value.pattern {
546 Pattern::Simple(b) => Self::new(a.mul(b, int)?.into(), args_exact),
547 Pattern::Pi(b) => Self::new(
548 Real {
549 pattern: Pattern::Pi(a.mul(b, int)?),
550 },
551 args_exact,
552 ),
553 },
554 Pattern::Pi(a) => match &rhs.value.pattern {
555 Pattern::Simple(b) => Self::new(
556 Real {
557 pattern: Pattern::Pi(a.mul(b, int)?),
558 },
559 args_exact,
560 ),
561 Pattern::Pi(_) => Self::new(
562 Real {
563 pattern: Pattern::Pi(a.mul(&rhs.value.clone().approximate(int)?, int)?),
564 },
565 false,
566 ),
567 },
568 })
569 }
570
571 pub(crate) fn div<I: Interrupt>(self, rhs: &Self, int: &I) -> FResult<Self> {
572 if rhs.value.is_zero() {
573 return Err(FendError::DivideByZero);
574 }
575 if self.exact && self.value.is_zero() {
576 return Ok(self);
577 }
578 Ok(match self.value.pattern {
579 Pattern::Simple(a) => match &rhs.value.pattern {
580 Pattern::Simple(b) => Self::new(a.div(b, int)?.into(), self.exact && rhs.exact),
581 Pattern::Pi(_) => Self::new(
582 a.div(&rhs.value.clone().approximate(int)?, int)?.into(),
583 false,
584 ),
585 },
586 Pattern::Pi(a) => match &rhs.value.pattern {
587 Pattern::Simple(b) => Self::new(
588 Real {
589 pattern: Pattern::Pi(a.div(b, int)?),
590 },
591 self.exact && rhs.exact,
592 ),
593 Pattern::Pi(b) => Self::new(a.div(b, int)?.into(), self.exact && rhs.exact),
594 },
595 })
596 }
597}
598
599impl Neg for Real {
600 type Output = Self;
601
602 fn neg(self) -> Self {
603 match self.pattern {
604 Pattern::Simple(s) => Self::from(-s),
605 Pattern::Pi(n) => Self {
606 pattern: Pattern::Pi(-n),
607 },
608 }
609 }
610}
611
612impl From<u64> for Real {
613 fn from(i: u64) -> Self {
614 Self {
615 pattern: Pattern::Simple(i.into()),
616 }
617 }
618}
619
620impl From<BigRat> for Real {
621 fn from(n: BigRat) -> Self {
622 Self {
623 pattern: Pattern::Simple(n),
624 }
625 }
626}
627
628#[derive(Debug)]
629pub(crate) struct Formatted {
630 num: FormattedBigRat,
631}
632
633impl fmt::Display for Formatted {
634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635 write!(f, "{}", self.num)
636 }
637}
638
639#[cfg(test)]
640mod tests {
641 use super::*;
642
643 #[test]
644 fn test_pi() {
645 let int = &crate::interrupt::Never;
646 let pi = Real {
647 pattern: Pattern::Pi(BigRat::from(1u64)),
648 };
649 let pi = pi.approximate(int).unwrap();
650 let pi_f64 = pi.clone().into_f64(int).unwrap();
651
652 assert!((pi_f64 - std::f64::consts::PI).abs() < 3. * f64::EPSILON);
653
654 let ten_power_37_pi_floor = BigRat::from(BigUint::Large(vec![
656 12_315_011_256_901_221_737,
657 1_703_060_790_043_277_294,
658 ]));
659 let ten_power_37_pi_ceil = BigRat::from(BigUint::Large(vec![
661 12_315_011_256_901_221_738,
662 1_703_060_790_043_277_294,
663 ]));
664 let ten_power_37 = BigRat::from(BigUint::Large(vec![
666 68_739_955_140_067_328,
667 542_101_086_242_752_217,
668 ]));
669 let ten_power_minus_37 = BigRat::from(1).div(&ten_power_37, int).unwrap();
670
671 let pi_floor = ten_power_37_pi_floor.mul(&ten_power_minus_37, int).unwrap();
672 let pi_ceil = ten_power_37_pi_ceil.mul(&ten_power_minus_37, int).unwrap();
673
674 assert_eq!(
676 pi_ceil.clone().add(pi_floor.clone().neg(), int).unwrap(),
677 ten_power_minus_37
678 );
679
680 let pi_minus_pi_floor = pi.clone().add(pi_floor.clone().neg(), int).unwrap();
681 let pi_ceil_minus_pi = pi_ceil.clone().add(pi.clone().neg(), int).unwrap();
682
683 assert!(pi_floor < pi && pi < pi_ceil);
685 assert!(BigRat::from(0) < pi_minus_pi_floor && pi_minus_pi_floor < ten_power_minus_37);
687 assert!(BigRat::from(0) < pi_ceil_minus_pi && pi_ceil_minus_pi < ten_power_minus_37);
689 }
690
691 #[test]
692 fn test_sin_exact_values() {
693 let int = &crate::interrupt::Never;
694 let angles = [
695 (2, 1, -1), (11, 6, -1), (3, 2, -1), (7, 6, -1), (1, 1, -1), (5, 6, -1), (1, 2, -1), (1, 6, -1), (0, 1, 1), (1, 6, 1), (1, 2, 1), (5, 6, 1), (1, 1, 1), (7, 6, 1), (3, 2, 1), (11, 6, 1), (2, 1, 1), ]
713 .map(|(num, den, sign)| {
714 (
715 Real {
716 pattern: Pattern::Pi(BigRat::from(num).div(&BigRat::from(den), int).unwrap()),
717 },
718 sign,
719 )
720 })
721 .map(|(br, sign)| if sign > 0 { br } else { -br });
722 let expected_sinuses = [
723 (0, 1, 1), (1, 2, 1), (1, 1, 1), (1, 2, 1), (0, 1, 1), (1, 2, -1), (1, 1, -1), (1, 2, -1), (0, 1, 1), (1, 2, 1), (1, 1, 1), (1, 2, 1), (0, 1, 1), (1, 2, -1), (1, 1, -1), (1, 2, -1), (0, 1, 1), ]
741 .map(|(num, den, sign)| {
742 (
743 BigRat::from(num).div(&BigRat::from(den), int).unwrap(),
744 sign,
745 )
746 })
747 .map(|(br, sign)| if sign > 0 { br } else { -br });
748
749 let actual_sinuses = angles.map(|r| r.sin(int).unwrap().value);
750
751 for (actual, expected) in actual_sinuses.into_iter().zip(expected_sinuses) {
752 assert_eq!(actual.approximate(int).unwrap(), expected);
753 }
754 }
755
756 #[test]
757 fn test_cos_exact_values() {
758 let int = &crate::interrupt::Never;
759 let angles = [
760 (2, 1, -1), (5, 3, -1), (3, 2, -1), (4, 3, -1), (1, 1, -1), (2, 3, -1), (1, 2, -1), (1, 3, -1), (0, 1, 1), (1, 3, 1), (1, 2, 1), (2, 3, 1), (1, 1, 1), (4, 3, 1), (3, 2, 1), (5, 3, 1), (2, 1, 1), ]
778 .map(|(num, den, sign)| {
779 (
780 Real {
781 pattern: Pattern::Pi(BigRat::from(num).div(&BigRat::from(den), int).unwrap()),
782 },
783 sign,
784 )
785 })
786 .map(|(br, sign)| if sign > 0 { br } else { -br });
787 let expected_cosines = [
788 (1, 1, 1), (1, 2, 1), (0, 1, 1), (1, 2, -1), (1, 1, -1), (1, 2, -1), (0, 1, 1), (1, 2, 1), (1, 1, 1), (1, 2, 1), (0, 1, 1), (1, 2, -1), (1, 1, -1), (1, 2, -1), (0, 1, 1), (1, 2, 1), (1, 1, 1), ]
806 .map(|(num, den, sign)| {
807 (
808 BigRat::from(num).div(&BigRat::from(den), int).unwrap(),
809 sign,
810 )
811 })
812 .map(|(br, sign)| if sign > 0 { br } else { -br });
813
814 let actual_cosines = angles.map(|r| r.cos(int).unwrap().value);
815
816 for (actual, expected) in actual_cosines.into_iter().zip(expected_cosines) {
817 assert_eq!(actual.approximate(int).unwrap(), expected);
818 }
819 }
820}