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 {
2479 match (&self.inner, &m.inner) {
2480 (Flavor::Value(u), Flavor::Value(mv)) => {
2481 Self::result_to_ext(u.jacobi_ns(mv, p, rm, cc), false, true)
2482 }
2483 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2484 _ => NAN,
2485 }
2486 }
2487 pub fn jacobi_nc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2495 match (&self.inner, &m.inner) {
2496 (Flavor::Value(u), Flavor::Value(mv)) => {
2497 Self::result_to_ext(u.jacobi_nc(mv, p, rm, cc), false, true)
2498 }
2499 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2500 _ => NAN,
2501 }
2502 }
2503 pub fn jacobi_nd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2511 match (&self.inner, &m.inner) {
2512 (Flavor::Value(u), Flavor::Value(mv)) => {
2513 Self::result_to_ext(u.jacobi_nd(mv, p, rm, cc), false, true)
2514 }
2515 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2516 _ => NAN,
2517 }
2518 }
2519 pub fn jacobi_sc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2527 match (&self.inner, &m.inner) {
2528 (Flavor::Value(u), Flavor::Value(mv)) => {
2529 Self::result_to_ext(u.jacobi_sc(mv, p, rm, cc), false, true)
2530 }
2531 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2532 _ => NAN,
2533 }
2534 }
2535 pub fn jacobi_sd(&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_sd(mv, p, rm, cc), false, true)
2546 }
2547 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2548 _ => NAN,
2549 }
2550 }
2551 pub fn jacobi_cs(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2559 match (&self.inner, &m.inner) {
2560 (Flavor::Value(u), Flavor::Value(mv)) => {
2561 Self::result_to_ext(u.jacobi_cs(mv, p, rm, cc), false, true)
2562 }
2563 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2564 _ => NAN,
2565 }
2566 }
2567 pub fn jacobi_ds(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2575 match (&self.inner, &m.inner) {
2576 (Flavor::Value(u), Flavor::Value(mv)) => {
2577 Self::result_to_ext(u.jacobi_ds(mv, p, rm, cc), false, true)
2578 }
2579 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2580 _ => NAN,
2581 }
2582 }
2583 pub fn jacobi_dc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2591 match (&self.inner, &m.inner) {
2592 (Flavor::Value(u), Flavor::Value(mv)) => {
2593 Self::result_to_ext(u.jacobi_dc(mv, p, rm, cc), false, true)
2594 }
2595 (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2596 _ => NAN,
2597 }
2598 }
2599 pub fn legendre_p(&self, n: u32, p: usize, rm: RoundingMode) -> Self {
2607 match &self.inner {
2608 Flavor::Value(v) => Self::result_to_ext(v.legendre_p(n, p, rm), false, true),
2609 Flavor::Inf(_) => NAN,
2610 Flavor::NaN(err) => Self::nan(*err),
2611 }
2612 }
2613 pub fn assoc_legendre_p(&self, n: u32, m: i32, p: usize, rm: RoundingMode) -> Self {
2621 match &self.inner {
2622 Flavor::Value(v) => Self::result_to_ext(v.assoc_legendre_p(n, m, p, rm), false, true),
2623 Flavor::Inf(_) => NAN,
2624 Flavor::NaN(err) => Self::nan(*err),
2625 }
2626 }
2627 pub fn hypergeom_2f1(
2635 &self,
2636 b: &Self,
2637 c: &Self,
2638 z: &Self,
2639 p: usize,
2640 rm: RoundingMode,
2641 cc: &mut Consts,
2642 ) -> Self {
2643 match (&self.inner, &b.inner, &c.inner, &z.inner) {
2644 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv), Flavor::Value(zv)) => {
2645 Self::result_to_ext(a.hypergeom_2f1(bv, cv, zv, p, rm, cc), zv.is_zero(), true)
2646 }
2647 (Flavor::NaN(err), _, _, _)
2648 | (_, Flavor::NaN(err), _, _)
2649 | (_, _, Flavor::NaN(err), _)
2650 | (_, _, _, Flavor::NaN(err)) => Self::nan(*err),
2651 _ => NAN,
2652 }
2653 }
2654 pub fn betainc(&self, b: &Self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2662 match (&self.inner, &b.inner, &x.inner) {
2663 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(xv)) => {
2664 Self::result_to_ext(a.betainc(bv, xv, p, rm, cc), xv.is_zero(), true)
2665 }
2666 (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2667 Self::nan(*err)
2668 }
2669 _ => NAN,
2670 }
2671 }
2672 gen_wrapper_arg_rm_cc!(
2673 "Computes the hyperbolic arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2674 This function requires constants cache `cc` for computing the result.
2675 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2676 asinh,
2677 Self,
2678 { INF_POS },
2679 { INF_NEG },
2680 p,
2681 usize
2682 );
2683 gen_wrapper_arg_rm_cc!(
2684 "Computes the hyperbolic arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2685 This function requires constants cache `cc` for computing the result.
2686 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2687 acosh,
2688 Self,
2689 { INF_POS },
2690 { NAN },
2691 p,
2692 usize
2693 );
2694 gen_wrapper_arg_rm_cc!(
2695 "Computes the hyperbolic arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2696 This function requires constants cache `cc` for computing the result.
2697 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2698 atanh,
2699 Self,
2700 { NAN },
2701 { NAN },
2702 p,
2703 usize
2704 );
2705}
2706
2707macro_rules! impl_int_conv {
2708 ($s:ty, $from_s:ident) => {
2709 impl ExactNum {
2710 pub fn $from_s(i: $s, p: usize) -> Self {
2714 Self::result_to_ext(ExactNumNumber::$from_s(i, p), false, true)
2715 }
2716 }
2717 };
2718}
2719
2720impl_int_conv!(i8, from_i8);
2721impl_int_conv!(i16, from_i16);
2722impl_int_conv!(i32, from_i32);
2723impl_int_conv!(i64, from_i64);
2724impl_int_conv!(i128, from_i128);
2725
2726impl_int_conv!(u8, from_u8);
2727impl_int_conv!(u16, from_u16);
2728impl_int_conv!(u32, from_u32);
2729impl_int_conv!(u64, from_u64);
2730impl_int_conv!(u128, from_u128);
2731
2732impl From<ExactNumNumber> for ExactNum {
2733 fn from(x: ExactNumNumber) -> Self {
2734 ExactNum {
2735 inner: Flavor::Value(x),
2736 }
2737 }
2738}
2739
2740#[cfg(feature = "std")]
2741use core::{
2742 fmt::{Binary, Display, Formatter, Octal, UpperHex},
2743 str::FromStr,
2744};
2745
2746use core::{cmp::Eq, cmp::Ordering, cmp::PartialEq, cmp::PartialOrd, ops::Neg};
2747
2748impl Neg for ExactNum {
2749 type Output = ExactNum;
2750 fn neg(mut self) -> Self::Output {
2751 self.inv_sign();
2752 self
2753 }
2754}
2755
2756impl Neg for &ExactNum {
2757 type Output = ExactNum;
2758 fn neg(self) -> Self::Output {
2759 let mut ret = self.clone();
2760 ret.inv_sign();
2761 ret
2762 }
2763}
2764
2765impl PartialEq for ExactNum {
2770 fn eq(&self, other: &Self) -> bool {
2771 let cmp_result = ExactNum::cmp(self, other);
2772 matches!(cmp_result, Some(0))
2773 }
2774}
2775
2776impl<'a> PartialEq<&'a ExactNum> for ExactNum {
2777 fn eq(&self, other: &&'a ExactNum) -> bool {
2778 let cmp_result = ExactNum::cmp(self, other);
2779 matches!(cmp_result, Some(0))
2780 }
2781}
2782
2783impl Eq for ExactNum {}
2784
2785impl PartialOrd for ExactNum {
2786 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2787 let cmp_result = ExactNum::cmp(self, other);
2788 match cmp_result {
2789 Some(v) => {
2790 if v > 0 {
2791 Some(Ordering::Greater)
2792 } else if v < 0 {
2793 Some(Ordering::Less)
2794 } else {
2795 Some(Ordering::Equal)
2796 }
2797 }
2798 None => None,
2799 }
2800 }
2801}
2802
2803impl<'a> PartialOrd<&'a ExactNum> for ExactNum {
2804 fn partial_cmp(&self, other: &&'a ExactNum) -> Option<Ordering> {
2805 let cmp_result = ExactNum::cmp(self, other);
2806 match cmp_result {
2807 Some(v) => {
2808 if v > 0 {
2809 Some(Ordering::Greater)
2810 } else if v < 0 {
2811 Some(Ordering::Less)
2812 } else {
2813 Some(Ordering::Equal)
2814 }
2815 }
2816 None => None,
2817 }
2818 }
2819}
2820
2821impl Default for ExactNum {
2822 fn default() -> ExactNum {
2823 ExactNum::new(DEFAULT_P)
2824 }
2825}
2826
2827#[cfg(feature = "std")]
2828impl FromStr for ExactNum {
2829 type Err = Error;
2830
2831 fn from_str(src: &str) -> Result<ExactNum, Self::Err> {
2834 let bf = crate::common::consts::TENPOWERS.with(|tp| {
2835 let cc = &mut tp.borrow_mut();
2836 ExactNum::parse(src, Radix::Dec, usize::MAX, RoundingMode::ToEven, cc)
2837 });
2838
2839 if bf.is_nan() {
2840 if let Some(err) = bf.err() {
2841 return Err(err);
2842 }
2843 }
2844
2845 Ok(bf)
2846 }
2847}
2848
2849macro_rules! impl_from {
2850 ($tt:ty, $fn:ident) => {
2851 impl From<$tt> for ExactNum {
2852 fn from(v: $tt) -> Self {
2853 ExactNum::$fn(v, DEFAULT_P)
2854 }
2855 }
2856 };
2857}
2858
2859impl_from!(i8, from_i8);
2860impl_from!(i16, from_i16);
2861impl_from!(i32, from_i32);
2862impl_from!(i64, from_i64);
2863impl_from!(i128, from_i128);
2864impl_from!(u8, from_u8);
2865impl_from!(u16, from_u16);
2866impl_from!(u32, from_u32);
2867impl_from!(u64, from_u64);
2868impl_from!(u128, from_u128);
2869
2870#[cfg(feature = "std")]
2871macro_rules! impl_format_rdx {
2872 ($trait:ty, $rdx:path) => {
2873 impl $trait for ExactNum {
2874 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
2877 crate::common::consts::TENPOWERS.with(|tp| {
2878 let cc = &mut tp.borrow_mut();
2879 self.write_str(f, $rdx, RoundingMode::ToEven, cc)
2880 })
2881 }
2882 }
2883 };
2884}
2885
2886#[cfg(feature = "std")]
2887impl_format_rdx!(Binary, Radix::Bin);
2888#[cfg(feature = "std")]
2889impl_format_rdx!(Octal, Radix::Oct);
2890#[cfg(feature = "std")]
2891impl_format_rdx!(Display, Radix::Dec);
2892#[cfg(feature = "std")]
2893impl_format_rdx!(core::fmt::LowerExp, Radix::Dec);
2894#[cfg(feature = "std")]
2895impl_format_rdx!(UpperHex, Radix::Hex);
2896#[cfg(feature = "std")]
2897impl core::fmt::UpperExp for ExactNum {
2898 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2899 crate::common::consts::TENPOWERS.with(|tp| {
2900 let cc = &mut tp.borrow_mut();
2901 let mut s = String::new();
2902 self.write_str(&mut s, Radix::Dec, RoundingMode::ToEven, cc)?;
2903 f.write_str(&s.replace('e', "E"))
2904 })
2905 }
2906}
2907#[cfg(feature = "std")]
2908impl core::fmt::LowerHex for ExactNum {
2909 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2910 crate::common::consts::TENPOWERS.with(|tp| {
2911 let cc = &mut tp.borrow_mut();
2912 let mut s = String::new();
2913 self.write_str(&mut s, Radix::Hex, RoundingMode::ToEven, cc)?;
2914 if matches!(s.as_str(), "Inf" | "-Inf" | "NaN" | "Err") {
2915 f.write_str(&s)
2916 } else {
2917 f.write_str(&s.to_ascii_lowercase())
2918 }
2919 })
2920 }
2921}
2922
2923macro_rules! impl_exact_binop {
2924 ($trait:ident, $method:ident, $op:ident) => {
2925 impl core::ops::$trait<&ExactNum> for &ExactNum {
2926 type Output = ExactNum;
2927
2928 fn $method(self, rhs: &ExactNum) -> ExactNum {
2929 ExactNum::$op(self, rhs, DEFAULT_P, RoundingMode::ToEven)
2930 }
2931 }
2932
2933 impl core::ops::$trait<ExactNum> for &ExactNum {
2934 type Output = ExactNum;
2935
2936 fn $method(self, rhs: ExactNum) -> ExactNum {
2937 ExactNum::$op(self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2938 }
2939 }
2940
2941 impl core::ops::$trait<&ExactNum> for ExactNum {
2942 type Output = ExactNum;
2943
2944 fn $method(self, rhs: &ExactNum) -> ExactNum {
2945 ExactNum::$op(&self, rhs, DEFAULT_P, RoundingMode::ToEven)
2946 }
2947 }
2948
2949 impl core::ops::$trait<ExactNum> for ExactNum {
2950 type Output = ExactNum;
2951
2952 fn $method(self, rhs: ExactNum) -> ExactNum {
2953 ExactNum::$op(&self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2954 }
2955 }
2956 };
2957}
2958
2959impl_exact_binop!(Add, add, add);
2960impl_exact_binop!(Sub, sub, sub);
2961impl_exact_binop!(Mul, mul, mul);
2962impl_exact_binop!(Div, div, div);
2963
2964pub trait FromExt<T> {
2966 fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self;
2968}
2969
2970impl<T> FromExt<T> for ExactNum
2971where
2972 ExactNum: From<T>,
2973{
2974 fn from_ext(v: T, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
2975 let mut ret = ExactNum::from(v);
2976 if let Err(err) = ret.set_precision(p, rm) {
2977 ExactNum::nan(Some(err))
2978 } else {
2979 ret
2980 }
2981 }
2982}
2983
2984impl FromExt<&str> for ExactNum {
2985 fn from_ext(v: &str, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2986 ExactNum::parse(v, crate::Radix::Dec, p, rm, cc)
2987 }
2988}
2989
2990#[cfg(test)]
2991mod tests {
2992
2993 use crate::common::util::rand_p;
2994 use crate::defs::DEFAULT_P;
2995 use crate::ext::ONE;
2996 use crate::ext::TWO;
2997 use crate::Consts;
2998 use crate::Error;
2999 use crate::ExactNum;
3000 use crate::Radix;
3001 use crate::Sign;
3002 use crate::Word;
3003 use crate::INF_NEG;
3004 use crate::INF_POS;
3005 use crate::NAN;
3006 use crate::{defs::RoundingMode, WORD_BIT_SIZE};
3007
3008 use core::num::FpCategory;
3009 #[cfg(feature = "std")]
3010 use std::str::FromStr;
3011
3012 #[cfg(not(feature = "std"))]
3013 use alloc::format;
3014
3015 #[cfg(target_pointer_width = "32")]
3016 #[test]
3017 fn test_decimal_formatting_round_trip() {
3018 let mut cc = Consts::new().unwrap();
3021 let p = 53;
3022 let rm = RoundingMode::ToEven;
3023 let value = ExactNum::parse("1.0", Radix::Dec, p, rm, &mut cc);
3024
3025 let formatted = value.format(Radix::Dec, rm, &mut cc).unwrap();
3026 assert_eq!(formatted, "1.e+0");
3027
3028 let reparsed = ExactNum::parse(&formatted, Radix::Dec, p, rm, &mut cc);
3029 assert_eq!(reparsed, value);
3030 }
3031
3032 #[test]
3033 fn test_ext() {
3034 let rm = RoundingMode::ToOdd;
3035 let mut cc = Consts::new().unwrap();
3036
3037 let d1 = ExactNum::from_u8(1, rand_p());
3039 assert!(!d1.is_inf());
3040 assert!(!d1.is_nan());
3041 assert!(!d1.is_inf_pos());
3042 assert!(!d1.is_inf_neg());
3043 assert!(d1.is_positive());
3044
3045 let mut d1 = d1.div(&ExactNum::new(rand_p()), rand_p(), rm);
3046 assert!(d1.is_inf());
3047 assert!(!d1.is_nan());
3048 assert!(d1.is_inf_pos());
3049 assert!(!d1.is_inf_neg());
3050 assert!(d1.is_positive());
3051
3052 d1.inv_sign();
3053 assert!(d1.is_inf());
3054 assert!(!d1.is_nan());
3055 assert!(!d1.is_inf_pos());
3056 assert!(d1.is_inf_neg());
3057 assert!(d1.is_negative());
3058
3059 let d1 = ExactNum::new(rand_p()).div(&ExactNum::new(rand_p()), rand_p(), rm);
3060 assert!(!d1.is_inf());
3061 assert!(d1.is_nan());
3062 assert!(!d1.is_inf_pos());
3063 assert!(!d1.is_inf_neg());
3064 assert!(d1.sign().is_none());
3065
3066 for _ in 0..1000 {
3067 let i = crate::common::test_rng::random::<i64>();
3068 let d1 = ExactNum::from_i64(i, rand_p());
3069 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3070 assert!(d1.cmp(&n1) == Some(0));
3071
3072 let i = crate::common::test_rng::random::<u64>();
3073 let d1 = ExactNum::from_u64(i, rand_p());
3074 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3075 assert!(d1.cmp(&n1) == Some(0));
3076
3077 let i = crate::common::test_rng::random::<i128>();
3078 let d1 = ExactNum::from_i128(i, rand_p());
3079 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3080 assert!(d1.cmp(&n1) == Some(0));
3081
3082 let i = crate::common::test_rng::random::<u128>();
3083 let d1 = ExactNum::from_u128(i, rand_p());
3084 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3085 assert!(d1.cmp(&n1) == Some(0));
3086 }
3087
3088 assert!(ONE.exponent().is_some());
3089 assert!(INF_POS.exponent().is_none());
3090 assert!(INF_NEG.exponent().is_none());
3091 assert!(NAN.exponent().is_none());
3092
3093 assert!(ONE.as_raw_parts().is_some());
3094 assert!(INF_POS.as_raw_parts().is_none());
3095 assert!(INF_NEG.as_raw_parts().is_none());
3096 assert!(NAN.as_raw_parts().is_none());
3097
3098 assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3099 assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
3100 assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
3101 assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3102 assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
3103 assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
3104 assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
3105 assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3106 assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
3107
3108 assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
3109 assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
3110 assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
3111 assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
3112 assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
3113 assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
3114 assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
3115 assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
3116 assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
3117
3118 assert!(ONE.sub_full_prec(&ONE).is_zero());
3119 assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
3120 assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
3121 assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
3122 assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
3123 assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
3124 assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
3125 assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
3126 assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
3127
3128 assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
3129 assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
3130 assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
3131 assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
3132 assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
3133 assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
3134 assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
3135 assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
3136 assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
3137
3138 assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
3139 assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3140 assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
3141 assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3142 assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
3143 assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
3144 assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3145 assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
3146 assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3147
3148 assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3149 assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3150 assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
3151 assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3152 assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
3153 assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
3154 assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3155 assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
3156 assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
3157 assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3158 assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3159 assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3160 assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
3161 assert!(INF_POS.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3162 assert!(INF_NEG.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3163 assert!(ExactNum::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
3164 assert!(ExactNum::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
3165
3166 assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
3167 assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
3168 assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
3169 assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
3170 assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
3171 assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
3172 assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
3173 assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
3174 assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
3175 assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
3176 assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
3177 assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
3178 assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
3179 assert!(INF_POS
3180 .div(&ExactNum::new(rand_p()), rand_p(), rm)
3181 .is_inf_pos());
3182 assert!(INF_NEG
3183 .div(&ExactNum::new(rand_p()), rand_p(), rm)
3184 .is_inf_neg());
3185 assert!(ExactNum::new(rand_p())
3186 .div(&INF_POS, rand_p(), rm)
3187 .is_zero());
3188 assert!(ExactNum::new(rand_p())
3189 .div(&INF_NEG, rand_p(), rm)
3190 .is_zero());
3191
3192 assert!(TWO.rem(&TWO).is_zero());
3193 assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
3194 assert!(INF_POS.rem(&TWO).is_nan());
3195 assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
3196 assert!(INF_NEG.rem(&TWO).is_nan());
3197 assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
3198 assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
3199 assert!(INF_POS.rem(&TWO.neg()).is_nan());
3200 assert!(INF_NEG.rem(&TWO.neg()).is_nan());
3201 assert!(INF_POS.rem(&INF_POS).is_nan());
3202 assert!(INF_POS.rem(&INF_NEG).is_nan());
3203 assert!(INF_NEG.rem(&INF_NEG).is_nan());
3204 assert!(INF_NEG.rem(&INF_POS).is_nan());
3205 assert!(INF_POS.rem(&ExactNum::new(rand_p())).is_nan());
3206 assert!(INF_NEG.rem(&ExactNum::new(rand_p())).is_nan());
3207 assert!(ExactNum::new(rand_p()).rem(&INF_POS).is_zero());
3208 assert!(ExactNum::new(rand_p()).rem(&INF_NEG).is_zero());
3209
3210 for op in [ExactNum::add, ExactNum::sub, ExactNum::mul, ExactNum::div] {
3211 assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
3212 assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
3213 assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
3214 assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
3215 assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
3216 assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
3217 assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
3218 }
3219
3220 assert!(ExactNum::rem(&NAN, &ONE).is_nan());
3221 assert!(ExactNum::rem(&ONE, &NAN).is_nan());
3222 assert!(ExactNum::rem(&NAN, &INF_POS).is_nan());
3223 assert!(ExactNum::rem(&INF_POS, &NAN).is_nan());
3224 assert!(ExactNum::rem(&NAN, &INF_NEG).is_nan());
3225 assert!(ExactNum::rem(&INF_NEG, &NAN).is_nan());
3226 assert!(ExactNum::rem(&NAN, &NAN).is_nan());
3227
3228 for op in [ExactNum::add_full_prec, ExactNum::sub_full_prec, ExactNum::mul_full_prec] {
3229 assert!(op(&NAN, &ONE).is_nan());
3230 assert!(op(&ONE, &NAN).is_nan());
3231 assert!(op(&NAN, &INF_POS).is_nan());
3232 assert!(op(&INF_POS, &NAN).is_nan());
3233 assert!(op(&NAN, &INF_NEG).is_nan());
3234 assert!(op(&INF_NEG, &NAN).is_nan());
3235 assert!(op(&NAN, &NAN).is_nan());
3236 }
3237
3238 assert!(ONE.cmp(&ONE).unwrap() == 0);
3239 assert!(ONE.cmp(&INF_POS).unwrap() < 0);
3240 assert!(INF_POS.cmp(&ONE).unwrap() > 0);
3241 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3242 assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
3243 assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
3244 assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
3245 assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
3246 assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
3247 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3248 assert!(ONE.cmp(&NAN).is_none());
3249 assert!(NAN.cmp(&ONE).is_none());
3250 assert!(INF_POS.cmp(&NAN).is_none());
3251 assert!(NAN.cmp(&INF_POS).is_none());
3252 assert!(INF_NEG.cmp(&NAN).is_none());
3253 assert!(NAN.cmp(&INF_NEG).is_none());
3254 assert!(NAN.cmp(&NAN).is_none());
3255
3256 assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
3257 assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
3258 assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
3259 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3260 assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
3261 assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
3262 assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
3263 assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
3264 assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
3265 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3266 assert!(ONE.abs_cmp(&NAN).is_none());
3267 assert!(NAN.abs_cmp(&ONE).is_none());
3268 assert!(INF_POS.abs_cmp(&NAN).is_none());
3269 assert!(NAN.abs_cmp(&INF_POS).is_none());
3270 assert!(INF_NEG.abs_cmp(&NAN).is_none());
3271 assert!(NAN.abs_cmp(&INF_NEG).is_none());
3272 assert!(NAN.abs_cmp(&NAN).is_none());
3273
3274 assert!(ONE.is_positive());
3275 assert!(!ONE.is_negative());
3276
3277 assert!(ONE.neg().is_negative());
3278 assert!(!ONE.neg().is_positive());
3279 assert!(!INF_POS.is_negative());
3280 assert!(INF_POS.is_positive());
3281 assert!(INF_NEG.is_negative());
3282 assert!(!INF_NEG.is_positive());
3283 assert!(!NAN.is_positive());
3284 assert!(!NAN.is_negative());
3285
3286 assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3287 assert!(ExactNum::new(DEFAULT_P)
3288 .pow(&INF_POS, rand_p(), rm, &mut cc)
3289 .is_zero());
3290 assert!(ExactNum::new(DEFAULT_P)
3291 .pow(&INF_NEG, rand_p(), rm, &mut cc)
3292 .is_zero());
3293 assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3294 assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3295 assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3296 assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
3297 assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3298 assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
3299 assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3300 assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3301 assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3302 assert!(
3303 INF_POS
3304 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3305 .cmp(&ONE)
3306 == Some(0)
3307 );
3308 assert!(
3309 INF_NEG
3310 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3311 .cmp(&ONE)
3312 == Some(0)
3313 );
3314 assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3315 assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3316 assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3317 assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3318
3319 let half = ONE.div(&TWO, rand_p(), rm);
3320 assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3321 assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3322 assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3323 assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3324 assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3325 assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3326 assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3327 assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3328 assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
3329 assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
3330 assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3331 assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3332 assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3333 assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3334 assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3335 assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3336 assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
3337
3338 assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3339 assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
3340 assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3341 assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3342 assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3343 assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3344 assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3345
3346 assert!(NAN.powi(2, rand_p(), rm).is_nan());
3347 assert!(NAN.powi(0, rand_p(), rm).is_nan());
3348 assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
3349 assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
3350 assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
3351 assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
3352 assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3353 assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3354
3355 assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3356 assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3357 assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3358 assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3359 assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3360 assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3361 assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3362
3363 assert!(INF_NEG.abs().is_inf_pos());
3364 assert!(INF_POS.abs().is_inf_pos());
3365 assert!(NAN.abs().is_nan());
3366
3367 assert!(INF_NEG.int().is_nan());
3368 assert!(INF_POS.int().is_nan());
3369 assert!(NAN.int().is_nan());
3370
3371 assert!(INF_NEG.fract().is_nan());
3372 assert!(INF_POS.fract().is_nan());
3373 assert!(NAN.fract().is_nan());
3374
3375 assert!(INF_NEG.ceil().is_inf_neg());
3376 assert!(INF_POS.ceil().is_inf_pos());
3377 assert!(NAN.ceil().is_nan());
3378
3379 assert!(INF_NEG.floor().is_inf_neg());
3380 assert!(INF_POS.floor().is_inf_pos());
3381 assert!(NAN.floor().is_nan());
3382
3383 for rm in [
3384 RoundingMode::Up,
3385 RoundingMode::Down,
3386 RoundingMode::ToZero,
3387 RoundingMode::FromZero,
3388 RoundingMode::ToEven,
3389 RoundingMode::ToOdd,
3390 ] {
3391 assert!(INF_NEG.round(0, rm).is_inf_neg());
3392 assert!(INF_POS.round(0, rm).is_inf_pos());
3393 assert!(NAN.round(0, rm).is_nan());
3394 }
3395
3396 assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
3397 assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
3398 assert!(NAN.sqrt(rand_p(), rm).is_nan());
3399
3400 assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
3401 assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
3402 assert!(NAN.cbrt(rand_p(), rm).is_nan());
3403
3404 for op in [ExactNum::ln, ExactNum::log2, ExactNum::log10] {
3405 assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3406 assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3407 assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
3408 }
3409
3410 assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
3411 assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
3412 assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
3413
3414 assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
3415 assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
3416 assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
3417
3418 assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
3419 assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
3420 assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
3421
3422 assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
3423 assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
3424 assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
3425
3426 assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
3427 assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
3428 assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
3429
3430 assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
3431 assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
3432 assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
3433
3434 let p = rand_p();
3435 let mut half_pi: ExactNum = cc.pi_num(p, rm).unwrap().into();
3436 half_pi.set_exponent(1);
3437 assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
3438 assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
3439 assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
3440
3441 assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
3442 assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
3443 assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
3444
3445 assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3446 assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3447 assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
3448
3449 assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
3450 assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3451 assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
3452
3453 assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
3454 assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
3455 assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
3456
3457 assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
3458 assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
3459 assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
3460
3461 assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
3462 assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
3463 assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
3464
3465 assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
3466 assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
3467 assert!(NAN.reciprocal(rand_p(), rm).is_nan());
3468
3469 assert!(TWO.signum().cmp(&ONE) == Some(0));
3470 assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
3471 assert!(INF_POS.signum().cmp(&ONE) == Some(0));
3472 assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
3473 assert!(NAN.signum().is_nan());
3474
3475 let d1 = ONE.clone();
3476 assert!(d1.exponent() == Some(1));
3477 let words: &[Word] = {
3478 #[cfg(not(target_pointer_width = "32"))]
3479 {
3480 &[0, 0x8000000000000000]
3481 }
3482 #[cfg(target_pointer_width = "32")]
3483 {
3484 &[0, 0, 0, 0x80000000]
3485 }
3486 };
3487
3488 assert!(d1.mantissa_digits() == Some(words));
3489 assert!(d1.is_inline());
3490 assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
3491 assert!(d1.precision() == Some(DEFAULT_P));
3492 assert!(d1.sign() == Some(Sign::Pos));
3493
3494 assert!(INF_POS.exponent().is_none());
3495 assert!(INF_POS.mantissa_digits().is_none());
3496 assert!(INF_POS.mantissa_max_bit_len().is_none());
3497 assert!(INF_POS.precision().is_none());
3498 assert!(INF_POS.sign() == Some(Sign::Pos));
3499
3500 assert!(INF_NEG.exponent().is_none());
3501 assert!(INF_NEG.mantissa_digits().is_none());
3502 assert!(INF_NEG.mantissa_max_bit_len().is_none());
3503 assert!(INF_NEG.precision().is_none());
3504 assert!(INF_NEG.sign() == Some(Sign::Neg));
3505
3506 assert!(NAN.exponent().is_none());
3507 assert!(NAN.mantissa_digits().is_none());
3508 assert!(NAN.mantissa_max_bit_len().is_none());
3509 assert!(NAN.precision().is_none());
3510 assert!(NAN.sign().is_none());
3511
3512 INF_POS.clone().set_exponent(1);
3513 INF_POS.clone().set_precision(1, rm).unwrap();
3514 INF_POS.clone().set_sign(Sign::Pos);
3515
3516 INF_NEG.clone().set_exponent(1);
3517 INF_NEG.clone().set_precision(1, rm).unwrap();
3518 INF_NEG.clone().set_sign(Sign::Pos);
3519
3520 NAN.clone().set_exponent(1);
3521 NAN.clone().set_precision(1, rm).unwrap();
3522 NAN.clone().set_sign(Sign::Pos);
3523
3524 assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
3525 assert!(INF_NEG.min(&ONE).is_inf_neg());
3526 assert!(NAN.min(&ONE).is_nan());
3527 assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
3528 assert!(ONE.min(&INF_NEG).is_inf_neg());
3529 assert!(ONE.min(&NAN).is_nan());
3530 assert!(NAN.min(&INF_POS).is_nan());
3531 assert!(NAN.min(&INF_NEG).is_nan());
3532 assert!(NAN.min(&NAN).is_nan());
3533 assert!(INF_NEG.min(&INF_POS).is_inf_neg());
3534 assert!(INF_POS.min(&INF_NEG).is_inf_neg());
3535 assert!(INF_POS.min(&INF_POS).is_inf_pos());
3536 assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
3537
3538 assert!(INF_POS.max(&ONE).is_inf_pos());
3539 assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
3540 assert!(NAN.max(&ONE).is_nan());
3541 assert!(ONE.max(&INF_POS).is_inf_pos());
3542 assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
3543 assert!(ONE.max(&NAN).is_nan());
3544 assert!(NAN.max(&INF_POS).is_nan());
3545 assert!(NAN.max(&INF_NEG).is_nan());
3546 assert!(NAN.max(&NAN).is_nan());
3547 assert!(INF_NEG.max(&INF_POS).is_inf_pos());
3548 assert!(INF_POS.max(&INF_NEG).is_inf_pos());
3549 assert!(INF_POS.max(&INF_POS).is_inf_pos());
3550 assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
3551
3552 assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
3553 assert!(ONE.clamp(&TWO, &ONE).is_nan());
3554 assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
3555 assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
3556 assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3557 assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
3558 assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
3559 assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
3560 assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
3561 assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
3562 assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
3563 assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
3564 assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3565 assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
3566 assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
3567 assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
3568 assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
3569 assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
3570 assert!(NAN.clamp(&ONE, &TWO).is_nan());
3571 assert!(NAN.clamp(&NAN, &TWO).is_nan());
3572 assert!(NAN.clamp(&ONE, &NAN).is_nan());
3573 assert!(NAN.clamp(&NAN, &NAN).is_nan());
3574 assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
3575
3576 assert!(ExactNum::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
3577 assert!(INF_POS.classify() == FpCategory::Infinite);
3578 assert!(INF_NEG.classify() == FpCategory::Infinite);
3579 assert!(NAN.classify() == FpCategory::Nan);
3580 assert!(ONE.classify() == FpCategory::Normal);
3581
3582 assert!(!INF_POS.is_subnormal());
3583 assert!(!INF_NEG.is_subnormal());
3584 assert!(!NAN.is_subnormal());
3585 assert!(ExactNum::min_positive(DEFAULT_P).is_subnormal());
3586 assert!(!ExactNum::min_positive_normal(DEFAULT_P).is_subnormal());
3587 assert!(!ExactNum::max_value(DEFAULT_P).is_subnormal());
3588 assert!(!ExactNum::min_value(DEFAULT_P).is_subnormal());
3589
3590 let n1 = ExactNum::convert_from_radix(
3591 Sign::Pos,
3592 &[],
3593 0,
3594 Radix::Dec,
3595 usize::MAX - 1,
3596 RoundingMode::None,
3597 &mut cc,
3598 );
3599 assert!(n1.is_nan());
3600 assert!(n1.err() == Some(Error::InvalidArgument));
3601
3602 assert!(
3603 n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3604 == Err(Error::InvalidArgument)
3605 );
3606 assert!(
3607 INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3608 == Err(Error::InvalidArgument)
3609 );
3610 assert!(
3611 INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3612 == Err(Error::InvalidArgument)
3613 );
3614 }
3615
3616 #[cfg(feature = "std")]
3617 #[test]
3618 fn test_ops_std() {
3619 let mut cc = Consts::new().unwrap();
3620
3621 let d1 = ExactNum::parse(
3622 "0.0123456789012345678901234567890123456789",
3623 Radix::Dec,
3624 DEFAULT_P,
3625 RoundingMode::None,
3626 &mut cc,
3627 );
3628
3629 let d1str = format!("{}", d1);
3630 assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
3631 assert_eq!(format!("{:e}", d1), d1str);
3632 assert_eq!(
3633 format!("{:E}", d1),
3634 "1.23456789012345678901234567890123456789E-2"
3635 );
3636 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3637 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3638 assert_eq!(d2, d1);
3639
3640 let d1 = ExactNum::parse(
3641 "-123.456789012345678901234567890123456789",
3642 Radix::Dec,
3643 DEFAULT_P,
3644 RoundingMode::None,
3645 &mut cc,
3646 );
3647 let d1str = format!("{}", d1);
3648 assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
3649 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3650 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3651 assert_eq!(d2, d1);
3652
3653 let d1str = format!("{}", INF_POS);
3654 assert_eq!(d1str, "Inf");
3655
3656 let d1str = format!("{}", INF_NEG);
3657 assert_eq!(d1str, "-Inf");
3658
3659 let d1str = format!("{}", NAN);
3660 assert_eq!(d1str, "NaN");
3661
3662 assert!(ExactNum::from_str("abc").is_ok());
3663 assert!(ExactNum::from_str("abc").unwrap().is_nan());
3664 }
3665
3666 #[test]
3667 pub fn test_ops() {
3668 let mut cc = Consts::new().unwrap();
3669
3670 let d1 = -&(TWO.clone());
3671 assert!(d1.is_negative());
3672
3673 let p = DEFAULT_P;
3674 let rm = RoundingMode::ToEven;
3675 let two = ExactNum::from_u8(2, p);
3676 let eighth = two.powsi(-3, p, rm);
3677 let expected = ExactNum::from_u8(1, p).div(&ExactNum::from_u8(8, p), p, rm);
3678 assert_eq!(eighth.cmp(&expected), Some(0));
3679 assert_eq!(two.powsi(3, p, rm).cmp(&ExactNum::from_u8(8, p)), Some(0));
3680 assert!(
3681 ExactNum::from_i8(-123, p) == ExactNum::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
3682 );
3683 assert!(
3684 ExactNum::from_u8(123, p) == ExactNum::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
3685 );
3686 assert!(
3687 ExactNum::from_i16(-12312, p)
3688 == ExactNum::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
3689 );
3690 assert!(
3691 ExactNum::from_u16(12312, p)
3692 == ExactNum::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
3693 );
3694 assert!(
3695 ExactNum::from_i32(-123456789, p)
3696 == ExactNum::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3697 );
3698 assert!(
3699 ExactNum::from_u32(123456789, p)
3700 == ExactNum::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3701 );
3702 assert!(
3703 ExactNum::from_i64(-1234567890123456789, p)
3704 == ExactNum::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3705 );
3706 assert!(
3707 ExactNum::from_u64(1234567890123456789, p)
3708 == ExactNum::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3709 );
3710 assert!(
3711 ExactNum::from_i128(-123456789012345678901234567890123456789, p)
3712 == ExactNum::parse(
3713 "-1.23456789012345678901234567890123456789e+38",
3714 Radix::Dec,
3715 p,
3716 rm,
3717 &mut cc
3718 )
3719 );
3720 assert!(
3721 ExactNum::from_u128(123456789012345678901234567890123456789, p)
3722 == ExactNum::parse(
3723 "1.23456789012345678901234567890123456789e+38",
3724 Radix::Dec,
3725 p,
3726 rm,
3727 &mut cc
3728 )
3729 );
3730
3731 let neg = ExactNum::from_i8(-3, WORD_BIT_SIZE);
3732 let pos = ExactNum::from_i8(5, WORD_BIT_SIZE);
3733
3734 assert!(pos > neg);
3735 assert!(neg < pos);
3736 assert!(!(pos < neg));
3737 assert!(!(neg > pos));
3738 assert!(INF_NEG < neg);
3739 assert!(INF_NEG < pos);
3740 assert!(INF_NEG < INF_POS);
3741 assert!(!(INF_NEG > neg));
3742 assert!(!(INF_NEG > pos));
3743 assert!(!(INF_NEG > INF_POS));
3744 assert!(INF_POS > neg);
3745 assert!(INF_POS > pos);
3746 assert!(INF_POS > INF_NEG);
3747 assert!(!(INF_POS < neg));
3748 assert!(!(INF_POS < pos));
3749 assert!(!(INF_POS < INF_NEG));
3750 assert!(!(INF_POS > INF_POS));
3751 assert!(!(INF_POS < INF_POS));
3752 assert!(!(INF_NEG > INF_NEG));
3753 assert!(!(INF_NEG < INF_NEG));
3754 assert!(!(INF_POS > NAN));
3755 assert!(!(INF_POS < NAN));
3756 assert!(!(INF_NEG > NAN));
3757 assert!(!(INF_NEG < NAN));
3758 assert!(!(NAN > INF_POS));
3759 assert!(!(NAN < INF_POS));
3760 assert!(!(NAN > INF_NEG));
3761 assert!(!(NAN < INF_NEG));
3762 assert!(!(NAN > NAN));
3763 assert!(!(NAN < NAN));
3764 assert!(!(neg > NAN));
3765 assert!(!(neg < NAN));
3766 assert!(!(pos > NAN));
3767 assert!(!(pos < NAN));
3768 assert!(!(NAN > neg));
3769 assert!(!(NAN < neg));
3770 assert!(!(NAN > pos));
3771 assert!(!(NAN < pos));
3772
3773 assert!(!(NAN == NAN));
3774 assert!(!(NAN == INF_POS));
3775 assert!(!(NAN == INF_NEG));
3776 assert!(!(INF_POS == NAN));
3777 assert!(!(INF_NEG == NAN));
3778 assert!(!(INF_NEG == INF_POS));
3779 assert!(!(INF_POS == INF_NEG));
3780 assert!(!(INF_POS == neg));
3781 assert!(!(INF_POS == pos));
3782 assert!(!(INF_NEG == neg));
3783 assert!(!(INF_NEG == pos));
3784 assert!(!(neg == INF_POS));
3785 assert!(!(pos == INF_POS));
3786 assert!(!(neg == INF_NEG));
3787 assert!(!(pos == INF_NEG));
3788 assert!(!(pos == neg));
3789 assert!(!(neg == pos));
3790 assert!(neg == neg);
3791 assert!(pos == pos);
3792 assert!(INF_NEG == INF_NEG);
3793 assert!(INF_POS == INF_POS);
3794 }
3795
3796 #[test]
3797 fn test_oom_and_large_precision() {
3798 let oom = ExactNum::nan(Some(Error::MemoryAllocation));
3799 assert!(oom.is_nan());
3800 assert_eq!(oom.err(), Some(Error::MemoryAllocation));
3801
3802 let n = ExactNum::new(usize::MAX);
3803 assert!(n.is_nan());
3804 assert_eq!(n.err(), Some(Error::InvalidArgument));
3805
3806 let p = 128 * WORD_BIT_SIZE;
3807 let a = ExactNum::from_word(3, p);
3808 let b = ExactNum::from_word(5, p);
3809 let s = a.add(&b, p, RoundingMode::ToEven);
3810 let m = a.mul(&b, p, RoundingMode::ToEven);
3811 assert!(!s.is_nan(), "large-prec add hung or failed");
3812 assert!(!m.is_nan(), "large-prec mul hung or failed");
3813 assert_eq!(s.cmp(&ExactNum::from_word(8, p)), Some(0));
3814 }
3815
3816 #[test]
3817 fn test_two_sum_fused_polyval() {
3818 let p = 128;
3819 let rm = RoundingMode::ToEven;
3820 let one = ExactNum::from_u8(1, p);
3821 let two = ExactNum::from_u8(2, p);
3822 let three = ExactNum::from_u8(3, p);
3823
3824 let (hi, lo) = one.two_sum(&two, p, rm);
3825 let rec = hi.add(&lo, p, rm);
3826 assert_eq!(rec.cmp(&ExactNum::from_u8(3, p)), Some(0));
3827
3828 let (ph, pl) = two.two_product(&three, p, rm);
3829 let pr = ph.add(&pl, p, rm);
3830 assert_eq!(pr.cmp(&ExactNum::from_u8(6, p)), Some(0));
3831
3832 let sum = ExactNum::fused_sum(&[one.clone(), two.clone(), three.clone()], p, rm);
3833 assert_eq!(sum.cmp(&ExactNum::from_u8(6, p)), Some(0));
3834
3835 let dot = ExactNum::fused_dot(
3836 &[one.clone(), two.clone()],
3837 &[three.clone(), one.clone()],
3838 p,
3839 rm,
3840 );
3841 assert_eq!(dot.cmp(&ExactNum::from_u8(5, p)), Some(0));
3842
3843 let pv = ExactNum::polyval(&[one, two, three], &ExactNum::from_u8(2, p), p, rm);
3845 assert_eq!(pv.cmp(&ExactNum::from_u8(17, p)), Some(0));
3846 }
3847
3848 #[test]
3849 fn test_jacobi_sn_public() {
3850 let p = 256;
3851 let rm = RoundingMode::ToEven;
3852 let mut cc = Consts::new().unwrap();
3853 let one = ExactNum::from_u8(1, p);
3854 let zero = ExactNum::from_u8(0, p);
3855 let half = one.div(&ExactNum::from_u8(2, p), p, rm);
3856 let sn0 = zero.jacobi_sn(&half, p, rm, &mut cc);
3857 assert!(sn0.is_zero(), "sn(0)");
3858 let cn0 = zero.jacobi_cn(&half, p, rm, &mut cc);
3859 assert_eq!(cn0.cmp(&one), Some(0), "cn(0)");
3860 let sn_m0 = one.jacobi_sn(&zero, p, rm, &mut cc);
3861 let sin1 = one.sin(p, rm, &mut cc);
3862 let d = sn_m0.sub(&sin1, p, rm).abs();
3863 assert!(
3864 d.is_zero() || d.exponent().unwrap() < -80,
3865 "sn(1|0)=sin 1"
3866 );
3867 assert!(one
3868 .jacobi_sn(&ExactNum::from_i8(2, p), p, rm, &mut cc)
3869 .is_nan());
3870 }
3871}
3872
3873#[cfg(feature = "random")]
3874#[cfg(test)]
3875mod rand_tests {
3876
3877 use super::*;
3878 use crate::common::util::TEST_EXP_BOUND;
3879
3880 #[test]
3881 fn test_rand() {
3882 for _ in 0..100 {
3883 let p = crate::common::test_rng::random::<usize>() % 192 + DEFAULT_P;
3884 let exp_from = crate::common::test_rng::random::<Exponent>().abs() % TEST_EXP_BOUND;
3885 let span = (TEST_EXP_BOUND - exp_from).max(1);
3886 let exp_shift = crate::common::test_rng::random::<Exponent>().abs() % span;
3887 let exp_to = exp_from + exp_shift;
3888
3889 let n = ExactNum::random_normal(p, exp_from, exp_to);
3890
3891 assert!(!n.is_subnormal());
3892 assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
3893 assert!(n.precision().unwrap() >= p);
3894 }
3895 }
3896}