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 legendre_p(&self, n: u32, p: usize, rm: RoundingMode) -> Self {
2398 match &self.inner {
2399 Flavor::Value(v) => Self::result_to_ext(v.legendre_p(n, p, rm), false, true),
2400 Flavor::Inf(_) => NAN,
2401 Flavor::NaN(err) => Self::nan(*err),
2402 }
2403 }
2404 pub fn assoc_legendre_p(&self, n: u32, m: i32, p: usize, rm: RoundingMode) -> Self {
2412 match &self.inner {
2413 Flavor::Value(v) => Self::result_to_ext(v.assoc_legendre_p(n, m, p, rm), false, true),
2414 Flavor::Inf(_) => NAN,
2415 Flavor::NaN(err) => Self::nan(*err),
2416 }
2417 }
2418 pub fn hypergeom_2f1(
2426 &self,
2427 b: &Self,
2428 c: &Self,
2429 z: &Self,
2430 p: usize,
2431 rm: RoundingMode,
2432 cc: &mut Consts,
2433 ) -> Self {
2434 match (&self.inner, &b.inner, &c.inner, &z.inner) {
2435 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv), Flavor::Value(zv)) => {
2436 Self::result_to_ext(a.hypergeom_2f1(bv, cv, zv, p, rm, cc), zv.is_zero(), true)
2437 }
2438 (Flavor::NaN(err), _, _, _)
2439 | (_, Flavor::NaN(err), _, _)
2440 | (_, _, Flavor::NaN(err), _)
2441 | (_, _, _, Flavor::NaN(err)) => Self::nan(*err),
2442 _ => NAN,
2443 }
2444 }
2445 pub fn betainc(&self, b: &Self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2453 match (&self.inner, &b.inner, &x.inner) {
2454 (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(xv)) => {
2455 Self::result_to_ext(a.betainc(bv, xv, p, rm, cc), xv.is_zero(), true)
2456 }
2457 (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2458 Self::nan(*err)
2459 }
2460 _ => NAN,
2461 }
2462 }
2463 gen_wrapper_arg_rm_cc!(
2464 "Computes the hyperbolic arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2465 This function requires constants cache `cc` for computing the result.
2466 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2467 asinh,
2468 Self,
2469 { INF_POS },
2470 { INF_NEG },
2471 p,
2472 usize
2473 );
2474 gen_wrapper_arg_rm_cc!(
2475 "Computes the hyperbolic arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2476 This function requires constants cache `cc` for computing the result.
2477 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2478 acosh,
2479 Self,
2480 { INF_POS },
2481 { NAN },
2482 p,
2483 usize
2484 );
2485 gen_wrapper_arg_rm_cc!(
2486 "Computes the hyperbolic arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2487 This function requires constants cache `cc` for computing the result.
2488 Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2489 atanh,
2490 Self,
2491 { NAN },
2492 { NAN },
2493 p,
2494 usize
2495 );
2496}
2497
2498macro_rules! impl_int_conv {
2499 ($s:ty, $from_s:ident) => {
2500 impl ExactNum {
2501 pub fn $from_s(i: $s, p: usize) -> Self {
2505 Self::result_to_ext(ExactNumNumber::$from_s(i, p), false, true)
2506 }
2507 }
2508 };
2509}
2510
2511impl_int_conv!(i8, from_i8);
2512impl_int_conv!(i16, from_i16);
2513impl_int_conv!(i32, from_i32);
2514impl_int_conv!(i64, from_i64);
2515impl_int_conv!(i128, from_i128);
2516
2517impl_int_conv!(u8, from_u8);
2518impl_int_conv!(u16, from_u16);
2519impl_int_conv!(u32, from_u32);
2520impl_int_conv!(u64, from_u64);
2521impl_int_conv!(u128, from_u128);
2522
2523impl From<ExactNumNumber> for ExactNum {
2524 fn from(x: ExactNumNumber) -> Self {
2525 ExactNum {
2526 inner: Flavor::Value(x),
2527 }
2528 }
2529}
2530
2531#[cfg(feature = "std")]
2532use core::{
2533 fmt::{Binary, Display, Formatter, Octal, UpperHex},
2534 str::FromStr,
2535};
2536
2537use core::{cmp::Eq, cmp::Ordering, cmp::PartialEq, cmp::PartialOrd, ops::Neg};
2538
2539impl Neg for ExactNum {
2540 type Output = ExactNum;
2541 fn neg(mut self) -> Self::Output {
2542 self.inv_sign();
2543 self
2544 }
2545}
2546
2547impl Neg for &ExactNum {
2548 type Output = ExactNum;
2549 fn neg(self) -> Self::Output {
2550 let mut ret = self.clone();
2551 ret.inv_sign();
2552 ret
2553 }
2554}
2555
2556impl PartialEq for ExactNum {
2561 fn eq(&self, other: &Self) -> bool {
2562 let cmp_result = ExactNum::cmp(self, other);
2563 matches!(cmp_result, Some(0))
2564 }
2565}
2566
2567impl<'a> PartialEq<&'a ExactNum> for ExactNum {
2568 fn eq(&self, other: &&'a ExactNum) -> bool {
2569 let cmp_result = ExactNum::cmp(self, other);
2570 matches!(cmp_result, Some(0))
2571 }
2572}
2573
2574impl Eq for ExactNum {}
2575
2576impl PartialOrd for ExactNum {
2577 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2578 let cmp_result = ExactNum::cmp(self, other);
2579 match cmp_result {
2580 Some(v) => {
2581 if v > 0 {
2582 Some(Ordering::Greater)
2583 } else if v < 0 {
2584 Some(Ordering::Less)
2585 } else {
2586 Some(Ordering::Equal)
2587 }
2588 }
2589 None => None,
2590 }
2591 }
2592}
2593
2594impl<'a> PartialOrd<&'a ExactNum> for ExactNum {
2595 fn partial_cmp(&self, other: &&'a ExactNum) -> Option<Ordering> {
2596 let cmp_result = ExactNum::cmp(self, other);
2597 match cmp_result {
2598 Some(v) => {
2599 if v > 0 {
2600 Some(Ordering::Greater)
2601 } else if v < 0 {
2602 Some(Ordering::Less)
2603 } else {
2604 Some(Ordering::Equal)
2605 }
2606 }
2607 None => None,
2608 }
2609 }
2610}
2611
2612impl Default for ExactNum {
2613 fn default() -> ExactNum {
2614 ExactNum::new(DEFAULT_P)
2615 }
2616}
2617
2618#[cfg(feature = "std")]
2619impl FromStr for ExactNum {
2620 type Err = Error;
2621
2622 fn from_str(src: &str) -> Result<ExactNum, Self::Err> {
2625 let bf = crate::common::consts::TENPOWERS.with(|tp| {
2626 let cc = &mut tp.borrow_mut();
2627 ExactNum::parse(src, Radix::Dec, usize::MAX, RoundingMode::ToEven, cc)
2628 });
2629
2630 if bf.is_nan() {
2631 if let Some(err) = bf.err() {
2632 return Err(err);
2633 }
2634 }
2635
2636 Ok(bf)
2637 }
2638}
2639
2640macro_rules! impl_from {
2641 ($tt:ty, $fn:ident) => {
2642 impl From<$tt> for ExactNum {
2643 fn from(v: $tt) -> Self {
2644 ExactNum::$fn(v, DEFAULT_P)
2645 }
2646 }
2647 };
2648}
2649
2650impl_from!(i8, from_i8);
2651impl_from!(i16, from_i16);
2652impl_from!(i32, from_i32);
2653impl_from!(i64, from_i64);
2654impl_from!(i128, from_i128);
2655impl_from!(u8, from_u8);
2656impl_from!(u16, from_u16);
2657impl_from!(u32, from_u32);
2658impl_from!(u64, from_u64);
2659impl_from!(u128, from_u128);
2660
2661#[cfg(feature = "std")]
2662macro_rules! impl_format_rdx {
2663 ($trait:ty, $rdx:path) => {
2664 impl $trait for ExactNum {
2665 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
2668 crate::common::consts::TENPOWERS.with(|tp| {
2669 let cc = &mut tp.borrow_mut();
2670 self.write_str(f, $rdx, RoundingMode::ToEven, cc)
2671 })
2672 }
2673 }
2674 };
2675}
2676
2677#[cfg(feature = "std")]
2678impl_format_rdx!(Binary, Radix::Bin);
2679#[cfg(feature = "std")]
2680impl_format_rdx!(Octal, Radix::Oct);
2681#[cfg(feature = "std")]
2682impl_format_rdx!(Display, Radix::Dec);
2683#[cfg(feature = "std")]
2684impl_format_rdx!(core::fmt::LowerExp, Radix::Dec);
2685#[cfg(feature = "std")]
2686impl_format_rdx!(UpperHex, Radix::Hex);
2687#[cfg(feature = "std")]
2688impl core::fmt::UpperExp for ExactNum {
2689 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2690 crate::common::consts::TENPOWERS.with(|tp| {
2691 let cc = &mut tp.borrow_mut();
2692 let mut s = String::new();
2693 self.write_str(&mut s, Radix::Dec, RoundingMode::ToEven, cc)?;
2694 f.write_str(&s.replace('e', "E"))
2695 })
2696 }
2697}
2698#[cfg(feature = "std")]
2699impl core::fmt::LowerHex for ExactNum {
2700 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2701 crate::common::consts::TENPOWERS.with(|tp| {
2702 let cc = &mut tp.borrow_mut();
2703 let mut s = String::new();
2704 self.write_str(&mut s, Radix::Hex, RoundingMode::ToEven, cc)?;
2705 if matches!(s.as_str(), "Inf" | "-Inf" | "NaN" | "Err") {
2706 f.write_str(&s)
2707 } else {
2708 f.write_str(&s.to_ascii_lowercase())
2709 }
2710 })
2711 }
2712}
2713
2714macro_rules! impl_exact_binop {
2715 ($trait:ident, $method:ident, $op:ident) => {
2716 impl core::ops::$trait<&ExactNum> for &ExactNum {
2717 type Output = ExactNum;
2718
2719 fn $method(self, rhs: &ExactNum) -> ExactNum {
2720 ExactNum::$op(self, rhs, DEFAULT_P, RoundingMode::ToEven)
2721 }
2722 }
2723
2724 impl core::ops::$trait<ExactNum> for &ExactNum {
2725 type Output = ExactNum;
2726
2727 fn $method(self, rhs: ExactNum) -> ExactNum {
2728 ExactNum::$op(self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2729 }
2730 }
2731
2732 impl core::ops::$trait<&ExactNum> for ExactNum {
2733 type Output = ExactNum;
2734
2735 fn $method(self, rhs: &ExactNum) -> ExactNum {
2736 ExactNum::$op(&self, rhs, DEFAULT_P, RoundingMode::ToEven)
2737 }
2738 }
2739
2740 impl core::ops::$trait<ExactNum> for ExactNum {
2741 type Output = ExactNum;
2742
2743 fn $method(self, rhs: ExactNum) -> ExactNum {
2744 ExactNum::$op(&self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2745 }
2746 }
2747 };
2748}
2749
2750impl_exact_binop!(Add, add, add);
2751impl_exact_binop!(Sub, sub, sub);
2752impl_exact_binop!(Mul, mul, mul);
2753impl_exact_binop!(Div, div, div);
2754
2755pub trait FromExt<T> {
2757 fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self;
2759}
2760
2761impl<T> FromExt<T> for ExactNum
2762where
2763 ExactNum: From<T>,
2764{
2765 fn from_ext(v: T, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
2766 let mut ret = ExactNum::from(v);
2767 if let Err(err) = ret.set_precision(p, rm) {
2768 ExactNum::nan(Some(err))
2769 } else {
2770 ret
2771 }
2772 }
2773}
2774
2775impl FromExt<&str> for ExactNum {
2776 fn from_ext(v: &str, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2777 ExactNum::parse(v, crate::Radix::Dec, p, rm, cc)
2778 }
2779}
2780
2781#[cfg(test)]
2782mod tests {
2783
2784 use crate::common::util::rand_p;
2785 use crate::defs::DEFAULT_P;
2786 use crate::ext::ONE;
2787 use crate::ext::TWO;
2788 use crate::Consts;
2789 use crate::Error;
2790 use crate::ExactNum;
2791 use crate::Radix;
2792 use crate::Sign;
2793 use crate::Word;
2794 use crate::INF_NEG;
2795 use crate::INF_POS;
2796 use crate::NAN;
2797 use crate::{defs::RoundingMode, WORD_BIT_SIZE};
2798
2799 use core::num::FpCategory;
2800 #[cfg(feature = "std")]
2801 use std::str::FromStr;
2802
2803 #[cfg(not(feature = "std"))]
2804 use alloc::format;
2805
2806 #[cfg(target_pointer_width = "32")]
2807 #[test]
2808 fn test_decimal_formatting_round_trip() {
2809 let mut cc = Consts::new().unwrap();
2812 let p = 53;
2813 let rm = RoundingMode::ToEven;
2814 let value = ExactNum::parse("1.0", Radix::Dec, p, rm, &mut cc);
2815
2816 let formatted = value.format(Radix::Dec, rm, &mut cc).unwrap();
2817 assert_eq!(formatted, "1.e+0");
2818
2819 let reparsed = ExactNum::parse(&formatted, Radix::Dec, p, rm, &mut cc);
2820 assert_eq!(reparsed, value);
2821 }
2822
2823 #[test]
2824 fn test_ext() {
2825 let rm = RoundingMode::ToOdd;
2826 let mut cc = Consts::new().unwrap();
2827
2828 let d1 = ExactNum::from_u8(1, rand_p());
2830 assert!(!d1.is_inf());
2831 assert!(!d1.is_nan());
2832 assert!(!d1.is_inf_pos());
2833 assert!(!d1.is_inf_neg());
2834 assert!(d1.is_positive());
2835
2836 let mut d1 = d1.div(&ExactNum::new(rand_p()), rand_p(), rm);
2837 assert!(d1.is_inf());
2838 assert!(!d1.is_nan());
2839 assert!(d1.is_inf_pos());
2840 assert!(!d1.is_inf_neg());
2841 assert!(d1.is_positive());
2842
2843 d1.inv_sign();
2844 assert!(d1.is_inf());
2845 assert!(!d1.is_nan());
2846 assert!(!d1.is_inf_pos());
2847 assert!(d1.is_inf_neg());
2848 assert!(d1.is_negative());
2849
2850 let d1 = ExactNum::new(rand_p()).div(&ExactNum::new(rand_p()), rand_p(), rm);
2851 assert!(!d1.is_inf());
2852 assert!(d1.is_nan());
2853 assert!(!d1.is_inf_pos());
2854 assert!(!d1.is_inf_neg());
2855 assert!(d1.sign().is_none());
2856
2857 for _ in 0..1000 {
2858 let i = crate::common::test_rng::random::<i64>();
2859 let d1 = ExactNum::from_i64(i, rand_p());
2860 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
2861 assert!(d1.cmp(&n1) == Some(0));
2862
2863 let i = crate::common::test_rng::random::<u64>();
2864 let d1 = ExactNum::from_u64(i, rand_p());
2865 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
2866 assert!(d1.cmp(&n1) == Some(0));
2867
2868 let i = crate::common::test_rng::random::<i128>();
2869 let d1 = ExactNum::from_i128(i, rand_p());
2870 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
2871 assert!(d1.cmp(&n1) == Some(0));
2872
2873 let i = crate::common::test_rng::random::<u128>();
2874 let d1 = ExactNum::from_u128(i, rand_p());
2875 let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
2876 assert!(d1.cmp(&n1) == Some(0));
2877 }
2878
2879 assert!(ONE.exponent().is_some());
2880 assert!(INF_POS.exponent().is_none());
2881 assert!(INF_NEG.exponent().is_none());
2882 assert!(NAN.exponent().is_none());
2883
2884 assert!(ONE.as_raw_parts().is_some());
2885 assert!(INF_POS.as_raw_parts().is_none());
2886 assert!(INF_NEG.as_raw_parts().is_none());
2887 assert!(NAN.as_raw_parts().is_none());
2888
2889 assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
2890 assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
2891 assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
2892 assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
2893 assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
2894 assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
2895 assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
2896 assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
2897 assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
2898
2899 assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
2900 assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
2901 assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
2902 assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
2903 assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
2904 assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
2905 assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
2906 assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
2907 assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
2908
2909 assert!(ONE.sub_full_prec(&ONE).is_zero());
2910 assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
2911 assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
2912 assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
2913 assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
2914 assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
2915 assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
2916 assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
2917 assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
2918
2919 assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
2920 assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
2921 assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
2922 assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
2923 assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
2924 assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
2925 assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
2926 assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
2927 assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
2928
2929 assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
2930 assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
2931 assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
2932 assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
2933 assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
2934 assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
2935 assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
2936 assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
2937 assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
2938
2939 assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
2940 assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
2941 assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
2942 assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
2943 assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
2944 assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
2945 assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
2946 assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
2947 assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
2948 assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
2949 assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
2950 assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
2951 assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
2952 assert!(INF_POS.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
2953 assert!(INF_NEG.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
2954 assert!(ExactNum::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
2955 assert!(ExactNum::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
2956
2957 assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
2958 assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
2959 assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
2960 assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
2961 assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
2962 assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
2963 assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
2964 assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
2965 assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
2966 assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
2967 assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
2968 assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
2969 assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
2970 assert!(INF_POS
2971 .div(&ExactNum::new(rand_p()), rand_p(), rm)
2972 .is_inf_pos());
2973 assert!(INF_NEG
2974 .div(&ExactNum::new(rand_p()), rand_p(), rm)
2975 .is_inf_neg());
2976 assert!(ExactNum::new(rand_p())
2977 .div(&INF_POS, rand_p(), rm)
2978 .is_zero());
2979 assert!(ExactNum::new(rand_p())
2980 .div(&INF_NEG, rand_p(), rm)
2981 .is_zero());
2982
2983 assert!(TWO.rem(&TWO).is_zero());
2984 assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
2985 assert!(INF_POS.rem(&TWO).is_nan());
2986 assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
2987 assert!(INF_NEG.rem(&TWO).is_nan());
2988 assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
2989 assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
2990 assert!(INF_POS.rem(&TWO.neg()).is_nan());
2991 assert!(INF_NEG.rem(&TWO.neg()).is_nan());
2992 assert!(INF_POS.rem(&INF_POS).is_nan());
2993 assert!(INF_POS.rem(&INF_NEG).is_nan());
2994 assert!(INF_NEG.rem(&INF_NEG).is_nan());
2995 assert!(INF_NEG.rem(&INF_POS).is_nan());
2996 assert!(INF_POS.rem(&ExactNum::new(rand_p())).is_nan());
2997 assert!(INF_NEG.rem(&ExactNum::new(rand_p())).is_nan());
2998 assert!(ExactNum::new(rand_p()).rem(&INF_POS).is_zero());
2999 assert!(ExactNum::new(rand_p()).rem(&INF_NEG).is_zero());
3000
3001 for op in [ExactNum::add, ExactNum::sub, ExactNum::mul, ExactNum::div] {
3002 assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
3003 assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
3004 assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
3005 assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
3006 assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
3007 assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
3008 assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
3009 }
3010
3011 assert!(ExactNum::rem(&NAN, &ONE).is_nan());
3012 assert!(ExactNum::rem(&ONE, &NAN).is_nan());
3013 assert!(ExactNum::rem(&NAN, &INF_POS).is_nan());
3014 assert!(ExactNum::rem(&INF_POS, &NAN).is_nan());
3015 assert!(ExactNum::rem(&NAN, &INF_NEG).is_nan());
3016 assert!(ExactNum::rem(&INF_NEG, &NAN).is_nan());
3017 assert!(ExactNum::rem(&NAN, &NAN).is_nan());
3018
3019 for op in [ExactNum::add_full_prec, ExactNum::sub_full_prec, ExactNum::mul_full_prec] {
3020 assert!(op(&NAN, &ONE).is_nan());
3021 assert!(op(&ONE, &NAN).is_nan());
3022 assert!(op(&NAN, &INF_POS).is_nan());
3023 assert!(op(&INF_POS, &NAN).is_nan());
3024 assert!(op(&NAN, &INF_NEG).is_nan());
3025 assert!(op(&INF_NEG, &NAN).is_nan());
3026 assert!(op(&NAN, &NAN).is_nan());
3027 }
3028
3029 assert!(ONE.cmp(&ONE).unwrap() == 0);
3030 assert!(ONE.cmp(&INF_POS).unwrap() < 0);
3031 assert!(INF_POS.cmp(&ONE).unwrap() > 0);
3032 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3033 assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
3034 assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
3035 assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
3036 assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
3037 assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
3038 assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3039 assert!(ONE.cmp(&NAN).is_none());
3040 assert!(NAN.cmp(&ONE).is_none());
3041 assert!(INF_POS.cmp(&NAN).is_none());
3042 assert!(NAN.cmp(&INF_POS).is_none());
3043 assert!(INF_NEG.cmp(&NAN).is_none());
3044 assert!(NAN.cmp(&INF_NEG).is_none());
3045 assert!(NAN.cmp(&NAN).is_none());
3046
3047 assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
3048 assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
3049 assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
3050 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3051 assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
3052 assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
3053 assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
3054 assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
3055 assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
3056 assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3057 assert!(ONE.abs_cmp(&NAN).is_none());
3058 assert!(NAN.abs_cmp(&ONE).is_none());
3059 assert!(INF_POS.abs_cmp(&NAN).is_none());
3060 assert!(NAN.abs_cmp(&INF_POS).is_none());
3061 assert!(INF_NEG.abs_cmp(&NAN).is_none());
3062 assert!(NAN.abs_cmp(&INF_NEG).is_none());
3063 assert!(NAN.abs_cmp(&NAN).is_none());
3064
3065 assert!(ONE.is_positive());
3066 assert!(!ONE.is_negative());
3067
3068 assert!(ONE.neg().is_negative());
3069 assert!(!ONE.neg().is_positive());
3070 assert!(!INF_POS.is_negative());
3071 assert!(INF_POS.is_positive());
3072 assert!(INF_NEG.is_negative());
3073 assert!(!INF_NEG.is_positive());
3074 assert!(!NAN.is_positive());
3075 assert!(!NAN.is_negative());
3076
3077 assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3078 assert!(ExactNum::new(DEFAULT_P)
3079 .pow(&INF_POS, rand_p(), rm, &mut cc)
3080 .is_zero());
3081 assert!(ExactNum::new(DEFAULT_P)
3082 .pow(&INF_NEG, rand_p(), rm, &mut cc)
3083 .is_zero());
3084 assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3085 assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3086 assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3087 assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
3088 assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3089 assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
3090 assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3091 assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3092 assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3093 assert!(
3094 INF_POS
3095 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3096 .cmp(&ONE)
3097 == Some(0)
3098 );
3099 assert!(
3100 INF_NEG
3101 .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3102 .cmp(&ONE)
3103 == Some(0)
3104 );
3105 assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3106 assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3107 assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3108 assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3109
3110 let half = ONE.div(&TWO, rand_p(), rm);
3111 assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3112 assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3113 assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3114 assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3115 assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3116 assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3117 assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3118 assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3119 assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
3120 assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
3121 assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3122 assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3123 assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3124 assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3125 assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3126 assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3127 assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
3128
3129 assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3130 assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
3131 assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3132 assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3133 assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3134 assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3135 assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3136
3137 assert!(NAN.powi(2, rand_p(), rm).is_nan());
3138 assert!(NAN.powi(0, rand_p(), rm).is_nan());
3139 assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
3140 assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
3141 assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
3142 assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
3143 assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3144 assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3145
3146 assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3147 assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3148 assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3149 assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3150 assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3151 assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3152 assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3153
3154 assert!(INF_NEG.abs().is_inf_pos());
3155 assert!(INF_POS.abs().is_inf_pos());
3156 assert!(NAN.abs().is_nan());
3157
3158 assert!(INF_NEG.int().is_nan());
3159 assert!(INF_POS.int().is_nan());
3160 assert!(NAN.int().is_nan());
3161
3162 assert!(INF_NEG.fract().is_nan());
3163 assert!(INF_POS.fract().is_nan());
3164 assert!(NAN.fract().is_nan());
3165
3166 assert!(INF_NEG.ceil().is_inf_neg());
3167 assert!(INF_POS.ceil().is_inf_pos());
3168 assert!(NAN.ceil().is_nan());
3169
3170 assert!(INF_NEG.floor().is_inf_neg());
3171 assert!(INF_POS.floor().is_inf_pos());
3172 assert!(NAN.floor().is_nan());
3173
3174 for rm in [
3175 RoundingMode::Up,
3176 RoundingMode::Down,
3177 RoundingMode::ToZero,
3178 RoundingMode::FromZero,
3179 RoundingMode::ToEven,
3180 RoundingMode::ToOdd,
3181 ] {
3182 assert!(INF_NEG.round(0, rm).is_inf_neg());
3183 assert!(INF_POS.round(0, rm).is_inf_pos());
3184 assert!(NAN.round(0, rm).is_nan());
3185 }
3186
3187 assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
3188 assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
3189 assert!(NAN.sqrt(rand_p(), rm).is_nan());
3190
3191 assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
3192 assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
3193 assert!(NAN.cbrt(rand_p(), rm).is_nan());
3194
3195 for op in [ExactNum::ln, ExactNum::log2, ExactNum::log10] {
3196 assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3197 assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3198 assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
3199 }
3200
3201 assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
3202 assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
3203 assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
3204
3205 assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
3206 assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
3207 assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
3208
3209 assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
3210 assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
3211 assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
3212
3213 assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
3214 assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
3215 assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
3216
3217 assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
3218 assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
3219 assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
3220
3221 assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
3222 assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
3223 assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
3224
3225 let p = rand_p();
3226 let mut half_pi: ExactNum = cc.pi_num(p, rm).unwrap().into();
3227 half_pi.set_exponent(1);
3228 assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
3229 assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
3230 assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
3231
3232 assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
3233 assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
3234 assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
3235
3236 assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3237 assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3238 assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
3239
3240 assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
3241 assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3242 assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
3243
3244 assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
3245 assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
3246 assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
3247
3248 assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
3249 assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
3250 assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
3251
3252 assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
3253 assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
3254 assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
3255
3256 assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
3257 assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
3258 assert!(NAN.reciprocal(rand_p(), rm).is_nan());
3259
3260 assert!(TWO.signum().cmp(&ONE) == Some(0));
3261 assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
3262 assert!(INF_POS.signum().cmp(&ONE) == Some(0));
3263 assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
3264 assert!(NAN.signum().is_nan());
3265
3266 let d1 = ONE.clone();
3267 assert!(d1.exponent() == Some(1));
3268 let words: &[Word] = {
3269 #[cfg(not(target_pointer_width = "32"))]
3270 {
3271 &[0, 0x8000000000000000]
3272 }
3273 #[cfg(target_pointer_width = "32")]
3274 {
3275 &[0, 0, 0, 0x80000000]
3276 }
3277 };
3278
3279 assert!(d1.mantissa_digits() == Some(words));
3280 assert!(d1.is_inline());
3281 assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
3282 assert!(d1.precision() == Some(DEFAULT_P));
3283 assert!(d1.sign() == Some(Sign::Pos));
3284
3285 assert!(INF_POS.exponent().is_none());
3286 assert!(INF_POS.mantissa_digits().is_none());
3287 assert!(INF_POS.mantissa_max_bit_len().is_none());
3288 assert!(INF_POS.precision().is_none());
3289 assert!(INF_POS.sign() == Some(Sign::Pos));
3290
3291 assert!(INF_NEG.exponent().is_none());
3292 assert!(INF_NEG.mantissa_digits().is_none());
3293 assert!(INF_NEG.mantissa_max_bit_len().is_none());
3294 assert!(INF_NEG.precision().is_none());
3295 assert!(INF_NEG.sign() == Some(Sign::Neg));
3296
3297 assert!(NAN.exponent().is_none());
3298 assert!(NAN.mantissa_digits().is_none());
3299 assert!(NAN.mantissa_max_bit_len().is_none());
3300 assert!(NAN.precision().is_none());
3301 assert!(NAN.sign().is_none());
3302
3303 INF_POS.clone().set_exponent(1);
3304 INF_POS.clone().set_precision(1, rm).unwrap();
3305 INF_POS.clone().set_sign(Sign::Pos);
3306
3307 INF_NEG.clone().set_exponent(1);
3308 INF_NEG.clone().set_precision(1, rm).unwrap();
3309 INF_NEG.clone().set_sign(Sign::Pos);
3310
3311 NAN.clone().set_exponent(1);
3312 NAN.clone().set_precision(1, rm).unwrap();
3313 NAN.clone().set_sign(Sign::Pos);
3314
3315 assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
3316 assert!(INF_NEG.min(&ONE).is_inf_neg());
3317 assert!(NAN.min(&ONE).is_nan());
3318 assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
3319 assert!(ONE.min(&INF_NEG).is_inf_neg());
3320 assert!(ONE.min(&NAN).is_nan());
3321 assert!(NAN.min(&INF_POS).is_nan());
3322 assert!(NAN.min(&INF_NEG).is_nan());
3323 assert!(NAN.min(&NAN).is_nan());
3324 assert!(INF_NEG.min(&INF_POS).is_inf_neg());
3325 assert!(INF_POS.min(&INF_NEG).is_inf_neg());
3326 assert!(INF_POS.min(&INF_POS).is_inf_pos());
3327 assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
3328
3329 assert!(INF_POS.max(&ONE).is_inf_pos());
3330 assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
3331 assert!(NAN.max(&ONE).is_nan());
3332 assert!(ONE.max(&INF_POS).is_inf_pos());
3333 assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
3334 assert!(ONE.max(&NAN).is_nan());
3335 assert!(NAN.max(&INF_POS).is_nan());
3336 assert!(NAN.max(&INF_NEG).is_nan());
3337 assert!(NAN.max(&NAN).is_nan());
3338 assert!(INF_NEG.max(&INF_POS).is_inf_pos());
3339 assert!(INF_POS.max(&INF_NEG).is_inf_pos());
3340 assert!(INF_POS.max(&INF_POS).is_inf_pos());
3341 assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
3342
3343 assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
3344 assert!(ONE.clamp(&TWO, &ONE).is_nan());
3345 assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
3346 assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
3347 assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3348 assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
3349 assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
3350 assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
3351 assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
3352 assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
3353 assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
3354 assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
3355 assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3356 assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
3357 assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
3358 assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
3359 assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
3360 assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
3361 assert!(NAN.clamp(&ONE, &TWO).is_nan());
3362 assert!(NAN.clamp(&NAN, &TWO).is_nan());
3363 assert!(NAN.clamp(&ONE, &NAN).is_nan());
3364 assert!(NAN.clamp(&NAN, &NAN).is_nan());
3365 assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
3366
3367 assert!(ExactNum::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
3368 assert!(INF_POS.classify() == FpCategory::Infinite);
3369 assert!(INF_NEG.classify() == FpCategory::Infinite);
3370 assert!(NAN.classify() == FpCategory::Nan);
3371 assert!(ONE.classify() == FpCategory::Normal);
3372
3373 assert!(!INF_POS.is_subnormal());
3374 assert!(!INF_NEG.is_subnormal());
3375 assert!(!NAN.is_subnormal());
3376 assert!(ExactNum::min_positive(DEFAULT_P).is_subnormal());
3377 assert!(!ExactNum::min_positive_normal(DEFAULT_P).is_subnormal());
3378 assert!(!ExactNum::max_value(DEFAULT_P).is_subnormal());
3379 assert!(!ExactNum::min_value(DEFAULT_P).is_subnormal());
3380
3381 let n1 = ExactNum::convert_from_radix(
3382 Sign::Pos,
3383 &[],
3384 0,
3385 Radix::Dec,
3386 usize::MAX - 1,
3387 RoundingMode::None,
3388 &mut cc,
3389 );
3390 assert!(n1.is_nan());
3391 assert!(n1.err() == Some(Error::InvalidArgument));
3392
3393 assert!(
3394 n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3395 == Err(Error::InvalidArgument)
3396 );
3397 assert!(
3398 INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3399 == Err(Error::InvalidArgument)
3400 );
3401 assert!(
3402 INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3403 == Err(Error::InvalidArgument)
3404 );
3405 }
3406
3407 #[cfg(feature = "std")]
3408 #[test]
3409 fn test_ops_std() {
3410 let mut cc = Consts::new().unwrap();
3411
3412 let d1 = ExactNum::parse(
3413 "0.0123456789012345678901234567890123456789",
3414 Radix::Dec,
3415 DEFAULT_P,
3416 RoundingMode::None,
3417 &mut cc,
3418 );
3419
3420 let d1str = format!("{}", d1);
3421 assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
3422 assert_eq!(format!("{:e}", d1), d1str);
3423 assert_eq!(
3424 format!("{:E}", d1),
3425 "1.23456789012345678901234567890123456789E-2"
3426 );
3427 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3428 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3429 assert_eq!(d2, d1);
3430
3431 let d1 = ExactNum::parse(
3432 "-123.456789012345678901234567890123456789",
3433 Radix::Dec,
3434 DEFAULT_P,
3435 RoundingMode::None,
3436 &mut cc,
3437 );
3438 let d1str = format!("{}", d1);
3439 assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
3440 let mut d2 = ExactNum::from_str(&d1str).unwrap();
3441 d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3442 assert_eq!(d2, d1);
3443
3444 let d1str = format!("{}", INF_POS);
3445 assert_eq!(d1str, "Inf");
3446
3447 let d1str = format!("{}", INF_NEG);
3448 assert_eq!(d1str, "-Inf");
3449
3450 let d1str = format!("{}", NAN);
3451 assert_eq!(d1str, "NaN");
3452
3453 assert!(ExactNum::from_str("abc").is_ok());
3454 assert!(ExactNum::from_str("abc").unwrap().is_nan());
3455 }
3456
3457 #[test]
3458 pub fn test_ops() {
3459 let mut cc = Consts::new().unwrap();
3460
3461 let d1 = -&(TWO.clone());
3462 assert!(d1.is_negative());
3463
3464 let p = DEFAULT_P;
3465 let rm = RoundingMode::ToEven;
3466 let two = ExactNum::from_u8(2, p);
3467 let eighth = two.powsi(-3, p, rm);
3468 let expected = ExactNum::from_u8(1, p).div(&ExactNum::from_u8(8, p), p, rm);
3469 assert_eq!(eighth.cmp(&expected), Some(0));
3470 assert_eq!(two.powsi(3, p, rm).cmp(&ExactNum::from_u8(8, p)), Some(0));
3471 assert!(
3472 ExactNum::from_i8(-123, p) == ExactNum::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
3473 );
3474 assert!(
3475 ExactNum::from_u8(123, p) == ExactNum::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
3476 );
3477 assert!(
3478 ExactNum::from_i16(-12312, p)
3479 == ExactNum::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
3480 );
3481 assert!(
3482 ExactNum::from_u16(12312, p)
3483 == ExactNum::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
3484 );
3485 assert!(
3486 ExactNum::from_i32(-123456789, p)
3487 == ExactNum::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3488 );
3489 assert!(
3490 ExactNum::from_u32(123456789, p)
3491 == ExactNum::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3492 );
3493 assert!(
3494 ExactNum::from_i64(-1234567890123456789, p)
3495 == ExactNum::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3496 );
3497 assert!(
3498 ExactNum::from_u64(1234567890123456789, p)
3499 == ExactNum::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3500 );
3501 assert!(
3502 ExactNum::from_i128(-123456789012345678901234567890123456789, p)
3503 == ExactNum::parse(
3504 "-1.23456789012345678901234567890123456789e+38",
3505 Radix::Dec,
3506 p,
3507 rm,
3508 &mut cc
3509 )
3510 );
3511 assert!(
3512 ExactNum::from_u128(123456789012345678901234567890123456789, p)
3513 == ExactNum::parse(
3514 "1.23456789012345678901234567890123456789e+38",
3515 Radix::Dec,
3516 p,
3517 rm,
3518 &mut cc
3519 )
3520 );
3521
3522 let neg = ExactNum::from_i8(-3, WORD_BIT_SIZE);
3523 let pos = ExactNum::from_i8(5, WORD_BIT_SIZE);
3524
3525 assert!(pos > neg);
3526 assert!(neg < pos);
3527 assert!(!(pos < neg));
3528 assert!(!(neg > pos));
3529 assert!(INF_NEG < neg);
3530 assert!(INF_NEG < pos);
3531 assert!(INF_NEG < INF_POS);
3532 assert!(!(INF_NEG > neg));
3533 assert!(!(INF_NEG > pos));
3534 assert!(!(INF_NEG > INF_POS));
3535 assert!(INF_POS > neg);
3536 assert!(INF_POS > pos);
3537 assert!(INF_POS > INF_NEG);
3538 assert!(!(INF_POS < neg));
3539 assert!(!(INF_POS < pos));
3540 assert!(!(INF_POS < INF_NEG));
3541 assert!(!(INF_POS > INF_POS));
3542 assert!(!(INF_POS < INF_POS));
3543 assert!(!(INF_NEG > INF_NEG));
3544 assert!(!(INF_NEG < INF_NEG));
3545 assert!(!(INF_POS > NAN));
3546 assert!(!(INF_POS < NAN));
3547 assert!(!(INF_NEG > NAN));
3548 assert!(!(INF_NEG < NAN));
3549 assert!(!(NAN > INF_POS));
3550 assert!(!(NAN < INF_POS));
3551 assert!(!(NAN > INF_NEG));
3552 assert!(!(NAN < INF_NEG));
3553 assert!(!(NAN > NAN));
3554 assert!(!(NAN < NAN));
3555 assert!(!(neg > NAN));
3556 assert!(!(neg < NAN));
3557 assert!(!(pos > NAN));
3558 assert!(!(pos < NAN));
3559 assert!(!(NAN > neg));
3560 assert!(!(NAN < neg));
3561 assert!(!(NAN > pos));
3562 assert!(!(NAN < pos));
3563
3564 assert!(!(NAN == NAN));
3565 assert!(!(NAN == INF_POS));
3566 assert!(!(NAN == INF_NEG));
3567 assert!(!(INF_POS == NAN));
3568 assert!(!(INF_NEG == NAN));
3569 assert!(!(INF_NEG == INF_POS));
3570 assert!(!(INF_POS == INF_NEG));
3571 assert!(!(INF_POS == neg));
3572 assert!(!(INF_POS == pos));
3573 assert!(!(INF_NEG == neg));
3574 assert!(!(INF_NEG == pos));
3575 assert!(!(neg == INF_POS));
3576 assert!(!(pos == INF_POS));
3577 assert!(!(neg == INF_NEG));
3578 assert!(!(pos == INF_NEG));
3579 assert!(!(pos == neg));
3580 assert!(!(neg == pos));
3581 assert!(neg == neg);
3582 assert!(pos == pos);
3583 assert!(INF_NEG == INF_NEG);
3584 assert!(INF_POS == INF_POS);
3585 }
3586
3587 #[test]
3588 fn test_oom_and_large_precision() {
3589 let oom = ExactNum::nan(Some(Error::MemoryAllocation));
3590 assert!(oom.is_nan());
3591 assert_eq!(oom.err(), Some(Error::MemoryAllocation));
3592
3593 let n = ExactNum::new(usize::MAX);
3594 assert!(n.is_nan());
3595 assert_eq!(n.err(), Some(Error::InvalidArgument));
3596
3597 let p = 128 * WORD_BIT_SIZE;
3598 let a = ExactNum::from_word(3, p);
3599 let b = ExactNum::from_word(5, p);
3600 let s = a.add(&b, p, RoundingMode::ToEven);
3601 let m = a.mul(&b, p, RoundingMode::ToEven);
3602 assert!(!s.is_nan(), "large-prec add hung or failed");
3603 assert!(!m.is_nan(), "large-prec mul hung or failed");
3604 assert_eq!(s.cmp(&ExactNum::from_word(8, p)), Some(0));
3605 }
3606
3607 #[test]
3608 fn test_two_sum_fused_polyval() {
3609 let p = 128;
3610 let rm = RoundingMode::ToEven;
3611 let one = ExactNum::from_u8(1, p);
3612 let two = ExactNum::from_u8(2, p);
3613 let three = ExactNum::from_u8(3, p);
3614
3615 let (hi, lo) = one.two_sum(&two, p, rm);
3616 let rec = hi.add(&lo, p, rm);
3617 assert_eq!(rec.cmp(&ExactNum::from_u8(3, p)), Some(0));
3618
3619 let (ph, pl) = two.two_product(&three, p, rm);
3620 let pr = ph.add(&pl, p, rm);
3621 assert_eq!(pr.cmp(&ExactNum::from_u8(6, p)), Some(0));
3622
3623 let sum = ExactNum::fused_sum(&[one.clone(), two.clone(), three.clone()], p, rm);
3624 assert_eq!(sum.cmp(&ExactNum::from_u8(6, p)), Some(0));
3625
3626 let dot = ExactNum::fused_dot(
3627 &[one.clone(), two.clone()],
3628 &[three.clone(), one.clone()],
3629 p,
3630 rm,
3631 );
3632 assert_eq!(dot.cmp(&ExactNum::from_u8(5, p)), Some(0));
3633
3634 let pv = ExactNum::polyval(&[one, two, three], &ExactNum::from_u8(2, p), p, rm);
3636 assert_eq!(pv.cmp(&ExactNum::from_u8(17, p)), Some(0));
3637 }
3638}
3639
3640#[cfg(feature = "random")]
3641#[cfg(test)]
3642mod rand_tests {
3643
3644 use super::*;
3645 use crate::common::util::TEST_EXP_BOUND;
3646
3647 #[test]
3648 fn test_rand() {
3649 for _ in 0..100 {
3650 let p = crate::common::test_rng::random::<usize>() % 192 + DEFAULT_P;
3651 let exp_from = crate::common::test_rng::random::<Exponent>().abs() % TEST_EXP_BOUND;
3652 let span = (TEST_EXP_BOUND - exp_from).max(1);
3653 let exp_shift = crate::common::test_rng::random::<Exponent>().abs() % span;
3654 let exp_to = exp_from + exp_shift;
3655
3656 let n = ExactNum::random_normal(p, exp_from, exp_to);
3657
3658 assert!(!n.is_subnormal());
3659 assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
3660 assert!(n.precision().unwrap() >= p);
3661 }
3662 }
3663}