1use crate::common::util::log2_ceil;
4use crate::defs::SignedWord;
5use crate::defs::DEFAULT_P;
6use crate::num::ExactNumNumber;
7use crate::Consts;
8use crate::Error;
9use crate::Exponent;
10use crate::Radix;
11use crate::RoundingMode;
12use crate::Sign;
13use crate::Word;
14use crate::WORD_BIT_SIZE;
15use core::num::FpCategory;
16use lazy_static::lazy_static;
17
18#[cfg(feature = "std")]
19use core::fmt::Write;
20
21#[cfg(not(feature = "std"))]
22use alloc::{string::String, vec::Vec};
23
24pub const NAN: ExactNum = ExactNum {
26 inner: Flavor::NaN(None),
27};
28
29pub const INF_POS: ExactNum = ExactNum {
31 inner: Flavor::Inf(Sign::Pos),
32};
33
34pub const INF_NEG: ExactNum = ExactNum {
36 inner: Flavor::Inf(Sign::Neg),
37};
38
39lazy_static! {
40
41 pub static ref ONE: ExactNum = ExactNum { inner: Flavor::Value(ExactNumNumber::from_word(1, DEFAULT_P).expect("Constant ONE initialized")) };
43
44 pub static ref TWO: ExactNum = ExactNum { inner: Flavor::Value(ExactNumNumber::from_word(2, DEFAULT_P).expect("Constant TWO initialized")) };
46}
47
48#[derive(Debug)]
50pub struct ExactNum {
51 inner: Flavor,
52}
53
54#[derive(Debug)]
55enum Flavor {
56 Value(ExactNumNumber),
57 NaN(Option<Error>),
58 Inf(Sign), }
60
61impl ExactNum {
62 pub fn new(p: usize) -> Self {
65 Self::result_to_ext(ExactNumNumber::new(p), false, true)
66 }
67
68 pub fn nan(err: Option<Error>) -> Self {
70 ExactNum {
71 inner: Flavor::NaN(err),
72 }
73 }
74
75 pub fn is_inf_pos(&self) -> bool {
77 matches!(self.inner, Flavor::Inf(Sign::Pos))
78 }
79
80 pub fn is_inf_neg(&self) -> bool {
82 matches!(self.inner, Flavor::Inf(Sign::Neg))
83 }
84
85 pub fn is_inf(&self) -> bool {
87 matches!(self.inner, Flavor::Inf(_))
88 }
89
90 pub fn is_nan(&self) -> bool {
92 matches!(self.inner, Flavor::NaN(_))
93 }
94
95 pub fn is_int(&self) -> bool {
97 match &self.inner {
98 Flavor::Value(v) => v.is_int(),
99 Flavor::NaN(_) => false,
100 Flavor::Inf(_) => false,
101 }
102 }
103
104 pub fn err(&self) -> Option<Error> {
106 match &self.inner {
107 Flavor::NaN(Some(e)) => Some(*e),
108 _ => None,
109 }
110 }
111
112 pub fn add(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
116 self.add_op(d2, p, rm, false)
117 }
118
119 pub fn add_full_prec(&self, d2: &Self) -> Self {
123 self.add_op(d2, 0, RoundingMode::None, true)
124 }
125
126 fn add_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
127 match &self.inner {
128 Flavor::Value(v1) => match &d2.inner {
129 Flavor::Value(v2) => Self::result_to_ext(
130 if full_prec { v1.add_full_prec(v2) } else { v1.add(v2, p, rm) },
131 v1.is_zero(),
132 v1.sign() == v2.sign(),
133 ),
134 Flavor::Inf(s2) => ExactNum {
135 inner: Flavor::Inf(*s2),
136 },
137 Flavor::NaN(err) => Self::nan(*err),
138 },
139 Flavor::Inf(s1) => match &d2.inner {
140 Flavor::Value(_) => ExactNum {
141 inner: Flavor::Inf(*s1),
142 },
143 Flavor::Inf(s2) => {
144 if *s1 != *s2 {
145 NAN
146 } else {
147 ExactNum {
148 inner: Flavor::Inf(*s2),
149 }
150 }
151 }
152 Flavor::NaN(err) => Self::nan(*err),
153 },
154 Flavor::NaN(err) => Self::nan(*err),
155 }
156 }
157
158 pub fn sub(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
162 self.sub_op(d2, p, rm, false)
163 }
164
165 pub fn sub_full_prec(&self, d2: &Self) -> Self {
169 self.sub_op(d2, 0, RoundingMode::None, true)
170 }
171
172 fn sub_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
173 match &self.inner {
174 Flavor::Value(v1) => match &d2.inner {
175 Flavor::Value(v2) => Self::result_to_ext(
176 if full_prec { v1.sub_full_prec(v2) } else { v1.sub(v2, p, rm) },
177 v1.is_zero(),
178 v1.sign() == v2.sign(),
179 ),
180 Flavor::Inf(s2) => {
181 if s2.is_positive() {
182 INF_NEG
183 } else {
184 INF_POS
185 }
186 }
187 Flavor::NaN(err) => Self::nan(*err),
188 },
189 Flavor::Inf(s1) => match &d2.inner {
190 Flavor::Value(_) => ExactNum {
191 inner: Flavor::Inf(*s1),
192 },
193 Flavor::Inf(s2) => {
194 if *s1 == *s2 {
195 NAN
196 } else {
197 ExactNum {
198 inner: Flavor::Inf(*s1),
199 }
200 }
201 }
202 Flavor::NaN(err) => Self::nan(*err),
203 },
204 Flavor::NaN(err) => Self::nan(*err),
205 }
206 }
207
208 pub fn mul(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
212 self.mul_op(d2, p, rm, false)
213 }
214
215 pub fn mul_full_prec(&self, d2: &Self) -> Self {
219 self.mul_op(d2, 0, RoundingMode::None, true)
220 }
221
222 pub fn fma(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
226 if self.is_nan() {
227 return self.clone();
228 }
229 if b.is_nan() {
230 return b.clone();
231 }
232 if c.is_nan() {
233 return c.clone();
234 }
235 match (&self.inner, &b.inner, &c.inner) {
236 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv)) => {
237 Self::result_to_ext(a.fma(bv, cv, p, rm), false, true)
238 }
239 _ => {
240 let prod = self.mul(b, p, RoundingMode::None);
241 prod.add(c, p, rm)
242 }
243 }
244 }
245
246 pub fn two_sum(&self, b: &Self, p: usize, rm: RoundingMode) -> (Self, Self) {
254 if self.is_nan() {
255 return (self.clone(), Self::nan(self.err()));
256 }
257 if b.is_nan() {
258 return (b.clone(), Self::nan(b.err()));
259 }
260 if self.is_inf() || b.is_inf() {
261 return (self.add(b, p, rm), Self::new(p));
262 }
263 let exact = self.add_full_prec(b);
264 let mut hi = exact.clone();
265 if let Err(err) = hi.set_precision(p, rm) {
266 return (Self::nan(Some(err)), Self::nan(Some(err)));
267 }
268 let lo = exact.sub_full_prec(&hi);
269 (hi, Self::normalize_eft_lo(lo, p))
270 }
271
272 fn normalize_eft_lo(lo: Self, p: usize) -> Self {
273 if lo.is_nan() {
274 return lo;
275 }
276 if lo.is_zero() {
277 let mut z = Self::new(p);
278 z.set_inexact(lo.inexact());
279 return z;
280 }
281 lo
282 }
283
284 pub fn two_product(&self, b: &Self, p: usize, rm: RoundingMode) -> (Self, Self) {
287 if self.is_nan() {
288 return (self.clone(), Self::nan(self.err()));
289 }
290 if b.is_nan() {
291 return (b.clone(), Self::nan(b.err()));
292 }
293 if self.is_inf() || b.is_inf() {
294 return (self.mul(b, p, rm), Self::new(p));
295 }
296 let exact = self.mul_full_prec(b);
297 let mut hi = exact.clone();
298 if let Err(err) = hi.set_precision(p, rm) {
299 return (Self::nan(Some(err)), Self::nan(Some(err)));
300 }
301 let lo = exact.sub_full_prec(&hi);
302 (hi, Self::normalize_eft_lo(lo, p))
303 }
304
305 pub fn fused_sum(xs: &[Self], p: usize, rm: RoundingMode) -> Self {
307 if xs.is_empty() {
308 return Self::new(p);
309 }
310 let extra = log2_ceil(xs.len().max(1)).saturating_add(2);
311 let p_wrk = match p
312 .checked_add(WORD_BIT_SIZE)
313 .and_then(|v| v.checked_add(extra))
314 {
315 Some(v) => v,
316 None => return Self::nan(Some(Error::InvalidArgument)),
317 };
318 let mut acc = Self::new(p_wrk);
319 for x in xs {
320 acc = acc.add(x, p_wrk, RoundingMode::None);
321 }
322 if let Err(err) = acc.set_precision(p, rm) {
323 return Self::nan(Some(err));
324 }
325 acc
326 }
327
328 pub fn fused_dot(xs: &[Self], ys: &[Self], p: usize, rm: RoundingMode) -> Self {
331 if xs.len() != ys.len() {
332 return Self::nan(Some(Error::InvalidArgument));
333 }
334 if xs.is_empty() {
335 return Self::new(p);
336 }
337 let extra = log2_ceil(xs.len().max(1)).saturating_add(2);
338 let p_wrk = match p
339 .checked_add(WORD_BIT_SIZE)
340 .and_then(|v| v.checked_add(extra))
341 {
342 Some(v) => v,
343 None => return Self::nan(Some(Error::InvalidArgument)),
344 };
345 let mut acc = Self::new(p_wrk);
346 for (x, y) in xs.iter().zip(ys.iter()) {
347 let prod = x.mul(y, p_wrk, RoundingMode::None);
348 acc = acc.add(&prod, p_wrk, RoundingMode::None);
349 }
350 if let Err(err) = acc.set_precision(p, rm) {
351 return Self::nan(Some(err));
352 }
353 acc
354 }
355
356 pub fn polyval(coeffs: &[Self], x: &Self, p: usize, rm: RoundingMode) -> Self {
360 if coeffs.is_empty() {
361 return Self::new(p);
362 }
363 let extra = log2_ceil(coeffs.len().max(1)).saturating_add(2);
364 let p_wrk = match p
365 .checked_add(WORD_BIT_SIZE)
366 .and_then(|v| v.checked_add(extra))
367 {
368 Some(v) => v,
369 None => return Self::nan(Some(Error::InvalidArgument)),
370 };
371 let mut acc = coeffs[coeffs.len() - 1].clone();
372 if let Err(err) = acc.set_precision(p_wrk, RoundingMode::None) {
373 return Self::nan(Some(err));
374 }
375 for a in coeffs.iter().rev().skip(1) {
376 acc = acc.fma(x, a, p_wrk, RoundingMode::None);
377 }
378 if let Err(err) = acc.set_precision(p, rm) {
379 return Self::nan(Some(err));
380 }
381 acc
382 }
383
384 pub fn mul_add(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
386 if self.is_nan() {
387 return self.clone();
388 }
389 if b.is_nan() {
390 return b.clone();
391 }
392 if c.is_nan() {
393 return c.clone();
394 }
395 match (&self.inner, &b.inner, &c.inner) {
396 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv)) => {
397 Self::result_to_ext(a.mul_add(bv, cv, p, rm), false, true)
398 }
399 _ => self.fma(b, c, p, rm),
400 }
401 }
402
403 fn mul_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
404 match &self.inner {
405 Flavor::Value(v1) => {
406 match &d2.inner {
407 Flavor::Value(v2) => Self::result_to_ext(
408 if full_prec { v1.mul_full_prec(v2) } else { v1.mul(v2, p, rm) },
409 v1.is_zero(),
410 v1.sign() == v2.sign(),
411 ),
412 Flavor::Inf(s2) => {
413 if v1.is_zero() {
414 NAN
416 } else {
417 let s = if v1.sign() == *s2 { Sign::Pos } else { Sign::Neg };
418 ExactNum {
419 inner: Flavor::Inf(s),
420 }
421 }
422 }
423 Flavor::NaN(err) => Self::nan(*err),
424 }
425 }
426 Flavor::Inf(s1) => {
427 match &d2.inner {
428 Flavor::Value(v2) => {
429 if v2.is_zero() {
430 NAN
432 } else {
433 let s = if v2.sign() == *s1 { Sign::Pos } else { Sign::Neg };
434 ExactNum {
435 inner: Flavor::Inf(s),
436 }
437 }
438 }
439 Flavor::Inf(s2) => {
440 let s = if s1 == s2 { Sign::Pos } else { Sign::Neg };
441 ExactNum {
442 inner: Flavor::Inf(s),
443 }
444 }
445 Flavor::NaN(err) => Self::nan(*err),
446 }
447 }
448 Flavor::NaN(err) => Self::nan(*err),
449 }
450 }
451
452 pub fn div(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
456 match &self.inner {
457 Flavor::Value(v1) => match &d2.inner {
458 Flavor::Value(v2) => {
459 Self::result_to_ext(v1.div(v2, p, rm), v1.is_zero(), v1.sign() == v2.sign())
460 }
461 Flavor::Inf(_) => Self::new(v1.mantissa_max_bit_len()),
462 Flavor::NaN(err) => Self::nan(*err),
463 },
464 Flavor::Inf(s1) => match &d2.inner {
465 Flavor::Value(v) => {
466 if *s1 == v.sign() {
467 INF_POS
468 } else {
469 INF_NEG
470 }
471 }
472 Flavor::Inf(_) => NAN,
473 Flavor::NaN(err) => Self::nan(*err),
474 },
475 Flavor::NaN(err) => Self::nan(*err),
476 }
477 }
478
479 pub fn rem(&self, d2: &Self) -> Self {
481 match &self.inner {
482 Flavor::Value(v1) => match &d2.inner {
483 Flavor::Value(v2) => {
484 Self::result_to_ext(v1.rem(v2), v1.is_zero(), v1.sign() == v2.sign())
485 }
486 Flavor::Inf(_) => self.clone(),
487 Flavor::NaN(err) => Self::nan(*err),
488 },
489 Flavor::Inf(_) => NAN,
490 Flavor::NaN(err) => Self::nan(*err),
491 }
492 }
493
494 #[allow(clippy::should_implement_trait)]
497 pub fn cmp(&self, d2: &ExactNum) -> Option<SignedWord> {
498 match &self.inner {
499 Flavor::Value(v1) => match &d2.inner {
500 Flavor::Value(v2) => Some(v1.cmp(v2)),
501 Flavor::Inf(s2) => {
502 if *s2 == Sign::Pos {
503 Some(-1)
504 } else {
505 Some(1)
506 }
507 }
508 Flavor::NaN(_) => None,
509 },
510 Flavor::Inf(s1) => match &d2.inner {
511 Flavor::Value(_) => Some(*s1 as SignedWord),
512 Flavor::Inf(s2) => Some(*s1 as SignedWord - *s2 as SignedWord),
513 Flavor::NaN(_) => None,
514 },
515 Flavor::NaN(_) => None,
516 }
517 }
518
519 pub fn abs_cmp(&self, d2: &Self) -> Option<SignedWord> {
522 match &self.inner {
523 Flavor::Value(v1) => match &d2.inner {
524 Flavor::Value(v2) => Some(v1.cmp(v2)),
525 Flavor::Inf(_) => Some(-1),
526 Flavor::NaN(_) => None,
527 },
528 Flavor::Inf(_) => match &d2.inner {
529 Flavor::Value(_) => Some(1),
530 Flavor::Inf(_) => Some(0),
531 Flavor::NaN(_) => None,
532 },
533 Flavor::NaN(_) => None,
534 }
535 }
536
537 pub fn inv_sign(&mut self) {
539 match &mut self.inner {
540 Flavor::Value(v1) => v1.inv_sign(),
541 Flavor::Inf(s) => self.inner = Flavor::Inf(s.invert()),
542 Flavor::NaN(_) => {}
543 }
544 }
545
546 pub fn pow(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
551 match &self.inner {
552 Flavor::Value(v1) => {
553 match &n.inner {
554 Flavor::Value(v2) => Self::result_to_ext(
555 v1.pow(v2, p, rm, cc),
556 v1.is_zero(),
557 v1.sign() == v2.sign(),
558 ),
559 Flavor::Inf(s2) => {
560 let val = v1.cmp(&crate::common::consts::ONE);
562 if val > 0 {
563 ExactNum {
564 inner: Flavor::Inf(*s2),
565 }
566 } else if val < 0 {
567 Self::new(p)
568 } else {
569 Self::from_u8(1, p)
570 }
571 }
572 Flavor::NaN(err) => Self::nan(*err),
573 }
574 }
575 Flavor::Inf(s1) => {
576 match &n.inner {
577 Flavor::Value(v2) => {
578 if v2.is_zero() {
580 Self::from_u8(1, p)
581 } else if v2.is_positive() {
582 if s1.is_negative() && v2.is_odd_int() {
583 INF_NEG
585 } else {
586 INF_POS
587 }
588 } else {
589 Self::new(p)
590 }
591 }
592 Flavor::Inf(s2) => {
593 if s2.is_positive() {
595 INF_POS
596 } else {
597 Self::new(p)
598 }
599 }
600 Flavor::NaN(err) => Self::nan(*err),
601 }
602 }
603 Flavor::NaN(err) => Self::nan(*err),
604 }
605 }
606
607 pub fn powi(&self, n: usize, p: usize, rm: RoundingMode) -> Self {
611 match &self.inner {
612 Flavor::Value(v1) => Self::result_to_ext(v1.powi(n, p, rm), false, true),
613 Flavor::Inf(s1) => {
614 if n == 0 {
616 Self::from_u8(1, p)
617 } else if s1.is_negative() && (n & 1 == 1) {
618 INF_NEG
619 } else {
620 INF_POS
621 }
622 }
623 Flavor::NaN(err) => Self::nan(*err),
624 }
625 }
626
627 pub fn powsi(&self, n: isize, p: usize, rm: RoundingMode) -> Self {
632 match &self.inner {
633 Flavor::Value(v1) => Self::result_to_ext(v1.powsi(n, p, rm), false, true),
634 Flavor::Inf(s1) => {
635 if n == 0 {
636 Self::from_u8(1, p)
637 } else if n < 0 {
638 Self::new(p)
639 } else if s1.is_negative() && (n & 1 == 1) {
640 INF_NEG
641 } else {
642 INF_POS
643 }
644 }
645 Flavor::NaN(err) => Self::nan(*err),
646 }
647 }
648
649 pub fn log(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
654 match &self.inner {
655 Flavor::Value(v1) => {
656 match &n.inner {
657 Flavor::Value(v2) => {
658 if v2.is_zero() {
659 return INF_NEG;
660 }
661 Self::result_to_ext(v1.log(v2, p, rm, cc), false, true)
662 }
663 Flavor::Inf(s2) => {
664 if s2.is_positive() {
666 Self::new(p)
667 } else {
668 NAN
669 }
670 }
671 Flavor::NaN(err) => Self::nan(*err),
672 }
673 }
674 Flavor::Inf(s1) => {
675 if *s1 == Sign::Neg {
676 NAN
678 } else {
679 match &n.inner {
680 Flavor::Value(v2) => {
681 if v2.exponent() <= 0 {
683 INF_NEG
684 } else {
685 INF_POS
686 }
687 }
688 Flavor::Inf(_) => NAN, Flavor::NaN(err) => Self::nan(*err),
690 }
691 }
692 }
693 Flavor::NaN(err) => Self::nan(*err),
694 }
695 }
696
697 pub fn is_positive(&self) -> bool {
700 match &self.inner {
701 Flavor::Value(v) => v.is_positive(),
702 Flavor::Inf(s) => *s == Sign::Pos,
703 Flavor::NaN(_) => false,
704 }
705 }
706
707 pub fn is_negative(&self) -> bool {
710 match &self.inner {
711 Flavor::Value(v) => v.is_negative(),
712 Flavor::Inf(s) => *s == Sign::Neg,
713 Flavor::NaN(_) => false,
714 }
715 }
716
717 pub fn is_subnormal(&self) -> bool {
719 if let Flavor::Value(v) = &self.inner {
720 return v.is_subnormal();
721 }
722 false
723 }
724
725 pub fn is_zero(&self) -> bool {
727 match &self.inner {
728 Flavor::Value(v) => v.is_zero(),
729 Flavor::Inf(_) => false,
730 Flavor::NaN(_) => false,
731 }
732 }
733
734 pub fn clamp(&self, min: &Self, max: &Self) -> Self {
738 if self.is_nan() || min.is_nan() || max.is_nan() || max.cmp(min).unwrap() < 0 {
739 NAN
741 } else if self.cmp(min).unwrap() < 0 {
742 min.clone()
744 } else if self.cmp(max).unwrap() > 0 {
745 max.clone()
747 } else {
748 self.clone()
749 }
750 }
751
752 pub fn max(&self, d1: &Self) -> Self {
755 if self.is_nan() || d1.is_nan() {
756 NAN
757 } else if self.cmp(d1).unwrap() < 0 {
758 d1.clone()
760 } else {
761 self.clone()
762 }
763 }
764
765 pub fn min(&self, d1: &Self) -> Self {
768 if self.is_nan() || d1.is_nan() {
769 NAN
770 } else if self.cmp(d1).unwrap() > 0 {
771 d1.clone()
773 } else {
774 self.clone()
775 }
776 }
777
778 pub fn signum(&self) -> Self {
781 if self.is_nan() {
782 NAN
783 } else if self.is_negative() {
784 let mut ret = Self::from_u8(1, DEFAULT_P);
785 ret.inv_sign();
786 ret
787 } else {
788 Self::from_u8(1, DEFAULT_P)
789 }
790 }
791
792 pub fn parse(s: &str, rdx: Radix, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
815 match crate::parser::parse(s, rdx) {
816 Ok(ps) => {
817 if ps.is_inf() {
818 if ps.sign() == Sign::Pos {
819 INF_POS
820 } else {
821 INF_NEG
822 }
823 } else if ps.is_nan() {
824 NAN
825 } else {
826 let (m, s, e) = ps.raw_parts();
827 Self::result_to_ext(
828 ExactNumNumber::convert_from_radix(s, m, e, rdx, p, rm, cc),
829 false,
830 true,
831 )
832 }
833 }
834 Err(e) => Self::nan(Some(e)),
835 }
836 }
837
838 #[cfg(feature = "std")]
839 pub(crate) fn write_str<T: Write>(
840 &self,
841 w: &mut T,
842 rdx: Radix,
843 rm: RoundingMode,
844 cc: &mut Consts,
845 ) -> Result<(), core::fmt::Error> {
846 match &self.inner {
847 Flavor::Value(v) => match v.format(rdx, rm, cc) {
848 Ok(s) => w.write_str(&s),
849 Err(e) => match e {
850 Error::ExponentOverflow(s) => {
851 if s.is_positive() {
852 w.write_str("Inf")
853 } else {
854 w.write_str("-Inf")
855 }
856 }
857 _ => w.write_str("Err"),
858 },
859 },
860 Flavor::Inf(sign) => {
861 let s = if sign.is_negative() { "-Inf" } else { "Inf" };
862 w.write_str(s)
863 }
864 crate::ext::Flavor::NaN(_) => w.write_str("NaN"),
865 }
866 }
867
868 pub fn format(&self, rdx: Radix, rm: RoundingMode, cc: &mut Consts) -> Result<String, Error> {
878 let s = match &self.inner {
879 Flavor::Value(v) => match v.format(rdx, rm, cc) {
880 Ok(s) => return Ok(s),
881 Err(e) => match e {
882 Error::ExponentOverflow(s) => {
883 if s.is_positive() {
884 "Inf"
885 } else {
886 "-Inf"
887 }
888 }
889 _ => "Err",
890 },
891 },
892 Flavor::Inf(sign) => {
893 if sign.is_negative() {
894 "-Inf"
895 } else {
896 "Inf"
897 }
898 }
899 crate::ext::Flavor::NaN(_) => "NaN",
900 };
901
902 let mut ret = String::new();
903 ret.try_reserve_exact(s.len())?;
904 ret.push_str(s);
905
906 Ok(ret)
907 }
908
909 pub fn with_radix(self, radix: Radix) -> crate::radix_float::RadixFloat {
911 crate::radix_float::RadixFloat::with_radix(self, radix)
912 }
913
914 #[cfg(feature = "random")]
921 pub fn random_normal(p: usize, exp_from: Exponent, exp_to: Exponent) -> Self {
922 Self::result_to_ext(
923 ExactNumNumber::random_normal(p, exp_from, exp_to),
924 false,
925 true,
926 )
927 }
928
929 pub fn classify(&self) -> FpCategory {
931 match &self.inner {
932 Flavor::Value(v) => {
933 if v.is_subnormal() {
934 FpCategory::Subnormal
935 } else if v.is_zero() {
936 FpCategory::Zero
937 } else {
938 FpCategory::Normal
939 }
940 }
941 Flavor::Inf(_) => FpCategory::Infinite,
942 Flavor::NaN(_) => FpCategory::Nan,
943 }
944 }
945
946 pub fn atan(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
951 match &self.inner {
952 Flavor::Value(v) => Self::result_to_ext(v.atan(p, rm, cc), v.is_zero(), true),
953 Flavor::Inf(s) => Self::result_to_ext(Self::half_pi(*s, p, rm, cc), false, true),
954 Flavor::NaN(err) => Self::nan(*err),
955 }
956 }
957
958 pub fn atan2(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
963 if self.is_nan() {
964 return self.clone();
965 }
966 if x.is_nan() {
967 return x.clone();
968 }
969
970 match (&self.inner, &x.inner) {
971 (Flavor::Inf(sy), Flavor::Inf(sx)) => {
972 let mut q = cc.pi(p, rm);
973 q = q.div(&ExactNum::from_word(4, p), p, rm);
974 if sx.is_negative() {
975 let three = ExactNum::from_word(3, p);
976 q = three.mul(&q, p, rm);
977 }
978 if sy.is_negative() {
979 q.neg()
980 } else {
981 q
982 }
983 }
984 (Flavor::Inf(sy), Flavor::Value(_)) => {
985 Self::result_to_ext(Self::half_pi(*sy, p, rm, cc), false, true)
986 }
987 (Flavor::Value(y), Flavor::Inf(sx)) => {
988 if sx.is_positive() {
989 Self::result_to_ext(ExactNumNumber::new2(p, y.sign(), y.inexact()), false, true)
990 } else {
991 let mut pi = cc.pi(p, rm);
992 pi.set_sign(y.sign());
993 pi
994 }
995 }
996 (Flavor::Value(y), Flavor::Value(xv)) => {
997 Self::result_to_ext(y.atan2(xv, p, rm, cc), false, false)
998 }
999 _ => NAN,
1000 }
1001 }
1002
1003 pub fn hypot(&self, other: &Self, p: usize, rm: RoundingMode) -> Self {
1008 if self.is_inf() || other.is_inf() {
1009 return INF_POS;
1010 }
1011 if self.is_nan() {
1012 return self.clone();
1013 }
1014 if other.is_nan() {
1015 return other.clone();
1016 }
1017 match (&self.inner, &other.inner) {
1018 (Flavor::Value(a), Flavor::Value(b)) => {
1019 Self::result_to_ext(a.hypot(b, p, rm), false, true)
1020 }
1021 _ => NAN,
1022 }
1023 }
1024
1025 pub fn log1p(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1030 match &self.inner {
1031 Flavor::Value(v) => Self::result_to_ext(v.log1p(p, rm, cc), false, false),
1032 Flavor::Inf(s) => {
1033 if s.is_positive() {
1034 INF_POS
1035 } else {
1036 NAN
1037 }
1038 }
1039 Flavor::NaN(err) => Self::nan(*err),
1040 }
1041 }
1042
1043 pub fn expm1(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1047 match &self.inner {
1048 Flavor::Value(v) => Self::result_to_ext(v.expm1(p, rm, cc), false, true),
1049 Flavor::Inf(s) => {
1050 if s.is_positive() {
1051 INF_POS
1052 } else {
1053 ExactNum::from_i8(-1, p)
1054 }
1055 }
1056 Flavor::NaN(err) => Self::nan(*err),
1057 }
1058 }
1059
1060 pub fn tanh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1065 match &self.inner {
1066 Flavor::Value(v) => Self::result_to_ext(v.tanh(p, rm, cc), v.is_zero(), true),
1067 Flavor::Inf(s) => Self::from_i8(s.to_int(), p),
1068 Flavor::NaN(err) => Self::nan(*err),
1069 }
1070 }
1071
1072 fn half_pi(
1073 s: Sign,
1074 p: usize,
1075 rm: RoundingMode,
1076 cc: &mut Consts,
1077 ) -> Result<ExactNumNumber, Error> {
1078 let mut half_pi = cc.pi_num(p, rm)?;
1079
1080 half_pi.set_exponent(1);
1081 half_pi.set_sign(s);
1082
1083 Ok(half_pi)
1084 }
1085
1086 fn result_to_ext(
1087 res: Result<ExactNumNumber, Error>,
1088 is_dividend_zero: bool,
1089 is_same_sign: bool,
1090 ) -> ExactNum {
1091 match res {
1092 Err(e) => match e {
1093 Error::ExponentOverflow(s) => {
1094 if s.is_positive() {
1095 INF_POS
1096 } else {
1097 INF_NEG
1098 }
1099 }
1100 Error::DivisionByZero => {
1101 if is_dividend_zero {
1102 NAN
1103 } else if is_same_sign {
1104 INF_POS
1105 } else {
1106 INF_NEG
1107 }
1108 }
1109 Error::MemoryAllocation => Self::nan(Some(Error::MemoryAllocation)),
1110 Error::InvalidArgument => Self::nan(Some(Error::InvalidArgument)),
1111 Error::PrecisionRetryExhausted => Self::nan(Some(Error::PrecisionRetryExhausted)),
1112 },
1113 Ok(v) => ExactNum {
1114 inner: Flavor::Value(v),
1115 },
1116 }
1117 }
1118
1119 pub fn exponent(&self) -> Option<Exponent> {
1121 match &self.inner {
1122 Flavor::Value(v) => Some(v.exponent()),
1123 _ => None,
1124 }
1125 }
1126
1127 pub fn precision(&self) -> Option<usize> {
1131 match &self.inner {
1132 Flavor::Value(v) => Some(v.precision()),
1133 _ => None,
1134 }
1135 }
1136
1137 pub fn max_value(p: usize) -> Self {
1142 Self::result_to_ext(ExactNumNumber::max_value(p), false, true)
1143 }
1144
1145 pub fn min_value(p: usize) -> Self {
1148 Self::result_to_ext(ExactNumNumber::min_value(p), false, true)
1149 }
1150
1151 pub fn min_positive(p: usize) -> Self {
1157 Self::result_to_ext(ExactNumNumber::min_positive(p), false, true)
1158 }
1159
1160 pub fn min_positive_normal(p: usize) -> Self {
1166 Self::result_to_ext(ExactNumNumber::min_positive_normal(p), false, true)
1167 }
1168
1169 pub fn from_word(d: Word, p: usize) -> Self {
1172 Self::result_to_ext(ExactNumNumber::from_word(d, p), false, true)
1173 }
1174
1175 pub fn neg(&self) -> Self {
1177 let mut ret = self.clone();
1178 ret.inv_sign();
1179 ret
1180 }
1181
1182 pub fn as_raw_parts(&self) -> Option<(&[Word], usize, Sign, Exponent, bool)> {
1187 if let Flavor::Value(v) = &self.inner {
1188 Some(v.as_raw_parts())
1189 } else {
1190 None
1191 }
1192 }
1193
1194 pub fn from_raw_parts(m: &[Word], n: usize, s: Sign, e: Exponent, inexact: bool) -> Self {
1210 Self::result_to_ext(
1211 crate::mantissa::Mantissa::from_raw_parts(m, n)
1212 .map(|mantissa| ExactNumNumber::from_raw_unchecked(mantissa, s, e, inexact)),
1213 false,
1214 true,
1215 )
1216 }
1217
1218 pub fn from_words(m: &[Word], s: Sign, e: Exponent) -> Self {
1226 Self::result_to_ext(ExactNumNumber::from_words(m, s, e), false, true)
1227 }
1228
1229 pub fn sign(&self) -> Option<Sign> {
1231 match &self.inner {
1232 Flavor::Value(v) => Some(v.sign()),
1233 Flavor::Inf(s) => Some(*s),
1234 Flavor::NaN(_) => None,
1235 }
1236 }
1237
1238 pub fn set_exponent(&mut self, e: Exponent) {
1263 if let Flavor::Value(v) = &mut self.inner {
1264 v.set_exponent(e)
1265 }
1266 }
1267
1268 pub fn mantissa_max_bit_len(&self) -> Option<usize> {
1270 if let Flavor::Value(v) = &self.inner {
1271 Some(v.mantissa_max_bit_len())
1272 } else {
1273 None
1274 }
1275 }
1276
1277 pub fn is_inline(&self) -> bool {
1280 match &self.inner {
1281 Flavor::Value(v) => v.is_inline(),
1282 Flavor::Inf(_) | Flavor::NaN(_) => false,
1283 }
1284 }
1285
1286 pub fn set_precision(&mut self, p: usize, rm: RoundingMode) -> Result<(), Error> {
1294 if let Flavor::Value(v) = &mut self.inner {
1295 v.set_precision(p, rm)
1296 } else {
1297 Ok(())
1298 }
1299 }
1300
1301 pub fn reciprocal(&self, p: usize, rm: RoundingMode) -> Self {
1306 match &self.inner {
1307 Flavor::Value(v) => Self::result_to_ext(v.reciprocal(p, rm), false, v.is_positive()),
1308 Flavor::Inf(s) => {
1309 let mut ret = Self::new(p);
1310 ret.set_sign(*s);
1311 ret
1312 }
1313 Flavor::NaN(err) => Self::nan(*err),
1314 }
1315 }
1316
1317 pub fn set_sign(&mut self, s: Sign) {
1319 match &mut self.inner {
1320 Flavor::Value(v) => v.set_sign(s),
1321 Flavor::Inf(_) => self.inner = Flavor::Inf(s),
1322 Flavor::NaN(_) => {}
1323 };
1324 }
1325
1326 pub fn mantissa_digits(&self) -> Option<&[Word]> {
1328 if let Flavor::Value(v) = &self.inner {
1329 Some(v.mantissa().digits())
1330 } else {
1331 None
1332 }
1333 }
1334
1335 pub fn convert_from_radix(
1371 sign: Sign,
1372 digits: &[u8],
1373 e: Exponent,
1374 rdx: Radix,
1375 p: usize,
1376 rm: RoundingMode,
1377 cc: &mut Consts,
1378 ) -> Self {
1379 Self::result_to_ext(
1380 ExactNumNumber::convert_from_radix(sign, digits, e, rdx, p, rm, cc),
1381 false,
1382 true,
1383 )
1384 }
1385
1386 pub fn convert_to_radix(
1409 &self,
1410 rdx: Radix,
1411 rm: RoundingMode,
1412 cc: &mut Consts,
1413 ) -> Result<(Sign, Vec<u8>, Exponent), Error> {
1414 match &self.inner {
1415 Flavor::Value(v) => v.convert_to_radix(rdx, rm, cc),
1416 Flavor::NaN(_) => Err(Error::InvalidArgument),
1417 Flavor::Inf(_) => Err(Error::InvalidArgument),
1418 }
1419 }
1420
1421 pub fn inexact(&self) -> bool {
1423 if let Flavor::Value(v) = &self.inner {
1424 v.inexact()
1425 } else {
1426 false
1427 }
1428 }
1429
1430 pub fn set_inexact(&mut self, inexact: bool) {
1433 if let Flavor::Value(v) = &mut self.inner {
1434 v.set_inexact(inexact);
1435 }
1436 }
1437
1438 pub fn try_set_precision(&mut self, p: usize, rm: RoundingMode, s: usize) -> bool {
1444 if let Flavor::Value(v) = &mut self.inner {
1445 v.try_set_precision(p, rm, s).unwrap_or_else(|e| {
1446 self.inner = Flavor::NaN(Some(e));
1447 true
1448 })
1449 } else {
1450 true
1451 }
1452 }
1453
1454 pub fn frexp(&self) -> (Self, Exponent) {
1456 match &self.inner {
1457 Flavor::Value(v) => match v.frexp() {
1458 Ok((m, e)) => (m.into(), e),
1459 Err(err) => (Self::nan(Some(err)), 0),
1460 },
1461 Flavor::Inf(_) | Flavor::NaN(_) => (self.clone(), 0),
1462 }
1463 }
1464
1465 pub fn ldexp(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
1467 match &self.inner {
1468 Flavor::Value(v) => Self::result_to_ext(v.ldexp(n, p, rm), v.is_zero(), true),
1469 Flavor::Inf(_) | Flavor::NaN(_) => self.clone(),
1470 }
1471 }
1472
1473 pub fn scalb(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
1475 self.ldexp(n, p, rm)
1476 }
1477
1478 pub fn logb(&self, p: usize, rm: RoundingMode) -> Self {
1480 match &self.inner {
1481 Flavor::Value(v) => Self::result_to_ext(v.logb(p, rm), v.is_zero(), true),
1482 Flavor::Inf(_) => INF_POS,
1483 Flavor::NaN(err) => Self::nan(*err),
1484 }
1485 }
1486
1487 pub fn ilogb(&self) -> Option<Exponent> {
1489 match &self.inner {
1490 Flavor::Value(v) => v.ilogb().ok(),
1491 _ => None,
1492 }
1493 }
1494}
1495
1496impl Clone for ExactNum {
1497 fn clone(&self) -> Self {
1498 match &self.inner {
1499 Flavor::Value(v) => Self::result_to_ext(v.clone(), false, true),
1500 Flavor::Inf(s) => {
1501 if s.is_positive() {
1502 INF_POS
1503 } else {
1504 INF_NEG
1505 }
1506 }
1507 Flavor::NaN(err) => Self::nan(*err),
1508 }
1509 }
1510}
1511
1512macro_rules! gen_wrapper_arg {
1513 ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1515 #[doc=$comment]
1516 pub fn $fname(&self$(,$arg: $arg_type)*) -> $ret {
1517 match &self.inner {
1518 Flavor::Value(v) => Self::result_to_ext(v.$fname($($arg,)*), v.is_zero(), true),
1519 Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1520 Flavor::NaN(err) => Self::nan(*err),
1521 }
1522 }
1523 };
1524}
1525
1526macro_rules! gen_wrapper_arg_rm {
1527 ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1529 #[doc=$comment]
1530 pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode) -> $ret {
1531 match &self.inner {
1532 Flavor::Value(v) => {
1533 Self::result_to_ext(v.$fname($($arg,)* rm), v.is_zero(), true)
1534 },
1535 Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1536 Flavor::NaN(err) => Self::nan(*err),
1537 }
1538 }
1539 };
1540}
1541
1542macro_rules! gen_wrapper_arg_rm_cc {
1543 ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1545 #[doc=$comment]
1546 pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1547 match &self.inner {
1548 Flavor::Value(v) => {
1549 Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1550 },
1551 Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1552 Flavor::NaN(err) => Self::nan(*err),
1553 }
1554 }
1555 };
1556}
1557
1558macro_rules! gen_wrapper_log {
1559 ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1560 #[doc=$comment]
1561 pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1562 match &self.inner {
1563 Flavor::Value(v) => {
1564 if v.is_zero() {
1565 return INF_NEG;
1566 }
1567 Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1568 },
1569 Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1570 Flavor::NaN(err) => Self::nan(*err),
1571 }
1572 }
1573 };
1574}
1575
1576impl ExactNum {
1577 gen_wrapper_arg!(
1578 "Returns the absolute value of `self`.",
1579 abs,
1580 Self,
1581 { INF_POS },
1582 { INF_POS },
1583 );
1584 pub fn copysign(&self, sign: &Self, p: usize, rm: RoundingMode) -> Self {
1586 if self.is_nan() {
1587 return self.clone();
1588 }
1589 let sign_num = match &sign.inner {
1590 Flavor::Value(v) => v.clone(),
1591 Flavor::Inf(s) => ExactNumNumber::from_i8(s.to_int(), p),
1592 Flavor::NaN(_) => ExactNumNumber::new(p),
1593 };
1594 let sign_num = match sign_num {
1595 Ok(v) => v,
1596 Err(e) => return Self::nan(Some(e)),
1597 };
1598 match &self.inner {
1599 Flavor::Value(v) => Self::result_to_ext(v.copysign(&sign_num, p, rm), false, true),
1600 Flavor::Inf(_) => {
1601 if sign.is_negative() || (sign.is_zero() && sign_num.is_negative()) {
1602 INF_NEG
1603 } else {
1604 INF_POS
1605 }
1606 }
1607 Flavor::NaN(err) => Self::nan(*err),
1608 }
1609 }
1610 pub fn next_after(&self, toward: &Self, p: usize, rm: RoundingMode) -> Self {
1612 if self.is_nan() {
1613 return self.clone();
1614 }
1615 if toward.is_nan() {
1616 return toward.clone();
1617 }
1618 match (&self.inner, &toward.inner) {
1619 (Flavor::Value(v), Flavor::Value(t)) => {
1620 Self::result_to_ext(v.next_after(t, p, rm), false, true)
1621 }
1622 (Flavor::Inf(_), _) | (_, Flavor::Inf(_)) => self.clone(),
1623 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
1624 }
1625 }
1626 gen_wrapper_arg!("Returns the integer part of `self`.", int, Self, { NAN }, {
1627 NAN
1628 },);
1629 gen_wrapper_arg!(
1630 "Returns the fractional part of `self`.",
1631 fract,
1632 Self,
1633 { NAN },
1634 { NAN },
1635 );
1636 gen_wrapper_arg!(
1637 "Returns the smallest integer greater than or equal to `self`.",
1638 ceil,
1639 Self,
1640 { INF_POS },
1641 { INF_NEG },
1642 );
1643 gen_wrapper_arg!(
1644 "Returns the largest integer less than or equal to `self`.",
1645 floor,
1646 Self,
1647 { INF_POS },
1648 { INF_NEG },
1649 );
1650 gen_wrapper_arg_rm!("Returns the rounded number with `n` binary positions in the fractional part of the number using rounding mode `rm`.",
1651 round,
1652 Self,
1653 { INF_POS },
1654 { INF_NEG },
1655 n,
1656 usize
1657 );
1658 gen_wrapper_arg_rm!(
1659 "Computes the square root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1660 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1661 sqrt,
1662 Self,
1663 { INF_POS },
1664 { NAN },
1665 p,
1666 usize
1667 );
1668 gen_wrapper_arg_rm!(
1669 "Computes the cube root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1670 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1671 cbrt,
1672 Self,
1673 { INF_POS },
1674 { INF_NEG },
1675 p,
1676 usize
1677 );
1678 pub fn nth_root(&self, n: usize, p: usize, rm: RoundingMode) -> Self {
1680 if n == 0 {
1681 return Self::nan(Some(Error::InvalidArgument));
1682 }
1683 match &self.inner {
1684 Flavor::Value(v) => Self::result_to_ext(v.nth_root(n, p, rm), v.is_zero(), true),
1685 Flavor::Inf(s) => {
1686 if n % 2 == 0 {
1687 if s.is_negative() {
1688 NAN
1689 } else {
1690 INF_POS
1691 }
1692 } else if s.is_negative() {
1693 INF_NEG
1694 } else {
1695 INF_POS
1696 }
1697 }
1698 Flavor::NaN(err) => Self::nan(*err),
1699 }
1700 }
1701 gen_wrapper_log!(
1702 "Computes the natural logarithm of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1703 This function requires constants cache `cc` for computing the result.
1704 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1705 ln,
1706 Self,
1707 { INF_POS },
1708 { NAN },
1709 p,
1710 usize
1711 );
1712 gen_wrapper_log!(
1713 "Computes the logarithm base 2 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1714 This function requires constants cache `cc` for computing the result.
1715 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1716 log2,
1717 Self,
1718 { INF_POS },
1719 { NAN },
1720 p,
1721 usize
1722 );
1723 gen_wrapper_log!(
1724 "Computes the logarithm base 10 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1725 This function requires constants cache `cc` for computing the result.
1726 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1727 log10,
1728 Self,
1729 { INF_POS },
1730 { NAN },
1731 p,
1732 usize
1733 );
1734 gen_wrapper_arg_rm_cc!(
1735 "Computes `e` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1736 This function requires constants cache `cc` for computing the result.
1737 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1738 exp,
1739 Self,
1740 { INF_POS },
1741 { Self::new(p) },
1742 p,
1743 usize
1744 );
1745 gen_wrapper_arg_rm_cc!(
1746 "Computes `2` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1747 This function requires constants cache `cc` for computing the result.
1748 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1749 exp2,
1750 Self,
1751 { INF_POS },
1752 { Self::new(p) },
1753 p,
1754 usize
1755 );
1756 gen_wrapper_arg_rm_cc!(
1757 "Computes `10` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1758 This function requires constants cache `cc` for computing the result.
1759 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1760 exp10,
1761 Self,
1762 { INF_POS },
1763 { Self::new(p) },
1764 p,
1765 usize
1766 );
1767 gen_wrapper_arg_rm_cc!(
1768 "Reduces `self` modulo `2π` into the interval `(-2π, 2π)` using precision `p` and rounding mode `rm`.
1769 This function requires constants cache `cc` for computing the result.",
1770 rem_pi,
1771 Self,
1772 { NAN },
1773 { NAN },
1774 p,
1775 usize
1776 );
1777
1778 gen_wrapper_arg_rm_cc!(
1779 "Computes the sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1780 This function requires constants cache `cc` for computing the result.
1781 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1782 sin,
1783 Self,
1784 { NAN },
1785 { NAN },
1786 p,
1787 usize
1788 );
1789 gen_wrapper_arg_rm_cc!(
1790 "Computes the cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1791 This function requires constants cache `cc` for computing the result.
1792 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1793 cos,
1794 Self,
1795 { NAN },
1796 { NAN },
1797 p,
1798 usize
1799 );
1800 pub fn sin_cos(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> (Self, Self) {
1802 match &self.inner {
1803 Flavor::Value(v) => match v.sin_cos(p, rm, cc) {
1804 Ok((s, c)) => (
1805 Self::result_to_ext(Ok(s), false, true),
1806 Self::result_to_ext(Ok(c), false, true),
1807 ),
1808 Err(e) => (Self::nan(Some(e)), Self::nan(Some(e))),
1809 },
1810 Flavor::Inf(_) => (NAN, NAN),
1811 Flavor::NaN(err) => (Self::nan(*err), Self::nan(*err)),
1812 }
1813 }
1814 gen_wrapper_arg_rm_cc!(
1815 "Computes the tangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1816 This function requires constants cache `cc` for computing the result.
1817 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1818 tan,
1819 Self,
1820 { NAN },
1821 { NAN },
1822 p,
1823 usize
1824 );
1825 gen_wrapper_arg_rm_cc!(
1826 "Computes the arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1827 This function requires constants cache `cc` for computing the result.
1828 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1829 asin,
1830 Self,
1831 {NAN},
1832 {NAN},
1833 p,
1834 usize
1835 );
1836 gen_wrapper_arg_rm_cc!(
1837 "Computes the arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1838 This function requires constants cache `cc` for computing the result.
1839 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1840 acos,
1841 Self,
1842 { NAN },
1843 { NAN },
1844 p,
1845 usize
1846 );
1847
1848 gen_wrapper_arg_rm_cc!(
1849 "Computes the hyperbolic sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1850 This function requires constants cache cc for computing the result.
1851 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1852 sinh,
1853 Self,
1854 { INF_POS },
1855 { INF_NEG },
1856 p,
1857 usize
1858 );
1859 gen_wrapper_arg_rm_cc!(
1860 "Computes the hyperbolic cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1861 This function requires constants cache cc for computing the result.
1862 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1863 cosh,
1864 Self,
1865 { INF_POS },
1866 { INF_POS },
1867 p,
1868 usize
1869 );
1870 pub fn sinh_cosh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> (Self, Self) {
1872 match &self.inner {
1873 Flavor::Value(v) => match v.sinh_cosh(p, rm, cc) {
1874 Ok((s, c)) => (
1875 Self::result_to_ext(Ok(s), false, true),
1876 Self::result_to_ext(Ok(c), false, true),
1877 ),
1878 Err(Error::ExponentOverflow(s)) => {
1879 if s.is_positive() {
1880 (INF_POS, INF_POS)
1881 } else {
1882 (INF_NEG, INF_POS)
1883 }
1884 }
1885 Err(e) => (Self::nan(Some(e)), Self::nan(Some(e))),
1886 },
1887 Flavor::Inf(s) => {
1888 if s.is_positive() {
1889 (INF_POS, INF_POS)
1890 } else {
1891 (INF_NEG, INF_POS)
1892 }
1893 }
1894 Flavor::NaN(err) => (Self::nan(*err), Self::nan(*err)),
1895 }
1896 }
1897 gen_wrapper_arg_rm_cc!(
1898 "Error function `erf(self)` with precision `p`.
1899
1900# Precision
1901
1902- Algorithm: Taylor series when `|x|.exponent() ≤ 2`; complementary asymptotic otherwise. Saturates to `±1` when `2|e| > p+4`.
1903- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on `|x| ≲ 4`.
1904- Thresholds: exponent cut `≤ 2` (not a named constant).
1905- MPFR oracle: yes, `|x| ≲ 4` under `mpfr-tests`. Complex `erf` on the real axis uses the same oracle; GNU MPC has no `mpc_erf`.",
1906 erf,
1907 Self,
1908 { ExactNum::from_u8(1, p) },
1909 { ExactNum::from_i8(-1, p) },
1910 p,
1911 usize
1912 );
1913 gen_wrapper_arg_rm_cc!(
1914 "Complementary error function `erfc(self) = 1 - erf(self)` with precision `p`.
1915
1916# Precision
1917
1918- Algorithm: `1 - erf` at extra working precision (same series / asymptotic as `erf`).
1919- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on `|x| ≲ 4`.
1920- MPFR oracle: yes, `|x| ≲ 4` under `mpfr-tests`.",
1921 erfc,
1922 Self,
1923 { Self::new(p) },
1924 { ExactNum::from_u8(2, p) },
1925 p,
1926 usize
1927 );
1928 gen_wrapper_arg_rm_cc!(
1929 "Gamma function `Γ(self)` with precision `p`. Poles at non-positive integers yield NaN (or +Inf at 0).
1930
1931# Precision
1932
1933- Algorithm: Stirling series for `ln Γ` then `exp`; reflection across the negative axis. Integer factorials for small positive integers.
1934- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on the oracle domain.
1935- MPFR oracle: yes, under `mpfr-tests`.",
1936 gamma,
1937 Self,
1938 { INF_POS },
1939 { NAN },
1940 p,
1941 usize
1942 );
1943 gen_wrapper_arg_rm_cc!(
1944 "`ln Γ(self)` for positive `self` with precision `p`.
1945
1946# Precision
1947
1948- Algorithm: Stirling series (Bernoulli) at working precision `p + WORD_BIT_SIZE`.
1949- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on the oracle domain.
1950- MPFR oracle: yes, under `mpfr-tests`.",
1951 ln_gamma,
1952 Self,
1953 { INF_POS },
1954 { NAN },
1955 p,
1956 usize
1957 );
1958 gen_wrapper_arg_rm_cc!(
1959 "Digamma `ψ(self)`. Poles at non-positive integers. Reflection for z < 0.
1960
1961# Precision
1962
1963- Algorithm: recurrence to a large argument, then Bernoulli series; reflection for `z < 0`.
1964- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR `digamma` on `z > 0`.
1965- MPFR oracle: yes, `z > 0` under `mpfr-tests`.",
1966 digamma,
1967 Self,
1968 { INF_POS },
1969 { NAN },
1970 p,
1971 usize
1972 );
1973 pub fn gammainc(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1981 match (&self.inner, &x.inner) {
1982 (Flavor::Value(s), Flavor::Value(xv)) => {
1983 Self::result_to_ext(s.gammainc(xv, p, rm, cc), xv.is_zero(), true)
1984 }
1985 (Flavor::Value(s), Flavor::Inf(sx)) => {
1986 if sx.is_positive() {
1987 Self::result_to_ext(s.gamma(p, rm, cc), false, true)
1988 } else {
1989 NAN
1990 }
1991 }
1992 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
1993 (Flavor::Inf(_), _) => NAN,
1994 }
1995 }
1996 pub fn gammainc_upper(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2004 match (&self.inner, &x.inner) {
2005 (Flavor::Value(s), Flavor::Value(xv)) => {
2006 Self::result_to_ext(s.gammainc_upper(xv, p, rm, cc), xv.is_zero(), true)
2007 }
2008 (Flavor::Value(_), Flavor::Inf(sx)) => {
2009 if sx.is_positive() {
2010 Self::new(p)
2011 } else {
2012 NAN
2013 }
2014 }
2015 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2016 (Flavor::Inf(_), _) => NAN,
2017 }
2018 }
2019 gen_wrapper_arg_rm_cc!(
2020 "Exponential integral `Ei(self)` (principal value for `self < 0`). `0` is a pole.
2021
2022# Precision
2023
2024- Algorithm: power series for moderate `|x|`; factorial asymptotic when `|x|` is large (`exponent() > 6` and `|x| ≳ 0.7 p`).
2025- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2026- MPFR oracle: yes, `mpfr_eint` under `mpfr-tests`.",
2027 ei,
2028 Self,
2029 { INF_POS },
2030 { Self::new(p) },
2031 p,
2032 usize
2033 );
2034 pub fn si(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2042 match &self.inner {
2043 Flavor::Value(v) => Self::result_to_ext(v.si(p, rm, cc), v.is_zero(), true),
2044 Flavor::Inf(s) => Self::result_to_ext(Self::half_pi(*s, p, rm, cc), false, true),
2045 Flavor::NaN(err) => Self::nan(*err),
2046 }
2047 }
2048 gen_wrapper_arg_rm_cc!(
2049 "Cosine integral `Ci(self)` for `self > 0`.
2050
2051# Precision
2052
2053- Algorithm: series, or auxiliary `f,g` asymptotic (same `|x|` cut as `Ei`). Near-zero is a pole.
2054- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2055- MPFR oracle: no (identity / series golds; GNU MPFR has no `Si`/`Ci`).",
2056 ci,
2057 Self,
2058 { Self::new(p) },
2059 { NAN },
2060 p,
2061 usize
2062 );
2063 gen_wrapper_arg_rm_cc!(
2064 "Logarithmic integral `li(self) = Ei(ln self)` for `self > 0`, `self ≠ 1`.
2065
2066# Precision
2067
2068- Algorithm: `Ei(ln self)` at extra working precision (inherits `Ei` series / asymptotic).
2069- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2070- MPFR oracle: no (`li(e)=Ei(1)` identity).",
2071 li,
2072 Self,
2073 { INF_POS },
2074 { NAN },
2075 p,
2076 usize
2077 );
2078 pub fn fresnel_s(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2086 self.fresnel_sc_ext(true, p, rm, cc)
2087 }
2088
2089 pub fn fresnel_c(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2097 self.fresnel_sc_ext(false, p, rm, cc)
2098 }
2099
2100 fn fresnel_sc_ext(&self, sine: bool, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2101 match &self.inner {
2102 Flavor::Value(v) => {
2103 let inner = if sine { v.fresnel_s(p, rm, cc) } else { v.fresnel_c(p, rm, cc) };
2104 Self::result_to_ext(inner, v.is_zero(), true)
2105 }
2106 Flavor::Inf(s) => {
2107 let mut half = ExactNum::from_u8(1, p);
2108 half.set_exponent(0);
2109 half.set_sign(*s);
2110 half
2111 }
2112 Flavor::NaN(err) => Self::nan(*err),
2113 }
2114 }
2115
2116 pub fn ai(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2124 match &self.inner {
2125 Flavor::Value(v) => Self::result_to_ext(v.ai(p, rm, cc), v.is_zero(), true),
2126 Flavor::Inf(s) => {
2127 if s.is_positive() {
2128 Self::new(p)
2129 } else {
2130 NAN
2131 }
2132 }
2133 Flavor::NaN(err) => Self::nan(*err),
2134 }
2135 }
2136
2137 pub fn bi(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2145 match &self.inner {
2146 Flavor::Value(v) => Self::result_to_ext(v.bi(p, rm, cc), v.is_zero(), true),
2147 Flavor::Inf(s) => {
2148 if s.is_positive() {
2149 INF_POS
2150 } else {
2151 NAN
2152 }
2153 }
2154 Flavor::NaN(err) => Self::nan(*err),
2155 }
2156 }
2157
2158 pub fn ai_prime(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2166 match &self.inner {
2167 Flavor::Value(v) => Self::result_to_ext(v.ai_prime(p, rm, cc), v.is_zero(), true),
2168 Flavor::Inf(s) => {
2169 if s.is_positive() {
2170 Self::new(p)
2171 } else {
2172 NAN
2173 }
2174 }
2175 Flavor::NaN(err) => Self::nan(*err),
2176 }
2177 }
2178
2179 pub fn bi_prime(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2187 match &self.inner {
2188 Flavor::Value(v) => Self::result_to_ext(v.bi_prime(p, rm, cc), v.is_zero(), true),
2189 Flavor::Inf(s) => {
2190 if s.is_positive() {
2191 INF_POS
2192 } else {
2193 NAN
2194 }
2195 }
2196 Flavor::NaN(err) => Self::nan(*err),
2197 }
2198 }
2199
2200 pub fn bessel_j(&self, n: usize, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2208 match &self.inner {
2209 Flavor::Value(v) => Self::result_to_ext(v.bessel_j(n, p, rm, cc), v.is_zero(), true),
2210 Flavor::Inf(_) => NAN,
2211 Flavor::NaN(err) => Self::nan(*err),
2212 }
2213 }
2214
2215 fn bessel_nu_ext(
2216 &self,
2217 nu: &Self,
2218 p: usize,
2219 rm: RoundingMode,
2220 cc: &mut Consts,
2221 f: fn(
2222 &ExactNumNumber,
2223 &ExactNumNumber,
2224 usize,
2225 RoundingMode,
2226 &mut Consts,
2227 ) -> Result<ExactNumNumber, Error>,
2228 ) -> Self {
2229 match (&self.inner, &nu.inner) {
2230 (Flavor::Value(x), Flavor::Value(n)) => {
2231 Self::result_to_ext(f(x, n, p, rm, cc), x.is_zero(), true)
2232 }
2233 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2234 _ => NAN,
2235 }
2236 }
2237
2238 pub fn bessel_j_nu(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2246 self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_j_nu)
2247 }
2248
2249 pub fn bessel_y(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2257 self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_y)
2258 }
2259
2260 pub fn bessel_i(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2268 self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_i)
2269 }
2270
2271 pub fn bessel_k(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2279 self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_k)
2280 }
2281 gen_wrapper_arg_rm_cc!(
2282 "Complete elliptic `K(self)`. Parameter `m = k²`. `m = 1` is `+∞`; `m > 1` uses the reciprocal-modulus transform.
2283
2284# Precision
2285
2286- Algorithm: Carlson `R_F` duplication; cap `CARLSON_DUPE_MAX = 128`.
2287- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2288- MPFR oracle: no (identity golds; GNU MPFR has no Carlson `K`).",
2289 elliptic_k,
2290 Self,
2291 { NAN },
2292 { NAN },
2293 p,
2294 usize
2295 );
2296 gen_wrapper_arg_rm_cc!(
2297 "Complete elliptic `E(self)` for `self ≤ 1`. `E(1) = 1`.
2298
2299# Precision
2300
2301- Algorithm: Carlson `R_F` / `R_D`; `CARLSON_DUPE_MAX = 128`.
2302- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2303- MPFR oracle: no.",
2304 elliptic_e_complete,
2305 Self,
2306 { NAN },
2307 { NAN },
2308 p,
2309 usize
2310 );
2311 pub fn elliptic_f(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2319 match (&self.inner, &m.inner) {
2320 (Flavor::Value(x), Flavor::Value(mv)) => {
2321 Self::result_to_ext(x.elliptic_f(mv, p, rm, cc), x.is_zero(), true)
2322 }
2323 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2324 _ => NAN,
2325 }
2326 }
2327 pub fn elliptic_e(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2335 match (&self.inner, &m.inner) {
2336 (Flavor::Value(x), Flavor::Value(mv)) => {
2337 Self::result_to_ext(x.elliptic_e(mv, p, rm, cc), x.is_zero(), true)
2338 }
2339 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2340 _ => NAN,
2341 }
2342 }
2343 pub fn elliptic_pi_complete(
2351 &self,
2352 m: &Self,
2353 p: usize,
2354 rm: RoundingMode,
2355 cc: &mut Consts,
2356 ) -> Self {
2357 match (&self.inner, &m.inner) {
2358 (Flavor::Value(n), Flavor::Value(mv)) => {
2359 Self::result_to_ext(n.elliptic_pi_complete(mv, p, rm, cc), false, true)
2360 }
2361 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2362 _ => NAN,
2363 }
2364 }
2365 pub fn elliptic_pi(
2373 &self,
2374 x: &Self,
2375 m: &Self,
2376 p: usize,
2377 rm: RoundingMode,
2378 cc: &mut Consts,
2379 ) -> Self {
2380 match (&self.inner, &x.inner, &m.inner) {
2381 (Flavor::Value(n), Flavor::Value(xv), Flavor::Value(mv)) => {
2382 Self::result_to_ext(n.elliptic_pi(xv, mv, p, rm, cc), xv.is_zero(), true)
2383 }
2384 (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2385 Self::nan(*err)
2386 }
2387 _ => NAN,
2388 }
2389 }
2390 pub fn jacobi_am(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2398 match (&self.inner, &m.inner) {
2399 (Flavor::Value(u), Flavor::Value(mv)) => {
2400 Self::result_to_ext(u.jacobi_am(mv, p, rm, cc), u.is_zero(), true)
2401 }
2402 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2403 _ => NAN,
2404 }
2405 }
2406 pub fn jacobi_sn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2415 match (&self.inner, &m.inner) {
2416 (Flavor::Value(u), Flavor::Value(mv)) => {
2417 Self::result_to_ext(u.jacobi_sn(mv, p, rm, cc), u.is_zero(), true)
2418 }
2419 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2420 _ => NAN,
2421 }
2422 }
2423 pub fn jacobi_cn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2431 match (&self.inner, &m.inner) {
2432 (Flavor::Value(u), Flavor::Value(mv)) => {
2433 Self::result_to_ext(u.jacobi_cn(mv, p, rm, cc), u.is_zero(), true)
2434 }
2435 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2436 _ => NAN,
2437 }
2438 }
2439 pub fn jacobi_dn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2447 match (&self.inner, &m.inner) {
2448 (Flavor::Value(u), Flavor::Value(mv)) => {
2449 Self::result_to_ext(u.jacobi_dn(mv, p, rm, cc), false, true)
2450 }
2451 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2452 _ => NAN,
2453 }
2454 }
2455 pub fn jacobi_cd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2463 match (&self.inner, &m.inner) {
2464 (Flavor::Value(u), Flavor::Value(mv)) => {
2465 Self::result_to_ext(u.jacobi_cd(mv, p, rm, cc), false, true)
2466 }
2467 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2468 _ => NAN,
2469 }
2470 }
2471 pub fn jacobi_ns(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2473 match (&self.inner, &m.inner) {
2474 (Flavor::Value(u), Flavor::Value(mv)) => {
2475 Self::result_to_ext(u.jacobi_ns(mv, p, rm, cc), false, true)
2476 }
2477 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2478 _ => NAN,
2479 }
2480 }
2481 pub fn jacobi_nc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2483 match (&self.inner, &m.inner) {
2484 (Flavor::Value(u), Flavor::Value(mv)) => {
2485 Self::result_to_ext(u.jacobi_nc(mv, p, rm, cc), false, true)
2486 }
2487 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2488 _ => NAN,
2489 }
2490 }
2491 pub fn jacobi_nd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2493 match (&self.inner, &m.inner) {
2494 (Flavor::Value(u), Flavor::Value(mv)) => {
2495 Self::result_to_ext(u.jacobi_nd(mv, p, rm, cc), false, true)
2496 }
2497 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2498 _ => NAN,
2499 }
2500 }
2501 pub fn jacobi_sc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2503 match (&self.inner, &m.inner) {
2504 (Flavor::Value(u), Flavor::Value(mv)) => {
2505 Self::result_to_ext(u.jacobi_sc(mv, p, rm, cc), false, true)
2506 }
2507 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2508 _ => NAN,
2509 }
2510 }
2511 pub fn jacobi_sd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2513 match (&self.inner, &m.inner) {
2514 (Flavor::Value(u), Flavor::Value(mv)) => {
2515 Self::result_to_ext(u.jacobi_sd(mv, p, rm, cc), false, true)
2516 }
2517 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2518 _ => NAN,
2519 }
2520 }
2521 pub fn jacobi_cs(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2523 match (&self.inner, &m.inner) {
2524 (Flavor::Value(u), Flavor::Value(mv)) => {
2525 Self::result_to_ext(u.jacobi_cs(mv, p, rm, cc), false, true)
2526 }
2527 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2528 _ => NAN,
2529 }
2530 }
2531 pub fn jacobi_ds(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2533 match (&self.inner, &m.inner) {
2534 (Flavor::Value(u), Flavor::Value(mv)) => {
2535 Self::result_to_ext(u.jacobi_ds(mv, p, rm, cc), false, true)
2536 }
2537 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2538 _ => NAN,
2539 }
2540 }
2541 pub fn jacobi_dc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2543 match (&self.inner, &m.inner) {
2544 (Flavor::Value(u), Flavor::Value(mv)) => {
2545 Self::result_to_ext(u.jacobi_dc(mv, p, rm, cc), false, true)
2546 }
2547 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2548 _ => NAN,
2549 }
2550 }
2551 pub fn legendre_p(&self, n: u32, p: usize, rm: RoundingMode) -> Self {
2559 match &self.inner {
2560 Flavor::Value(v) => Self::result_to_ext(v.legendre_p(n, p, rm), false, true),
2561 Flavor::Inf(_) => NAN,
2562 Flavor::NaN(err) => Self::nan(*err),
2563 }
2564 }
2565 pub fn assoc_legendre_p(&self, n: u32, m: i32, p: usize, rm: RoundingMode) -> Self {
2573 match &self.inner {
2574 Flavor::Value(v) => Self::result_to_ext(v.assoc_legendre_p(n, m, p, rm), false, true),
2575 Flavor::Inf(_) => NAN,
2576 Flavor::NaN(err) => Self::nan(*err),
2577 }
2578 }
2579 pub fn hypergeom_2f1(
2587 &self,
2588 b: &Self,
2589 c: &Self,
2590 z: &Self,
2591 p: usize,
2592 rm: RoundingMode,
2593 cc: &mut Consts,
2594 ) -> Self {
2595 match (&self.inner, &b.inner, &c.inner, &z.inner) {
2596 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv), Flavor::Value(zv)) => {
2597 Self::result_to_ext(a.hypergeom_2f1(bv, cv, zv, p, rm, cc), zv.is_zero(), true)
2598 }
2599 (Flavor::NaN(err), _, _, _)
2600 | (_, Flavor::NaN(err), _, _)
2601 | (_, _, Flavor::NaN(err), _)
2602 | (_, _, _, Flavor::NaN(err)) => Self::nan(*err),
2603 _ => NAN,
2604 }
2605 }
2606 pub fn betainc(&self, b: &Self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2614 match (&self.inner, &b.inner, &x.inner) {
2615 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(xv)) => {
2616 Self::result_to_ext(a.betainc(bv, xv, p, rm, cc), xv.is_zero(), true)
2617 }
2618 (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2619 Self::nan(*err)
2620 }
2621 _ => NAN,
2622 }
2623 }
2624 gen_wrapper_arg_rm_cc!(
2625 "Computes the hyperbolic arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2626 This function requires constants cache `cc` for computing the result.
2627 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2628 asinh,
2629 Self,
2630 { INF_POS },
2631 { INF_NEG },
2632 p,
2633 usize
2634 );
2635 gen_wrapper_arg_rm_cc!(
2636 "Computes the hyperbolic arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2637 This function requires constants cache `cc` for computing the result.
2638 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2639 acosh,
2640 Self,
2641 { INF_POS },
2642 { NAN },
2643 p,
2644 usize
2645 );
2646 gen_wrapper_arg_rm_cc!(
2647 "Computes the hyperbolic arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2648 This function requires constants cache `cc` for computing the result.
2649 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2650 atanh,
2651 Self,
2652 { NAN },
2653 { NAN },
2654 p,
2655 usize
2656 );
2657}
2658
2659macro_rules! impl_int_conv {
2660 ($s:ty, $from_s:ident) => {
2661 impl ExactNum {
2662 pub fn $from_s(i: $s, p: usize) -> Self {
2666 Self::result_to_ext(ExactNumNumber::$from_s(i, p), false, true)
2667 }
2668 }
2669 };
2670}
2671
2672impl_int_conv!(i8, from_i8);
2673impl_int_conv!(i16, from_i16);
2674impl_int_conv!(i32, from_i32);
2675impl_int_conv!(i64, from_i64);
2676impl_int_conv!(i128, from_i128);
2677
2678impl_int_conv!(u8, from_u8);
2679impl_int_conv!(u16, from_u16);
2680impl_int_conv!(u32, from_u32);
2681impl_int_conv!(u64, from_u64);
2682impl_int_conv!(u128, from_u128);
2683
2684impl From<ExactNumNumber> for ExactNum {
2685 fn from(x: ExactNumNumber) -> Self {
2686 ExactNum {
2687 inner: Flavor::Value(x),
2688 }
2689 }
2690}
2691
2692#[cfg(feature = "std")]
2693use core::{
2694 fmt::{Binary, Display, Formatter, Octal, UpperHex},
2695 str::FromStr,
2696};
2697
2698use core::{cmp::Eq, cmp::Ordering, cmp::PartialEq, cmp::PartialOrd, ops::Neg};
2699
2700impl Neg for ExactNum {
2701 type Output = ExactNum;
2702 fn neg(mut self) -> Self::Output {
2703 self.inv_sign();
2704 self
2705 }
2706}
2707
2708impl Neg for &ExactNum {
2709 type Output = ExactNum;
2710 fn neg(self) -> Self::Output {
2711 let mut ret = self.clone();
2712 ret.inv_sign();
2713 ret
2714 }
2715}
2716
2717impl PartialEq for ExactNum {
2722 fn eq(&self, other: &Self) -> bool {
2723 let cmp_result = ExactNum::cmp(self, other);
2724 matches!(cmp_result, Some(0))
2725 }
2726}
2727
2728impl<'a> PartialEq<&'a ExactNum> for ExactNum {
2729 fn eq(&self, other: &&'a ExactNum) -> bool {
2730 let cmp_result = ExactNum::cmp(self, other);
2731 matches!(cmp_result, Some(0))
2732 }
2733}
2734
2735impl Eq for ExactNum {}
2736
2737impl PartialOrd for ExactNum {
2738 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2739 let cmp_result = ExactNum::cmp(self, other);
2740 match cmp_result {
2741 Some(v) => {
2742 if v > 0 {
2743 Some(Ordering::Greater)
2744 } else if v < 0 {
2745 Some(Ordering::Less)
2746 } else {
2747 Some(Ordering::Equal)
2748 }
2749 }
2750 None => None,
2751 }
2752 }
2753}
2754
2755impl<'a> PartialOrd<&'a ExactNum> for ExactNum {
2756 fn partial_cmp(&self, other: &&'a ExactNum) -> Option<Ordering> {
2757 let cmp_result = ExactNum::cmp(self, other);
2758 match cmp_result {
2759 Some(v) => {
2760 if v > 0 {
2761 Some(Ordering::Greater)
2762 } else if v < 0 {
2763 Some(Ordering::Less)
2764 } else {
2765 Some(Ordering::Equal)
2766 }
2767 }
2768 None => None,
2769 }
2770 }
2771}
2772
2773impl Default for ExactNum {
2774 fn default() -> ExactNum {
2775 ExactNum::new(DEFAULT_P)
2776 }
2777}
2778
2779#[cfg(feature = "std")]
2780impl FromStr for ExactNum {
2781 type Err = Error;
2782
2783 fn from_str(src: &str) -> Result<ExactNum, Self::Err> {
2786 let bf = crate::common::consts::TENPOWERS.with(|tp| {
2787 let cc = &mut tp.borrow_mut();
2788 ExactNum::parse(src, Radix::Dec, usize::MAX, RoundingMode::ToEven, cc)
2789 });
2790
2791 if bf.is_nan() {
2792 if let Some(err) = bf.err() {
2793 return Err(err);
2794 }
2795 }
2796
2797 Ok(bf)
2798 }
2799}
2800
2801macro_rules! impl_from {
2802 ($tt:ty, $fn:ident) => {
2803 impl From<$tt> for ExactNum {
2804 fn from(v: $tt) -> Self {
2805 ExactNum::$fn(v, DEFAULT_P)
2806 }
2807 }
2808 };
2809}
2810
2811impl_from!(i8, from_i8);
2812impl_from!(i16, from_i16);
2813impl_from!(i32, from_i32);
2814impl_from!(i64, from_i64);
2815impl_from!(i128, from_i128);
2816impl_from!(u8, from_u8);
2817impl_from!(u16, from_u16);
2818impl_from!(u32, from_u32);
2819impl_from!(u64, from_u64);
2820impl_from!(u128, from_u128);
2821
2822#[cfg(feature = "std")]
2823macro_rules! impl_format_rdx {
2824 ($trait:ty, $rdx:path) => {
2825 impl $trait for ExactNum {
2826 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
2829 crate::common::consts::TENPOWERS.with(|tp| {
2830 let cc = &mut tp.borrow_mut();
2831 self.write_str(f, $rdx, RoundingMode::ToEven, cc)
2832 })
2833 }
2834 }
2835 };
2836}
2837
2838#[cfg(feature = "std")]
2839impl_format_rdx!(Binary, Radix::Bin);
2840#[cfg(feature = "std")]
2841impl_format_rdx!(Octal, Radix::Oct);
2842#[cfg(feature = "std")]
2843impl_format_rdx!(Display, Radix::Dec);
2844#[cfg(feature = "std")]
2845impl_format_rdx!(core::fmt::LowerExp, Radix::Dec);
2846#[cfg(feature = "std")]
2847impl_format_rdx!(UpperHex, Radix::Hex);
2848#[cfg(feature = "std")]
2849impl core::fmt::UpperExp for ExactNum {
2850 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2851 crate::common::consts::TENPOWERS.with(|tp| {
2852 let cc = &mut tp.borrow_mut();
2853 let mut s = String::new();
2854 self.write_str(&mut s, Radix::Dec, RoundingMode::ToEven, cc)?;
2855 f.write_str(&s.replace('e', "E"))
2856 })
2857 }
2858}
2859#[cfg(feature = "std")]
2860impl core::fmt::LowerHex for ExactNum {
2861 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2862 crate::common::consts::TENPOWERS.with(|tp| {
2863 let cc = &mut tp.borrow_mut();
2864 let mut s = String::new();
2865 self.write_str(&mut s, Radix::Hex, RoundingMode::ToEven, cc)?;
2866 if matches!(s.as_str(), "Inf" | "-Inf" | "NaN" | "Err") {
2867 f.write_str(&s)
2868 } else {
2869 f.write_str(&s.to_ascii_lowercase())
2870 }
2871 })
2872 }
2873}
2874
2875macro_rules! impl_exact_binop {
2876 ($trait:ident, $method:ident, $op:ident) => {
2877 impl core::ops::$trait<&ExactNum> for &ExactNum {
2878 type Output = ExactNum;
2879
2880 fn $method(self, rhs: &ExactNum) -> ExactNum {
2881 ExactNum::$op(self, rhs, DEFAULT_P, RoundingMode::ToEven)
2882 }
2883 }
2884
2885 impl core::ops::$trait<ExactNum> for &ExactNum {
2886 type Output = ExactNum;
2887
2888 fn $method(self, rhs: ExactNum) -> ExactNum {
2889 ExactNum::$op(self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2890 }
2891 }
2892
2893 impl core::ops::$trait<&ExactNum> for ExactNum {
2894 type Output = ExactNum;
2895
2896 fn $method(self, rhs: &ExactNum) -> ExactNum {
2897 ExactNum::$op(&self, rhs, DEFAULT_P, RoundingMode::ToEven)
2898 }
2899 }
2900
2901 impl core::ops::$trait<ExactNum> for ExactNum {
2902 type Output = ExactNum;
2903
2904 fn $method(self, rhs: ExactNum) -> ExactNum {
2905 ExactNum::$op(&self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2906 }
2907 }
2908 };
2909}
2910
2911impl_exact_binop!(Add, add, add);
2912impl_exact_binop!(Sub, sub, sub);
2913impl_exact_binop!(Mul, mul, mul);
2914impl_exact_binop!(Div, div, div);
2915
2916pub trait FromExt<T> {
2918 fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self;
2920}
2921
2922impl<T> FromExt<T> for ExactNum
2923where
2924 ExactNum: From<T>,
2925{
2926 fn from_ext(v: T, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
2927 let mut ret = ExactNum::from(v);
2928 if let Err(err) = ret.set_precision(p, rm) {
2929 ExactNum::nan(Some(err))
2930 } else {
2931 ret
2932 }
2933 }
2934}
2935
2936impl FromExt<&str> for ExactNum {
2937 fn from_ext(v: &str, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2938 ExactNum::parse(v, crate::Radix::Dec, p, rm, cc)
2939 }
2940}
2941
2942#[cfg(test)]
2943mod tests {
2944
2945 use crate::common::util::rand_p;
2946 use crate::defs::DEFAULT_P;
2947 use crate::ext::ONE;
2948 use crate::ext::TWO;
2949 use crate::Consts;
2950 use crate::Error;
2951 use crate::ExactNum;
2952 use crate::Radix;
2953 use crate::Sign;
2954 use crate::Word;
2955 use crate::INF_NEG;
2956 use crate::INF_POS;
2957 use crate::NAN;
2958 use crate::{defs::RoundingMode, WORD_BIT_SIZE};
2959
2960 use core::num::FpCategory;
2961 #[cfg(feature = "std")]
2962 use std::str::FromStr;
2963
2964 #[cfg(not(feature = "std"))]
2965 use alloc::format;
2966
2967 #[cfg(target_pointer_width = "32")]
2968 #[test]
2969 fn test_decimal_formatting_round_trip() {
2970 let mut cc = Consts::new().unwrap();
2973 let p = 53;
2974 let rm = RoundingMode::ToEven;
2975 let value = ExactNum::parse("1.0", Radix::Dec, p, rm, &mut cc);
2976
2977 let formatted = value.format(Radix::Dec, rm, &mut cc).unwrap();
2978 assert_eq!(formatted, "1.e+0");
2979
2980 let reparsed = ExactNum::parse(&formatted, Radix::Dec, p, rm, &mut cc);
2981 assert_eq!(reparsed, value);
2982 }
2983
2984 #[test]
2985 fn test_ext() {
2986 let rm = RoundingMode::ToOdd;
2987 let mut cc = Consts::new().unwrap();
2988
2989 let d1 = ExactNum::from_u8(1, rand_p());
2991 assert!(!d1.is_inf());
2992 assert!(!d1.is_nan());
2993 assert!(!d1.is_inf_pos());
2994 assert!(!d1.is_inf_neg());
2995 assert!(d1.is_positive());
2996
2997 let mut d1 = d1.div(&ExactNum::new(rand_p()), rand_p(), rm);
2998 assert!(d1.is_inf());
2999 assert!(!d1.is_nan());
3000 assert!(d1.is_inf_pos());
3001 assert!(!d1.is_inf_neg());
3002 assert!(d1.is_positive());
3003
3004 d1.inv_sign();
3005 assert!(d1.is_inf());
3006 assert!(!d1.is_nan());
3007 assert!(!d1.is_inf_pos());
3008 assert!(d1.is_inf_neg());
3009 assert!(d1.is_negative());
3010
3011 let d1 = ExactNum::new(rand_p()).div(&ExactNum::new(rand_p()), rand_p(), rm);
3012 assert!(!d1.is_inf());
3013 assert!(d1.is_nan());
3014 assert!(!d1.is_inf_pos());
3015 assert!(!d1.is_inf_neg());
3016 assert!(d1.sign().is_none());
3017
3018 for _ in 0..1000 {
3019 let i = crate::common::test_rng::random::<i64>();
3020 let d1 = ExactNum::from_i64(i, rand_p());
3021 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3022 assert!(d1.cmp(&n1) == Some(0));
3023
3024 let i = crate::common::test_rng::random::<u64>();
3025 let d1 = ExactNum::from_u64(i, rand_p());
3026 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3027 assert!(d1.cmp(&n1) == Some(0));
3028
3029 let i = crate::common::test_rng::random::<i128>();
3030 let d1 = ExactNum::from_i128(i, rand_p());
3031 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3032 assert!(d1.cmp(&n1) == Some(0));
3033
3034 let i = crate::common::test_rng::random::<u128>();
3035 let d1 = ExactNum::from_u128(i, rand_p());
3036 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3037 assert!(d1.cmp(&n1) == Some(0));
3038 }
3039
3040 assert!(ONE.exponent().is_some());
3041 assert!(INF_POS.exponent().is_none());
3042 assert!(INF_NEG.exponent().is_none());
3043 assert!(NAN.exponent().is_none());
3044
3045 assert!(ONE.as_raw_parts().is_some());
3046 assert!(INF_POS.as_raw_parts().is_none());
3047 assert!(INF_NEG.as_raw_parts().is_none());
3048 assert!(NAN.as_raw_parts().is_none());
3049
3050 assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3051 assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
3052 assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
3053 assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3054 assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
3055 assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
3056 assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
3057 assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3058 assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
3059
3060 assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
3061 assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
3062 assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
3063 assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
3064 assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
3065 assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
3066 assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
3067 assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
3068 assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
3069
3070 assert!(ONE.sub_full_prec(&ONE).is_zero());
3071 assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
3072 assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
3073 assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
3074 assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
3075 assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
3076 assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
3077 assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
3078 assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
3079
3080 assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
3081 assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
3082 assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
3083 assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
3084 assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
3085 assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
3086 assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
3087 assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
3088 assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
3089
3090 assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
3091 assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3092 assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
3093 assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3094 assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
3095 assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
3096 assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3097 assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
3098 assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3099
3100 assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3101 assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3102 assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
3103 assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3104 assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
3105 assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
3106 assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3107 assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
3108 assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
3109 assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3110 assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3111 assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3112 assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
3113 assert!(INF_POS.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3114 assert!(INF_NEG.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3115 assert!(ExactNum::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
3116 assert!(ExactNum::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
3117
3118 assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
3119 assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
3120 assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
3121 assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
3122 assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
3123 assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
3124 assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
3125 assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
3126 assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
3127 assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
3128 assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
3129 assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
3130 assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
3131 assert!(INF_POS
3132 .div(&ExactNum::new(rand_p()), rand_p(), rm)
3133 .is_inf_pos());
3134 assert!(INF_NEG
3135 .div(&ExactNum::new(rand_p()), rand_p(), rm)
3136 .is_inf_neg());
3137 assert!(ExactNum::new(rand_p())
3138 .div(&INF_POS, rand_p(), rm)
3139 .is_zero());
3140 assert!(ExactNum::new(rand_p())
3141 .div(&INF_NEG, rand_p(), rm)
3142 .is_zero());
3143
3144 assert!(TWO.rem(&TWO).is_zero());
3145 assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
3146 assert!(INF_POS.rem(&TWO).is_nan());
3147 assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
3148 assert!(INF_NEG.rem(&TWO).is_nan());
3149 assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
3150 assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
3151 assert!(INF_POS.rem(&TWO.neg()).is_nan());
3152 assert!(INF_NEG.rem(&TWO.neg()).is_nan());
3153 assert!(INF_POS.rem(&INF_POS).is_nan());
3154 assert!(INF_POS.rem(&INF_NEG).is_nan());
3155 assert!(INF_NEG.rem(&INF_NEG).is_nan());
3156 assert!(INF_NEG.rem(&INF_POS).is_nan());
3157 assert!(INF_POS.rem(&ExactNum::new(rand_p())).is_nan());
3158 assert!(INF_NEG.rem(&ExactNum::new(rand_p())).is_nan());
3159 assert!(ExactNum::new(rand_p()).rem(&INF_POS).is_zero());
3160 assert!(ExactNum::new(rand_p()).rem(&INF_NEG).is_zero());
3161
3162 for op in [ExactNum::add, ExactNum::sub, ExactNum::mul, ExactNum::div] {
3163 assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
3164 assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
3165 assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
3166 assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
3167 assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
3168 assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
3169 assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
3170 }
3171
3172 assert!(ExactNum::rem(&NAN, &ONE).is_nan());
3173 assert!(ExactNum::rem(&ONE, &NAN).is_nan());
3174 assert!(ExactNum::rem(&NAN, &INF_POS).is_nan());
3175 assert!(ExactNum::rem(&INF_POS, &NAN).is_nan());
3176 assert!(ExactNum::rem(&NAN, &INF_NEG).is_nan());
3177 assert!(ExactNum::rem(&INF_NEG, &NAN).is_nan());
3178 assert!(ExactNum::rem(&NAN, &NAN).is_nan());
3179
3180 for op in [ExactNum::add_full_prec, ExactNum::sub_full_prec, ExactNum::mul_full_prec] {
3181 assert!(op(&NAN, &ONE).is_nan());
3182 assert!(op(&ONE, &NAN).is_nan());
3183 assert!(op(&NAN, &INF_POS).is_nan());
3184 assert!(op(&INF_POS, &NAN).is_nan());
3185 assert!(op(&NAN, &INF_NEG).is_nan());
3186 assert!(op(&INF_NEG, &NAN).is_nan());
3187 assert!(op(&NAN, &NAN).is_nan());
3188 }
3189
3190 assert!(ONE.cmp(&ONE).unwrap() == 0);
3191 assert!(ONE.cmp(&INF_POS).unwrap() < 0);
3192 assert!(INF_POS.cmp(&ONE).unwrap() > 0);
3193 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3194 assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
3195 assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
3196 assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
3197 assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
3198 assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
3199 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3200 assert!(ONE.cmp(&NAN).is_none());
3201 assert!(NAN.cmp(&ONE).is_none());
3202 assert!(INF_POS.cmp(&NAN).is_none());
3203 assert!(NAN.cmp(&INF_POS).is_none());
3204 assert!(INF_NEG.cmp(&NAN).is_none());
3205 assert!(NAN.cmp(&INF_NEG).is_none());
3206 assert!(NAN.cmp(&NAN).is_none());
3207
3208 assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
3209 assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
3210 assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
3211 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3212 assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
3213 assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
3214 assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
3215 assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
3216 assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
3217 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3218 assert!(ONE.abs_cmp(&NAN).is_none());
3219 assert!(NAN.abs_cmp(&ONE).is_none());
3220 assert!(INF_POS.abs_cmp(&NAN).is_none());
3221 assert!(NAN.abs_cmp(&INF_POS).is_none());
3222 assert!(INF_NEG.abs_cmp(&NAN).is_none());
3223 assert!(NAN.abs_cmp(&INF_NEG).is_none());
3224 assert!(NAN.abs_cmp(&NAN).is_none());
3225
3226 assert!(ONE.is_positive());
3227 assert!(!ONE.is_negative());
3228
3229 assert!(ONE.neg().is_negative());
3230 assert!(!ONE.neg().is_positive());
3231 assert!(!INF_POS.is_negative());
3232 assert!(INF_POS.is_positive());
3233 assert!(INF_NEG.is_negative());
3234 assert!(!INF_NEG.is_positive());
3235 assert!(!NAN.is_positive());
3236 assert!(!NAN.is_negative());
3237
3238 assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3239 assert!(ExactNum::new(DEFAULT_P)
3240 .pow(&INF_POS, rand_p(), rm, &mut cc)
3241 .is_zero());
3242 assert!(ExactNum::new(DEFAULT_P)
3243 .pow(&INF_NEG, rand_p(), rm, &mut cc)
3244 .is_zero());
3245 assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3246 assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3247 assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3248 assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
3249 assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3250 assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
3251 assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3252 assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3253 assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3254 assert!(
3255 INF_POS
3256 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3257 .cmp(&ONE)
3258 == Some(0)
3259 );
3260 assert!(
3261 INF_NEG
3262 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3263 .cmp(&ONE)
3264 == Some(0)
3265 );
3266 assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3267 assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3268 assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3269 assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3270
3271 let half = ONE.div(&TWO, rand_p(), rm);
3272 assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3273 assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3274 assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3275 assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3276 assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3277 assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3278 assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3279 assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3280 assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
3281 assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
3282 assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3283 assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3284 assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3285 assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3286 assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3287 assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3288 assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
3289
3290 assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3291 assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
3292 assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3293 assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3294 assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3295 assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3296 assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3297
3298 assert!(NAN.powi(2, rand_p(), rm).is_nan());
3299 assert!(NAN.powi(0, rand_p(), rm).is_nan());
3300 assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
3301 assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
3302 assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
3303 assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
3304 assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3305 assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3306
3307 assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3308 assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3309 assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3310 assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3311 assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3312 assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3313 assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3314
3315 assert!(INF_NEG.abs().is_inf_pos());
3316 assert!(INF_POS.abs().is_inf_pos());
3317 assert!(NAN.abs().is_nan());
3318
3319 assert!(INF_NEG.int().is_nan());
3320 assert!(INF_POS.int().is_nan());
3321 assert!(NAN.int().is_nan());
3322
3323 assert!(INF_NEG.fract().is_nan());
3324 assert!(INF_POS.fract().is_nan());
3325 assert!(NAN.fract().is_nan());
3326
3327 assert!(INF_NEG.ceil().is_inf_neg());
3328 assert!(INF_POS.ceil().is_inf_pos());
3329 assert!(NAN.ceil().is_nan());
3330
3331 assert!(INF_NEG.floor().is_inf_neg());
3332 assert!(INF_POS.floor().is_inf_pos());
3333 assert!(NAN.floor().is_nan());
3334
3335 for rm in [
3336 RoundingMode::Up,
3337 RoundingMode::Down,
3338 RoundingMode::ToZero,
3339 RoundingMode::FromZero,
3340 RoundingMode::ToEven,
3341 RoundingMode::ToOdd,
3342 ] {
3343 assert!(INF_NEG.round(0, rm).is_inf_neg());
3344 assert!(INF_POS.round(0, rm).is_inf_pos());
3345 assert!(NAN.round(0, rm).is_nan());
3346 }
3347
3348 assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
3349 assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
3350 assert!(NAN.sqrt(rand_p(), rm).is_nan());
3351
3352 assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
3353 assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
3354 assert!(NAN.cbrt(rand_p(), rm).is_nan());
3355
3356 for op in [ExactNum::ln, ExactNum::log2, ExactNum::log10] {
3357 assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3358 assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3359 assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
3360 }
3361
3362 assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
3363 assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
3364 assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
3365
3366 assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
3367 assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
3368 assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
3369
3370 assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
3371 assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
3372 assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
3373
3374 assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
3375 assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
3376 assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
3377
3378 assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
3379 assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
3380 assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
3381
3382 assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
3383 assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
3384 assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
3385
3386 let p = rand_p();
3387 let mut half_pi: ExactNum = cc.pi_num(p, rm).unwrap().into();
3388 half_pi.set_exponent(1);
3389 assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
3390 assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
3391 assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
3392
3393 assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
3394 assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
3395 assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
3396
3397 assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3398 assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3399 assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
3400
3401 assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
3402 assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3403 assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
3404
3405 assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
3406 assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
3407 assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
3408
3409 assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
3410 assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
3411 assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
3412
3413 assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
3414 assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
3415 assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
3416
3417 assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
3418 assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
3419 assert!(NAN.reciprocal(rand_p(), rm).is_nan());
3420
3421 assert!(TWO.signum().cmp(&ONE) == Some(0));
3422 assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
3423 assert!(INF_POS.signum().cmp(&ONE) == Some(0));
3424 assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
3425 assert!(NAN.signum().is_nan());
3426
3427 let d1 = ONE.clone();
3428 assert!(d1.exponent() == Some(1));
3429 let words: &[Word] = {
3430 #[cfg(not(target_pointer_width = "32"))]
3431 {
3432 &[0, 0x8000000000000000]
3433 }
3434 #[cfg(target_pointer_width = "32")]
3435 {
3436 &[0, 0, 0, 0x80000000]
3437 }
3438 };
3439
3440 assert!(d1.mantissa_digits() == Some(words));
3441 assert!(d1.is_inline());
3442 assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
3443 assert!(d1.precision() == Some(DEFAULT_P));
3444 assert!(d1.sign() == Some(Sign::Pos));
3445
3446 assert!(INF_POS.exponent().is_none());
3447 assert!(INF_POS.mantissa_digits().is_none());
3448 assert!(INF_POS.mantissa_max_bit_len().is_none());
3449 assert!(INF_POS.precision().is_none());
3450 assert!(INF_POS.sign() == Some(Sign::Pos));
3451
3452 assert!(INF_NEG.exponent().is_none());
3453 assert!(INF_NEG.mantissa_digits().is_none());
3454 assert!(INF_NEG.mantissa_max_bit_len().is_none());
3455 assert!(INF_NEG.precision().is_none());
3456 assert!(INF_NEG.sign() == Some(Sign::Neg));
3457
3458 assert!(NAN.exponent().is_none());
3459 assert!(NAN.mantissa_digits().is_none());
3460 assert!(NAN.mantissa_max_bit_len().is_none());
3461 assert!(NAN.precision().is_none());
3462 assert!(NAN.sign().is_none());
3463
3464 INF_POS.clone().set_exponent(1);
3465 INF_POS.clone().set_precision(1, rm).unwrap();
3466 INF_POS.clone().set_sign(Sign::Pos);
3467
3468 INF_NEG.clone().set_exponent(1);
3469 INF_NEG.clone().set_precision(1, rm).unwrap();
3470 INF_NEG.clone().set_sign(Sign::Pos);
3471
3472 NAN.clone().set_exponent(1);
3473 NAN.clone().set_precision(1, rm).unwrap();
3474 NAN.clone().set_sign(Sign::Pos);
3475
3476 assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
3477 assert!(INF_NEG.min(&ONE).is_inf_neg());
3478 assert!(NAN.min(&ONE).is_nan());
3479 assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
3480 assert!(ONE.min(&INF_NEG).is_inf_neg());
3481 assert!(ONE.min(&NAN).is_nan());
3482 assert!(NAN.min(&INF_POS).is_nan());
3483 assert!(NAN.min(&INF_NEG).is_nan());
3484 assert!(NAN.min(&NAN).is_nan());
3485 assert!(INF_NEG.min(&INF_POS).is_inf_neg());
3486 assert!(INF_POS.min(&INF_NEG).is_inf_neg());
3487 assert!(INF_POS.min(&INF_POS).is_inf_pos());
3488 assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
3489
3490 assert!(INF_POS.max(&ONE).is_inf_pos());
3491 assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
3492 assert!(NAN.max(&ONE).is_nan());
3493 assert!(ONE.max(&INF_POS).is_inf_pos());
3494 assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
3495 assert!(ONE.max(&NAN).is_nan());
3496 assert!(NAN.max(&INF_POS).is_nan());
3497 assert!(NAN.max(&INF_NEG).is_nan());
3498 assert!(NAN.max(&NAN).is_nan());
3499 assert!(INF_NEG.max(&INF_POS).is_inf_pos());
3500 assert!(INF_POS.max(&INF_NEG).is_inf_pos());
3501 assert!(INF_POS.max(&INF_POS).is_inf_pos());
3502 assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
3503
3504 assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
3505 assert!(ONE.clamp(&TWO, &ONE).is_nan());
3506 assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
3507 assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
3508 assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3509 assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
3510 assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
3511 assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
3512 assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
3513 assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
3514 assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
3515 assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
3516 assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3517 assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
3518 assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
3519 assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
3520 assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
3521 assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
3522 assert!(NAN.clamp(&ONE, &TWO).is_nan());
3523 assert!(NAN.clamp(&NAN, &TWO).is_nan());
3524 assert!(NAN.clamp(&ONE, &NAN).is_nan());
3525 assert!(NAN.clamp(&NAN, &NAN).is_nan());
3526 assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
3527
3528 assert!(ExactNum::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
3529 assert!(INF_POS.classify() == FpCategory::Infinite);
3530 assert!(INF_NEG.classify() == FpCategory::Infinite);
3531 assert!(NAN.classify() == FpCategory::Nan);
3532 assert!(ONE.classify() == FpCategory::Normal);
3533
3534 assert!(!INF_POS.is_subnormal());
3535 assert!(!INF_NEG.is_subnormal());
3536 assert!(!NAN.is_subnormal());
3537 assert!(ExactNum::min_positive(DEFAULT_P).is_subnormal());
3538 assert!(!ExactNum::min_positive_normal(DEFAULT_P).is_subnormal());
3539 assert!(!ExactNum::max_value(DEFAULT_P).is_subnormal());
3540 assert!(!ExactNum::min_value(DEFAULT_P).is_subnormal());
3541
3542 let n1 = ExactNum::convert_from_radix(
3543 Sign::Pos,
3544 &[],
3545 0,
3546 Radix::Dec,
3547 usize::MAX - 1,
3548 RoundingMode::None,
3549 &mut cc,
3550 );
3551 assert!(n1.is_nan());
3552 assert!(n1.err() == Some(Error::InvalidArgument));
3553
3554 assert!(
3555 n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3556 == Err(Error::InvalidArgument)
3557 );
3558 assert!(
3559 INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3560 == Err(Error::InvalidArgument)
3561 );
3562 assert!(
3563 INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3564 == Err(Error::InvalidArgument)
3565 );
3566 }
3567
3568 #[cfg(feature = "std")]
3569 #[test]
3570 fn test_ops_std() {
3571 let mut cc = Consts::new().unwrap();
3572
3573 let d1 = ExactNum::parse(
3574 "0.0123456789012345678901234567890123456789",
3575 Radix::Dec,
3576 DEFAULT_P,
3577 RoundingMode::None,
3578 &mut cc,
3579 );
3580
3581 let d1str = format!("{}", d1);
3582 assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
3583 assert_eq!(format!("{:e}", d1), d1str);
3584 assert_eq!(
3585 format!("{:E}", d1),
3586 "1.23456789012345678901234567890123456789E-2"
3587 );
3588 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3589 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3590 assert_eq!(d2, d1);
3591
3592 let d1 = ExactNum::parse(
3593 "-123.456789012345678901234567890123456789",
3594 Radix::Dec,
3595 DEFAULT_P,
3596 RoundingMode::None,
3597 &mut cc,
3598 );
3599 let d1str = format!("{}", d1);
3600 assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
3601 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3602 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3603 assert_eq!(d2, d1);
3604
3605 let d1str = format!("{}", INF_POS);
3606 assert_eq!(d1str, "Inf");
3607
3608 let d1str = format!("{}", INF_NEG);
3609 assert_eq!(d1str, "-Inf");
3610
3611 let d1str = format!("{}", NAN);
3612 assert_eq!(d1str, "NaN");
3613
3614 assert!(ExactNum::from_str("abc").is_ok());
3615 assert!(ExactNum::from_str("abc").unwrap().is_nan());
3616 }
3617
3618 #[test]
3619 pub fn test_ops() {
3620 let mut cc = Consts::new().unwrap();
3621
3622 let d1 = -&(TWO.clone());
3623 assert!(d1.is_negative());
3624
3625 let p = DEFAULT_P;
3626 let rm = RoundingMode::ToEven;
3627 let two = ExactNum::from_u8(2, p);
3628 let eighth = two.powsi(-3, p, rm);
3629 let expected = ExactNum::from_u8(1, p).div(&ExactNum::from_u8(8, p), p, rm);
3630 assert_eq!(eighth.cmp(&expected), Some(0));
3631 assert_eq!(two.powsi(3, p, rm).cmp(&ExactNum::from_u8(8, p)), Some(0));
3632 assert!(
3633 ExactNum::from_i8(-123, p) == ExactNum::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
3634 );
3635 assert!(
3636 ExactNum::from_u8(123, p) == ExactNum::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
3637 );
3638 assert!(
3639 ExactNum::from_i16(-12312, p)
3640 == ExactNum::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
3641 );
3642 assert!(
3643 ExactNum::from_u16(12312, p)
3644 == ExactNum::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
3645 );
3646 assert!(
3647 ExactNum::from_i32(-123456789, p)
3648 == ExactNum::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3649 );
3650 assert!(
3651 ExactNum::from_u32(123456789, p)
3652 == ExactNum::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3653 );
3654 assert!(
3655 ExactNum::from_i64(-1234567890123456789, p)
3656 == ExactNum::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3657 );
3658 assert!(
3659 ExactNum::from_u64(1234567890123456789, p)
3660 == ExactNum::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3661 );
3662 assert!(
3663 ExactNum::from_i128(-123456789012345678901234567890123456789, p)
3664 == ExactNum::parse(
3665 "-1.23456789012345678901234567890123456789e+38",
3666 Radix::Dec,
3667 p,
3668 rm,
3669 &mut cc
3670 )
3671 );
3672 assert!(
3673 ExactNum::from_u128(123456789012345678901234567890123456789, p)
3674 == ExactNum::parse(
3675 "1.23456789012345678901234567890123456789e+38",
3676 Radix::Dec,
3677 p,
3678 rm,
3679 &mut cc
3680 )
3681 );
3682
3683 let neg = ExactNum::from_i8(-3, WORD_BIT_SIZE);
3684 let pos = ExactNum::from_i8(5, WORD_BIT_SIZE);
3685
3686 assert!(pos > neg);
3687 assert!(neg < pos);
3688 assert!(!(pos < neg));
3689 assert!(!(neg > pos));
3690 assert!(INF_NEG < neg);
3691 assert!(INF_NEG < pos);
3692 assert!(INF_NEG < INF_POS);
3693 assert!(!(INF_NEG > neg));
3694 assert!(!(INF_NEG > pos));
3695 assert!(!(INF_NEG > INF_POS));
3696 assert!(INF_POS > neg);
3697 assert!(INF_POS > pos);
3698 assert!(INF_POS > INF_NEG);
3699 assert!(!(INF_POS < neg));
3700 assert!(!(INF_POS < pos));
3701 assert!(!(INF_POS < INF_NEG));
3702 assert!(!(INF_POS > INF_POS));
3703 assert!(!(INF_POS < INF_POS));
3704 assert!(!(INF_NEG > INF_NEG));
3705 assert!(!(INF_NEG < INF_NEG));
3706 assert!(!(INF_POS > NAN));
3707 assert!(!(INF_POS < NAN));
3708 assert!(!(INF_NEG > NAN));
3709 assert!(!(INF_NEG < NAN));
3710 assert!(!(NAN > INF_POS));
3711 assert!(!(NAN < INF_POS));
3712 assert!(!(NAN > INF_NEG));
3713 assert!(!(NAN < INF_NEG));
3714 assert!(!(NAN > NAN));
3715 assert!(!(NAN < NAN));
3716 assert!(!(neg > NAN));
3717 assert!(!(neg < NAN));
3718 assert!(!(pos > NAN));
3719 assert!(!(pos < NAN));
3720 assert!(!(NAN > neg));
3721 assert!(!(NAN < neg));
3722 assert!(!(NAN > pos));
3723 assert!(!(NAN < pos));
3724
3725 assert!(!(NAN == NAN));
3726 assert!(!(NAN == INF_POS));
3727 assert!(!(NAN == INF_NEG));
3728 assert!(!(INF_POS == NAN));
3729 assert!(!(INF_NEG == NAN));
3730 assert!(!(INF_NEG == INF_POS));
3731 assert!(!(INF_POS == INF_NEG));
3732 assert!(!(INF_POS == neg));
3733 assert!(!(INF_POS == pos));
3734 assert!(!(INF_NEG == neg));
3735 assert!(!(INF_NEG == pos));
3736 assert!(!(neg == INF_POS));
3737 assert!(!(pos == INF_POS));
3738 assert!(!(neg == INF_NEG));
3739 assert!(!(pos == INF_NEG));
3740 assert!(!(pos == neg));
3741 assert!(!(neg == pos));
3742 assert!(neg == neg);
3743 assert!(pos == pos);
3744 assert!(INF_NEG == INF_NEG);
3745 assert!(INF_POS == INF_POS);
3746 }
3747
3748 #[test]
3749 fn test_oom_and_large_precision() {
3750 let oom = ExactNum::nan(Some(Error::MemoryAllocation));
3751 assert!(oom.is_nan());
3752 assert_eq!(oom.err(), Some(Error::MemoryAllocation));
3753
3754 let n = ExactNum::new(usize::MAX);
3755 assert!(n.is_nan());
3756 assert_eq!(n.err(), Some(Error::InvalidArgument));
3757
3758 let p = 128 * WORD_BIT_SIZE;
3759 let a = ExactNum::from_word(3, p);
3760 let b = ExactNum::from_word(5, p);
3761 let s = a.add(&b, p, RoundingMode::ToEven);
3762 let m = a.mul(&b, p, RoundingMode::ToEven);
3763 assert!(!s.is_nan(), "large-prec add hung or failed");
3764 assert!(!m.is_nan(), "large-prec mul hung or failed");
3765 assert_eq!(s.cmp(&ExactNum::from_word(8, p)), Some(0));
3766 }
3767
3768 #[test]
3769 fn test_two_sum_fused_polyval() {
3770 let p = 128;
3771 let rm = RoundingMode::ToEven;
3772 let one = ExactNum::from_u8(1, p);
3773 let two = ExactNum::from_u8(2, p);
3774 let three = ExactNum::from_u8(3, p);
3775
3776 let (hi, lo) = one.two_sum(&two, p, rm);
3777 let rec = hi.add(&lo, p, rm);
3778 assert_eq!(rec.cmp(&ExactNum::from_u8(3, p)), Some(0));
3779
3780 let (ph, pl) = two.two_product(&three, p, rm);
3781 let pr = ph.add(&pl, p, rm);
3782 assert_eq!(pr.cmp(&ExactNum::from_u8(6, p)), Some(0));
3783
3784 let sum = ExactNum::fused_sum(&[one.clone(), two.clone(), three.clone()], p, rm);
3785 assert_eq!(sum.cmp(&ExactNum::from_u8(6, p)), Some(0));
3786
3787 let dot = ExactNum::fused_dot(
3788 &[one.clone(), two.clone()],
3789 &[three.clone(), one.clone()],
3790 p,
3791 rm,
3792 );
3793 assert_eq!(dot.cmp(&ExactNum::from_u8(5, p)), Some(0));
3794
3795 let pv = ExactNum::polyval(&[one, two, three], &ExactNum::from_u8(2, p), p, rm);
3797 assert_eq!(pv.cmp(&ExactNum::from_u8(17, p)), Some(0));
3798 }
3799
3800 #[test]
3801 fn test_jacobi_sn_public() {
3802 let p = 256;
3803 let rm = RoundingMode::ToEven;
3804 let mut cc = Consts::new().unwrap();
3805 let one = ExactNum::from_u8(1, p);
3806 let zero = ExactNum::from_u8(0, p);
3807 let half = one.div(&ExactNum::from_u8(2, p), p, rm);
3808 let sn0 = zero.jacobi_sn(&half, p, rm, &mut cc);
3809 assert!(sn0.is_zero(), "sn(0)");
3810 let cn0 = zero.jacobi_cn(&half, p, rm, &mut cc);
3811 assert_eq!(cn0.cmp(&one), Some(0), "cn(0)");
3812 let sn_m0 = one.jacobi_sn(&zero, p, rm, &mut cc);
3813 let sin1 = one.sin(p, rm, &mut cc);
3814 let d = sn_m0.sub(&sin1, p, rm).abs();
3815 assert!(
3816 d.is_zero() || d.exponent().unwrap() < -80,
3817 "sn(1|0)=sin 1"
3818 );
3819 assert!(one
3820 .jacobi_sn(&ExactNum::from_i8(2, p), p, rm, &mut cc)
3821 .is_nan());
3822 }
3823}
3824
3825#[cfg(feature = "random")]
3826#[cfg(test)]
3827mod rand_tests {
3828
3829 use super::*;
3830 use crate::common::util::TEST_EXP_BOUND;
3831
3832 #[test]
3833 fn test_rand() {
3834 for _ in 0..100 {
3835 let p = crate::common::test_rng::random::<usize>() % 192 + DEFAULT_P;
3836 let exp_from = crate::common::test_rng::random::<Exponent>().abs() % TEST_EXP_BOUND;
3837 let span = (TEST_EXP_BOUND - exp_from).max(1);
3838 let exp_shift = crate::common::test_rng::random::<Exponent>().abs() % span;
3839 let exp_to = exp_from + exp_shift;
3840
3841 let n = ExactNum::random_normal(p, exp_from, exp_to);
3842
3843 assert!(!n.is_subnormal());
3844 assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
3845 assert!(n.precision().unwrap() >= p);
3846 }
3847 }
3848}