1use crate::defs::DEFAULT_P;
4use crate::Consts;
5use crate::ExactNum;
6use crate::Exponent;
7use crate::RoundingMode;
8use crate::WORD_BIT_SIZE;
9
10#[derive(Debug, Clone)]
12pub struct ExactComplex {
13 re: ExactNum,
14 im: ExactNum,
15}
16
17impl ExactComplex {
18 pub fn new(re: ExactNum, im: ExactNum) -> Self {
20 Self { re, im }
21 }
22
23 pub fn re(&self) -> &ExactNum {
25 &self.re
26 }
27
28 pub fn im(&self) -> &ExactNum {
30 &self.im
31 }
32
33 pub fn zero(p: usize) -> Self {
35 Self::new(ExactNum::new(p), ExactNum::new(p))
36 }
37
38 pub fn one(p: usize) -> Self {
40 Self::new(ExactNum::from_u8(1, p), ExactNum::new(p))
41 }
42
43 pub fn i(p: usize) -> Self {
45 Self::new(ExactNum::new(p), ExactNum::from_u8(1, p))
46 }
47
48 pub fn inexact(&self) -> bool {
50 self.re.inexact() || self.im.inexact()
51 }
52
53 pub fn set_inexact(&mut self, inexact: bool) {
55 self.re.set_inexact(inexact);
56 self.im.set_inexact(inexact);
57 }
58
59 pub fn set_precision(&mut self, p: usize, rm: RoundingMode) -> Result<(), crate::Error> {
61 self.re.set_precision(p, rm)?;
62 self.im.set_precision(p, rm)
63 }
64
65 pub fn from_real(re: ExactNum, p: usize) -> Self {
67 Self::new(re, ExactNum::new(p))
68 }
69
70 pub fn reciprocal(&self, p: usize, rm: RoundingMode) -> Self {
72 Self::one(p).div(self, p, rm)
73 }
74
75 pub fn is_nan(&self) -> bool {
77 self.re.is_nan() || self.im.is_nan()
78 }
79
80 pub fn conj(&self) -> Self {
82 Self::new(self.re.clone(), self.im.neg())
83 }
84
85 pub fn abs(&self, p: usize, rm: RoundingMode) -> ExactNum {
87 self.re.hypot(&self.im, p, rm)
88 }
89
90 pub fn arg(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> ExactNum {
95 self.im.atan2(&self.re, p, rm, cc)
96 }
97
98 pub fn add(&self, rhs: &Self, p: usize, rm: RoundingMode) -> Self {
100 Self::new(self.re.add(&rhs.re, p, rm), self.im.add(&rhs.im, p, rm))
101 }
102
103 pub fn sub(&self, rhs: &Self, p: usize, rm: RoundingMode) -> Self {
105 Self::new(self.re.sub(&rhs.re, p, rm), self.im.sub(&rhs.im, p, rm))
106 }
107
108 pub fn mul(&self, rhs: &Self, p: usize, rm: RoundingMode) -> Self {
114 let ac = self.re.mul(&rhs.re, p, rm);
115 let bd = self.im.mul(&rhs.im, p, rm);
116 let ad = self.re.mul(&rhs.im, p, rm);
117 let bc = self.im.mul(&rhs.re, p, rm);
118 Self::new(ac.sub(&bd, p, rm), ad.add(&bc, p, rm))
119 }
120
121 pub fn div(&self, rhs: &Self, p: usize, rm: RoundingMode) -> Self {
123 let ac = self.re.mul(&rhs.re, p, RoundingMode::None);
124 let bd = self.im.mul(&rhs.im, p, RoundingMode::None);
125 let bc = self.im.mul(&rhs.re, p, RoundingMode::None);
126 let ad = self.re.mul(&rhs.im, p, RoundingMode::None);
127 let den = rhs.re.mul(&rhs.re, p, RoundingMode::None).add(
128 &rhs.im.mul(&rhs.im, p, RoundingMode::None),
129 p,
130 RoundingMode::None,
131 );
132 Self::new(
133 ac.add(&bd, p, rm).div(&den, p, rm),
134 bc.sub(&ad, p, rm).div(&den, p, rm),
135 )
136 }
137
138 pub fn exp(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
140 let er = self.re.exp(p, RoundingMode::None, cc);
141 let (s, c) = self.im.sin_cos(p, RoundingMode::None, cc);
142 Self::new(er.mul(&c, p, rm), er.mul(&s, p, rm))
143 }
144
145 pub fn ln(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
149 let mag = self.abs(p, RoundingMode::None);
150 Self::new(mag.ln(p, rm, cc), self.arg(p, rm, cc))
151 }
152
153 pub fn sin(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
158 let (sn, cs) = self.re.sin_cos(p, RoundingMode::None, cc);
159 let (sh, ch) = self.im.sinh_cosh(p, RoundingMode::None, cc);
160 Self::new(sn.mul(&ch, p, rm), cs.mul(&sh, p, rm))
161 }
162
163 pub fn cos(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
165 let (sn, cs) = self.re.sin_cos(p, RoundingMode::None, cc);
166 let (sh, ch) = self.im.sinh_cosh(p, RoundingMode::None, cc);
167 Self::new(cs.mul(&ch, p, rm), sn.mul(&sh, p, rm).neg())
168 }
169
170 fn finish(self, p: usize, rm: RoundingMode) -> Self {
171 let mut re = self.re;
172 let mut im = self.im;
173 if let Err(e) = re.set_precision(p, rm) {
174 return Self::new(ExactNum::nan(Some(e)), ExactNum::nan(Some(e)));
175 }
176 if let Err(e) = im.set_precision(p, rm) {
177 return Self::new(ExactNum::nan(Some(e)), ExactNum::nan(Some(e)));
178 }
179 Self::new(re, im)
180 }
181
182 fn work_p(p: usize) -> usize {
183 p.saturating_add(WORD_BIT_SIZE)
184 }
185
186 pub fn tan(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
188 let p_x = Self::work_p(p);
189 self.sin(p_x, RoundingMode::None, cc)
190 .div(
191 &self.cos(p_x, RoundingMode::None, cc),
192 p_x,
193 RoundingMode::None,
194 )
195 .finish(p, rm)
196 }
197
198 pub fn sinh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
200 let p_x = Self::work_p(p);
201 let (sh, ch) = self.re.sinh_cosh(p_x, RoundingMode::None, cc);
202 let (sn, cs) = self.im.sin_cos(p_x, RoundingMode::None, cc);
203 Self::new(
204 sh.mul(&cs, p_x, RoundingMode::None),
205 ch.mul(&sn, p_x, RoundingMode::None),
206 )
207 .finish(p, rm)
208 }
209
210 pub fn cosh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
212 let p_x = Self::work_p(p);
213 let (sh, ch) = self.re.sinh_cosh(p_x, RoundingMode::None, cc);
214 let (sn, cs) = self.im.sin_cos(p_x, RoundingMode::None, cc);
215 Self::new(
216 ch.mul(&cs, p_x, RoundingMode::None),
217 sh.mul(&sn, p_x, RoundingMode::None),
218 )
219 .finish(p, rm)
220 }
221
222 pub fn tanh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
224 let p_x = Self::work_p(p);
225 self.sinh(p_x, RoundingMode::None, cc)
226 .div(
227 &self.cosh(p_x, RoundingMode::None, cc),
228 p_x,
229 RoundingMode::None,
230 )
231 .finish(p, rm)
232 }
233
234 pub fn sqrt(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
238 let p_x = Self::work_p(p);
239 let r = self.abs(p_x, RoundingMode::None);
240 let th = self.arg(p_x, RoundingMode::None, cc);
241 let sr = r.sqrt(p_x, RoundingMode::None);
242 let half_th = th.ldexp(-1, p_x, RoundingMode::None);
243 let (s, c) = half_th.sin_cos(p_x, RoundingMode::None, cc);
244 Self::new(
245 sr.mul(&c, p_x, RoundingMode::None),
246 sr.mul(&s, p_x, RoundingMode::None),
247 )
248 .finish(p, rm)
249 }
250
251 pub fn log2(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
253 let p_x = Self::work_p(p);
254 let ln = self.ln(p_x, RoundingMode::None, cc);
255 let base = Self::from_real(cc.ln_2(p_x, RoundingMode::None), p_x);
256 ln.div(&base, p_x, RoundingMode::None).finish(p, rm)
257 }
258
259 pub fn log10(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
261 let p_x = Self::work_p(p);
262 let ln = self.ln(p_x, RoundingMode::None, cc);
263 let base = Self::from_real(cc.ln_10(p_x, RoundingMode::None), p_x);
264 ln.div(&base, p_x, RoundingMode::None).finish(p, rm)
265 }
266
267 pub fn log(&self, base: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
269 let p_x = Self::work_p(p);
270 let ln = self.ln(p_x, RoundingMode::None, cc);
271 let lnb = base.ln(p_x, RoundingMode::None, cc);
272 ln.div(&lnb, p_x, RoundingMode::None).finish(p, rm)
273 }
274
275 pub fn log1p(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
277 let p_x = Self::work_p(p);
278 Self::one(p_x)
279 .add(self, p_x, RoundingMode::None)
280 .ln(p_x, RoundingMode::None, cc)
281 .finish(p, rm)
282 }
283
284 pub fn exp2(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
286 let p_x = Self::work_p(p);
287 let ln2 = Self::from_real(cc.ln_2(p_x, RoundingMode::None), p_x);
288 self.mul(&ln2, p_x, RoundingMode::None)
289 .exp(p_x, RoundingMode::None, cc)
290 .finish(p, rm)
291 }
292
293 pub fn exp10(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
295 let p_x = Self::work_p(p);
296 let ln10 = Self::from_real(cc.ln_10(p_x, RoundingMode::None), p_x);
297 self.mul(&ln10, p_x, RoundingMode::None)
298 .exp(p_x, RoundingMode::None, cc)
299 .finish(p, rm)
300 }
301
302 pub fn expm1(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
304 let p_x = Self::work_p(p);
305 self.exp(p_x, RoundingMode::None, cc)
306 .sub(&Self::one(p_x), p_x, RoundingMode::None)
307 .finish(p, rm)
308 }
309
310 pub fn ldexp(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
312 self.ldexp_parts(n, p, rm)
313 }
314
315 pub fn scalb(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
317 self.ldexp(n, p, rm)
318 }
319
320 pub fn logb(&self, p: usize, rm: RoundingMode) -> ExactNum {
322 self.abs(p, rm).logb(p, rm)
323 }
324
325 pub fn nth_root(&self, n: usize, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
327 if n == 0 {
328 return Self::new(
329 ExactNum::nan(Some(crate::Error::InvalidArgument)),
330 ExactNum::nan(Some(crate::Error::InvalidArgument)),
331 );
332 }
333 if n == 1 {
334 let mut z = self.clone();
335 if let Err(e) = z.set_precision(p, rm) {
336 return Self::new(ExactNum::nan(Some(e)), ExactNum::nan(Some(e)));
337 }
338 return z;
339 }
340 if n == 2 {
341 return self.sqrt(p, rm, cc);
342 }
343 let p_x = Self::work_p(p);
344 let ln = self.ln(p_x, RoundingMode::None, cc);
345 let ninv = Self::from_real(
346 ExactNum::from_u32(1, p_x).div(
347 &ExactNum::from_u32(n as u32, p_x),
348 p_x,
349 RoundingMode::None,
350 ),
351 p_x,
352 );
353 ln.mul(&ninv, p_x, RoundingMode::None)
354 .exp(p_x, RoundingMode::None, cc)
355 .finish(p, rm)
356 }
357
358 pub fn cbrt(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
360 self.nth_root(3, p, rm, cc)
361 }
362
363 pub fn hypot(&self, other: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
365 let p_x = Self::work_p(p);
366 self.mul(self, p_x, RoundingMode::None)
367 .add(
368 &other.mul(other, p_x, RoundingMode::None),
369 p_x,
370 RoundingMode::None,
371 )
372 .sqrt(p_x, RoundingMode::None, cc)
373 .finish(p, rm)
374 }
375
376 pub fn fma(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
378 let p_x = Self::work_p(p);
379 self.mul(b, p_x, RoundingMode::None)
380 .add(c, p_x, RoundingMode::None)
381 .finish(p, rm)
382 }
383
384 pub fn mul_add(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
386 self.fma(b, c, p, rm)
387 }
388
389 pub fn pow(&self, rhs: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
393 let p_x = Self::work_p(p);
394 let ln = self.ln(p_x, RoundingMode::None, cc);
395 rhs.mul(&ln, p_x, RoundingMode::None)
396 .exp(p_x, RoundingMode::None, cc)
397 .finish(p, rm)
398 }
399
400 pub fn asin(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
402 let p_x = Self::work_p(p);
403 let z2 = self.mul(self, p_x, RoundingMode::None);
404 let one = Self::one(p_x);
405 let rad = one
406 .sub(&z2, p_x, RoundingMode::None)
407 .sqrt(p_x, RoundingMode::None, cc);
408 let iz = Self::i(p_x).mul(self, p_x, RoundingMode::None);
409 let ln = iz
410 .add(&rad, p_x, RoundingMode::None)
411 .ln(p_x, RoundingMode::None, cc);
412 Self::i(p_x)
413 .mul(&ln, p_x, RoundingMode::None)
414 .neg()
415 .finish(p, rm)
416 }
417
418 pub fn acos(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
420 let p_x = Self::work_p(p);
421 let half_pi = cc
422 .pi(p_x, RoundingMode::None)
423 .ldexp(-1, p_x, RoundingMode::None);
424 let asinv = self.asin(p_x, RoundingMode::None, cc);
425 Self::new(half_pi, ExactNum::new(p_x))
426 .sub(&asinv, p_x, RoundingMode::None)
427 .finish(p, rm)
428 }
429
430 pub fn atan(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
432 let p_x = Self::work_p(p);
433 let i = Self::i(p_x);
434 let num = i.add(self, p_x, RoundingMode::None);
435 let den = i.sub(self, p_x, RoundingMode::None);
436 let ln = num
437 .div(&den, p_x, RoundingMode::None)
438 .ln(p_x, RoundingMode::None, cc);
439 let half_i = i.ldexp_parts(-1, p_x, RoundingMode::None);
440 half_i.mul(&ln, p_x, RoundingMode::None).finish(p, rm)
441 }
442
443 pub fn asinh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
445 let p_x = Self::work_p(p);
446 let z2 = self.mul(self, p_x, RoundingMode::None);
447 let rad =
448 z2.add(&Self::one(p_x), p_x, RoundingMode::None)
449 .sqrt(p_x, RoundingMode::None, cc);
450 self.add(&rad, p_x, RoundingMode::None)
451 .ln(p_x, RoundingMode::None, cc)
452 .finish(p, rm)
453 }
454
455 pub fn acosh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
457 let p_x = Self::work_p(p);
458 let one = Self::one(p_x);
459 let zm = self
460 .sub(&one, p_x, RoundingMode::None)
461 .sqrt(p_x, RoundingMode::None, cc);
462 let zp = self
463 .add(&one, p_x, RoundingMode::None)
464 .sqrt(p_x, RoundingMode::None, cc);
465 self.add(
466 &zm.mul(&zp, p_x, RoundingMode::None),
467 p_x,
468 RoundingMode::None,
469 )
470 .ln(p_x, RoundingMode::None, cc)
471 .finish(p, rm)
472 }
473
474 pub fn atanh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
476 let p_x = Self::work_p(p);
477 let one = Self::one(p_x);
478 let num = one.add(self, p_x, RoundingMode::None);
479 let den = one.sub(self, p_x, RoundingMode::None);
480 num.div(&den, p_x, RoundingMode::None)
481 .ln(p_x, RoundingMode::None, cc)
482 .ldexp_parts(-1, p_x, RoundingMode::None)
483 .finish(p, rm)
484 }
485
486 fn ldexp_parts(&self, n: crate::Exponent, p: usize, rm: RoundingMode) -> Self {
487 Self::new(self.re.ldexp(n, p, rm), self.im.ldexp(n, p, rm))
488 }
489
490 fn neg(&self) -> Self {
491 Self::new(self.re.neg(), self.im.neg())
492 }
493}
494
495macro_rules! impl_cplx_binop {
496 ($trait:ident, $method:ident) => {
497 impl core::ops::$trait<&ExactComplex> for &ExactComplex {
498 type Output = ExactComplex;
499 fn $method(self, rhs: &ExactComplex) -> ExactComplex {
500 ExactComplex::$method(self, rhs, DEFAULT_P, RoundingMode::ToEven)
501 }
502 }
503 impl core::ops::$trait<ExactComplex> for &ExactComplex {
504 type Output = ExactComplex;
505 fn $method(self, rhs: ExactComplex) -> ExactComplex {
506 ExactComplex::$method(self, &rhs, DEFAULT_P, RoundingMode::ToEven)
507 }
508 }
509 impl core::ops::$trait<&ExactComplex> for ExactComplex {
510 type Output = ExactComplex;
511 fn $method(self, rhs: &ExactComplex) -> ExactComplex {
512 ExactComplex::$method(&self, rhs, DEFAULT_P, RoundingMode::ToEven)
513 }
514 }
515 impl core::ops::$trait<ExactComplex> for ExactComplex {
516 type Output = ExactComplex;
517 fn $method(self, rhs: ExactComplex) -> ExactComplex {
518 ExactComplex::$method(&self, &rhs, DEFAULT_P, RoundingMode::ToEven)
519 }
520 }
521 };
522}
523
524impl_cplx_binop!(Add, add);
525impl_cplx_binop!(Sub, sub);
526impl_cplx_binop!(Mul, mul);
527impl_cplx_binop!(Div, div);
528
529impl crate::FromExt<ExactComplex> for ExactComplex {
530 fn from_ext(mut v: ExactComplex, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
531 if let Err(e) = v.set_precision(p, rm) {
532 return Self::new(ExactNum::nan(Some(e)), ExactNum::nan(Some(e)));
533 }
534 v.set_inexact(false);
535 v
536 }
537}
538
539impl crate::FromExt<&ExactComplex> for ExactComplex {
540 fn from_ext(v: &ExactComplex, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
541 <Self as crate::FromExt<ExactComplex>>::from_ext(v.clone(), p, rm, cc)
542 }
543}
544
545impl<T> crate::FromExt<T> for ExactComplex
546where
547 ExactNum: crate::FromExt<T>,
548{
549 fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
550 Self::from_real(<ExactNum as crate::FromExt<T>>::from_ext(v, p, rm, cc), p)
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use super::*;
557 use crate::NAN;
558
559 #[test]
560 fn test_complex_arith() {
561 let p = 256;
562 let rm = RoundingMode::ToEven;
563 let mut cc = Consts::new().unwrap();
564
565 let a = ExactComplex::new(ExactNum::from_u8(3, p), ExactNum::from_u8(4, p));
566 let mag = a.abs(p, rm);
567 let five = ExactNum::from_u8(5, p);
568 assert_eq!(mag.cmp(&five), Some(0));
569
570 let i = ExactComplex::i(p);
571 let i2 = i.mul(&i, p, rm);
572 assert_eq!(i2.re().cmp(&ExactNum::from_i8(-1, p)), Some(0));
573 assert!(i2.im().is_zero());
574
575 let z = ExactComplex::one(p);
576 let e = z.exp(p, rm, &mut cc);
577 let back = e.ln(p, rm, &mut cc);
578 let d = back.re().sub(z.re(), p, RoundingMode::None).abs();
579 assert!(d.is_zero() || d.exponent().unwrap_or(0) < -((p as i32) / 4));
580
581 let z0 = ExactComplex::zero(p);
582 let t = z0.tan(p, rm, &mut cc);
583 assert!(t.re().is_zero() || t.re().exponent().unwrap_or(0) < -((p as i32) / 4));
584 assert!(t.im().is_zero() || t.im().exponent().unwrap_or(0) < -((p as i32) / 4));
585 let sh = z0.sinh(p, rm, &mut cc);
586 assert!(sh.re().is_zero() || sh.re().exponent().unwrap_or(0) < -((p as i32) / 4));
587
588 let two = ExactComplex::from_real(ExactNum::from_u8(2, p), p);
589 let four = ExactComplex::from_real(ExactNum::from_u8(4, p), p);
590 let lg = four.log2(p, rm, &mut cc);
591 let d = lg.re().sub(two.re(), p, RoundingMode::None).abs();
592 assert!(d.is_zero() || d.exponent().unwrap_or(0) < -((p as i32) / 8));
593 assert!(lg.im().is_zero() || lg.im().exponent().unwrap_or(0) < -((p as i32) / 4));
594 let e2 = two.exp2(p, rm, &mut cc);
595 let d2 = e2.re().sub(four.re(), p, RoundingMode::None).abs();
596 assert!(d2.is_zero() || d2.exponent().unwrap_or(0) < -((p as i32) / 8));
597 }
598
599 #[test]
600 fn test_complex_branch_cuts() {
601 let p = 256;
602 let rm = RoundingMode::ToEven;
603 let mut cc = Consts::new().unwrap();
604 let m1 = ExactComplex::from_real(ExactNum::from_i8(-1, p), p);
605
606 let s = m1.sqrt(p, rm, &mut cc);
607 assert!(s.re().is_zero() || s.re().exponent().unwrap_or(0) < -((p as i32) / 4));
608 assert_eq!(s.im().cmp(&ExactNum::from_u8(1, p)), Some(0));
609
610 let l = m1.ln(p, rm, &mut cc);
611 assert!(l.re().is_zero() || l.re().exponent().unwrap_or(0) < -((p as i32) / 4));
612 let pi = cc.pi(p, rm);
613 let d = l.im().abs().sub(&pi, p, RoundingMode::None).abs();
614 assert!(d.is_zero() || d.exponent().unwrap_or(0) < -((p as i32) / 8));
615 assert!(l.im().is_positive());
616
617 let below = ExactComplex::new(ExactNum::from_i8(-1, p), ExactNum::new(p).neg());
618 let lb = below.ln(p, rm, &mut cc);
619 let db = lb.im().abs().sub(&pi, p, RoundingMode::None).abs();
620 assert!(db.is_zero() || db.exponent().unwrap_or(0) < -((p as i32) / 8));
621 assert!(lb.im().is_negative());
622 }
623
624 #[test]
625 fn test_complex_nan() {
626 let n = ExactComplex::new(NAN.clone(), ExactNum::new(64));
627 assert!(n.is_nan());
628 }
629}