1use crate::eval::coercion::{to_number, to_string_val};
2use crate::eval::functions::check_arity;
3use crate::types::{ErrorKind, Value};
4
5#[derive(Clone, Copy, Debug, PartialEq)]
8pub(super) struct Complex {
9 pub re: f64,
10 pub im: f64,
11}
12
13impl Complex {
14 fn new(re: f64, im: f64) -> Self {
15 Self { re, im }
16 }
17
18 fn abs(self) -> f64 {
19 (self.re * self.re + self.im * self.im).sqrt()
20 }
21
22 fn arg(self) -> f64 {
23 self.im.atan2(self.re)
24 }
25
26 fn mul(self, rhs: Self) -> Self {
27 Self {
28 re: self.re * rhs.re - self.im * rhs.im,
29 im: self.re * rhs.im + self.im * rhs.re,
30 }
31 }
32
33 fn pow(self, n: Self) -> Option<Self> {
34 let r = self.abs();
36 if r == 0.0 {
37 if n.re == 0.0 && n.im == 0.0 {
39 return Some(Complex::new(1.0, 0.0));
40 }
41 if n.re > 0.0 {
42 return Some(Complex::new(0.0, 0.0));
43 }
44 return None; }
46 let theta = self.arg();
47 let ln_r = r.ln();
48 let exp_re = n.re * ln_r - n.im * theta;
51 let exp_im = n.im * ln_r + n.re * theta;
52 let scale = exp_re.exp();
53 Some(Complex::new(scale * exp_im.cos(), scale * exp_im.sin()))
54 }
55
56 fn sqrt(self) -> Self {
57 let r = self.abs();
59 let sqrt_r = r.sqrt();
60 let theta = self.arg();
61 Complex::new(sqrt_r * (theta / 2.0).cos(), sqrt_r * (theta / 2.0).sin())
62 }
63
64 fn ln(self) -> Option<Self> {
65 let r = self.abs();
66 if r == 0.0 {
67 return None;
68 }
69 Some(Complex::new(r.ln(), self.arg()))
70 }
71}
72
73pub(super) fn parse_complex(s: &str) -> Option<Complex> {
78 let s = s.trim();
79 if s.is_empty() {
80 return None;
81 }
82
83 let suffix = if s.ends_with('i') || s.ends_with('j') {
85 Some(s.chars().last().unwrap())
86 } else {
87 None
88 };
89
90 if suffix.is_none() {
91 let re = s.parse::<f64>().ok()?;
93 return Some(Complex::new(re, 0.0));
94 }
95
96 let s = &s[..s.len() - 1];
98
99 if s.is_empty() || s == "+" {
101 return Some(Complex::new(0.0, 1.0));
102 }
103 if s == "-" {
104 return Some(Complex::new(0.0, -1.0));
105 }
106
107 if !s.contains('+') && !s.contains('-') || s.starts_with('-') && s[1..].find(['+', '-']).is_none() {
109 let im = s.parse::<f64>().ok()?;
111 return Some(Complex::new(0.0, im));
112 }
113
114 let bytes = s.as_bytes();
117 let mut split = None;
118 let start = if bytes[0] == b'-' || bytes[0] == b'+' { 1 } else { 0 };
119 for i in (start + 1..bytes.len()).rev() {
120 if bytes[i] == b'+' || bytes[i] == b'-' {
121 split = Some(i);
122 break;
123 }
124 }
125
126 if let Some(idx) = split {
127 let re_str = &s[..idx];
128 let im_str = &s[idx..];
129
130 let re = if re_str.is_empty() { 0.0 } else { re_str.parse::<f64>().ok()? };
131 let im = if im_str == "+" || im_str.is_empty() {
132 1.0
133 } else if im_str == "-" {
134 -1.0
135 } else {
136 im_str.parse::<f64>().ok()?
137 };
138 Some(Complex::new(re, im))
139 } else {
140 let im = s.parse::<f64>().ok()?;
142 Some(Complex::new(0.0, im))
143 }
144}
145
146pub(super) fn format_complex(c: Complex, suffix: char) -> Value {
148 let re = c.re;
149 let im = c.im;
150
151 let re = if re.abs() < 1e-10 { 0.0 } else { re };
153 let im = if im.abs() < 1e-10 { 0.0 } else { im };
154
155 if im == 0.0 {
156 return Value::Number(re);
157 }
158
159 let re_str = if re == 0.0 {
160 String::new()
161 } else {
162 format_num(re)
163 };
164
165 let im_str = if im == 1.0 {
166 suffix.to_string()
167 } else if im == -1.0 {
168 format!("-{}", suffix)
169 } else {
170 format!("{}{}", format_num(im), suffix)
171 };
172
173 let result = if re == 0.0 {
174 im_str
175 } else if im > 0.0 || im == 1.0 {
176 format!("{}+{}", re_str, im_str)
177 } else {
178 format!("{}{}", re_str, im_str)
179 };
180
181 Value::Text(result)
182}
183
184fn format_num(n: f64) -> String {
185 if n.fract() == 0.0 && n.abs() < 1e15 {
187 format!("{}", n as i64)
188 } else {
189 format!("{}", n)
190 }
191}
192
193fn value_to_complex(v: Value) -> Result<Complex, Value> {
195 match v {
196 Value::Number(n) | Value::Date(n) => Ok(Complex::new(n, 0.0)),
197 Value::Text(s) => {
198 parse_complex(&s).ok_or(Value::Error(ErrorKind::Value))
199 }
200 Value::Error(_) => Err(v),
201 _ => {
202 match to_number(v) {
203 Ok(n) => Ok(Complex::new(n, 0.0)),
204 Err(e) => Err(e),
205 }
206 }
207 }
208}
209
210pub fn complex_fn(args: &[Value]) -> Value {
214 if let Some(err) = check_arity(args, 2, 3) {
215 return err;
216 }
217 let re = match to_number(args[0].clone()) {
218 Err(e) => return e,
219 Ok(v) => v,
220 };
221 let im = match to_number(args[1].clone()) {
222 Err(e) => return e,
223 Ok(v) => v,
224 };
225 let suffix = if args.len() == 3 {
226 match to_string_val(args[2].clone()) {
227 Err(e) => return e,
228 Ok(s) => {
229 if s == "i" || s == "j" {
230 s.chars().next().unwrap()
231 } else {
232 return Value::Error(ErrorKind::Value);
233 }
234 }
235 }
236 } else {
237 'i'
238 };
239 format_complex(Complex::new(re, im), suffix)
240}
241
242pub fn imreal_fn(args: &[Value]) -> Value {
246 if let Some(err) = check_arity(args, 1, 1) {
247 return err;
248 }
249 match value_to_complex(args[0].clone()) {
250 Err(e) => e,
251 Ok(c) => Value::Number(c.re),
252 }
253}
254
255pub fn imaginary_fn(args: &[Value]) -> Value {
257 if let Some(err) = check_arity(args, 1, 1) {
258 return err;
259 }
260 match value_to_complex(args[0].clone()) {
261 Err(e) => e,
262 Ok(c) => Value::Number(c.im),
263 }
264}
265
266pub fn imabs_fn(args: &[Value]) -> Value {
270 if let Some(err) = check_arity(args, 1, 1) {
271 return err;
272 }
273 match value_to_complex(args[0].clone()) {
274 Err(e) => e,
275 Ok(c) => Value::Number(c.abs()),
276 }
277}
278
279pub fn improduct_fn(args: &[Value]) -> Value {
283 if let Some(err) = check_arity(args, 1, usize::MAX) {
284 return err;
285 }
286 let mut result = Complex::new(1.0, 0.0);
287 for arg in args {
288 match value_to_complex(arg.clone()) {
289 Err(e) => return e,
290 Ok(c) => result = result.mul(c),
291 }
292 }
293 format_complex(result, 'i')
294}
295
296pub fn imsub_fn(args: &[Value]) -> Value {
300 if let Some(err) = check_arity(args, 2, 2) {
301 return err;
302 }
303 let a = match value_to_complex(args[0].clone()) {
304 Err(e) => return e,
305 Ok(c) => c,
306 };
307 let b = match value_to_complex(args[1].clone()) {
308 Err(e) => return e,
309 Ok(c) => c,
310 };
311 format_complex(Complex::new(a.re - b.re, a.im - b.im), 'i')
312}
313
314pub fn imsum_fn(args: &[Value]) -> Value {
318 if let Some(err) = check_arity(args, 1, usize::MAX) {
319 return err;
320 }
321 let mut re = 0.0f64;
322 let mut im = 0.0f64;
323 for arg in args {
324 match value_to_complex(arg.clone()) {
325 Err(e) => return e,
326 Ok(c) => {
327 re += c.re;
328 im += c.im;
329 }
330 }
331 }
332 format_complex(Complex::new(re, im), 'i')
333}
334
335pub fn imdiv_fn(args: &[Value]) -> Value {
339 if let Some(err) = check_arity(args, 2, 2) {
340 return err;
341 }
342 let a = match value_to_complex(args[0].clone()) {
343 Err(e) => return e,
344 Ok(c) => c,
345 };
346 let b = match value_to_complex(args[1].clone()) {
347 Err(e) => return e,
348 Ok(c) => c,
349 };
350 let denom = b.re * b.re + b.im * b.im;
351 if denom == 0.0 {
352 return Value::Error(ErrorKind::DivByZero);
353 }
354 let re = (a.re * b.re + a.im * b.im) / denom;
355 let im = (a.im * b.re - a.re * b.im) / denom;
356 format_complex(Complex::new(re, im), 'i')
357}
358
359pub fn imconjugate_fn(args: &[Value]) -> Value {
363 if let Some(err) = check_arity(args, 1, 1) {
364 return err;
365 }
366 match value_to_complex(args[0].clone()) {
367 Err(e) => e,
368 Ok(c) => format_complex(Complex::new(c.re, -c.im), 'i'),
369 }
370}
371
372pub fn imargument_fn(args: &[Value]) -> Value {
376 if let Some(err) = check_arity(args, 1, 1) {
377 return err;
378 }
379 match value_to_complex(args[0].clone()) {
380 Err(e) => e,
381 Ok(c) => {
382 if c.re == 0.0 && c.im == 0.0 {
383 Value::Error(ErrorKind::DivByZero)
384 } else {
385 Value::Number(c.arg())
386 }
387 }
388 }
389}
390
391pub fn imln_fn(args: &[Value]) -> Value {
395 if let Some(err) = check_arity(args, 1, 1) {
396 return err;
397 }
398 match value_to_complex(args[0].clone()) {
399 Err(e) => e,
400 Ok(c) => match c.ln() {
401 None => Value::Error(ErrorKind::DivByZero),
402 Some(result) => format_complex(result, 'i'),
403 },
404 }
405}
406
407pub fn imlog10_fn(args: &[Value]) -> Value {
411 if let Some(err) = check_arity(args, 1, 1) {
412 return err;
413 }
414 match value_to_complex(args[0].clone()) {
415 Err(e) => e,
416 Ok(c) => match c.ln() {
417 None => Value::Error(ErrorKind::DivByZero),
418 Some(result) => {
419 let ln10 = 10.0f64.ln();
420 format_complex(Complex::new(result.re / ln10, result.im / ln10), 'i')
421 }
422 },
423 }
424}
425
426pub fn imlog2_fn(args: &[Value]) -> Value {
428 if let Some(err) = check_arity(args, 1, 1) {
429 return err;
430 }
431 match value_to_complex(args[0].clone()) {
432 Err(e) => e,
433 Ok(c) => match c.ln() {
434 None => Value::Error(ErrorKind::DivByZero),
435 Some(result) => {
436 let ln2 = 2.0f64.ln();
437 format_complex(Complex::new(result.re / ln2, result.im / ln2), 'i')
438 }
439 },
440 }
441}
442
443pub fn imlog_fn(args: &[Value]) -> Value {
445 if let Some(err) = check_arity(args, 2, 2) {
446 return err;
447 }
448 let c = match value_to_complex(args[0].clone()) {
449 Err(e) => return e,
450 Ok(v) => v,
451 };
452 let base = match to_number(args[1].clone()) {
453 Err(e) => return e,
454 Ok(v) => v,
455 };
456 if base <= 0.0 || base == 1.0 {
457 return Value::Error(ErrorKind::Num);
458 }
459 match c.ln() {
460 None => Value::Error(ErrorKind::DivByZero),
461 Some(result) => {
462 let ln_base = base.ln();
463 format_complex(Complex::new(result.re / ln_base, result.im / ln_base), 'i')
464 }
465 }
466}
467
468pub fn imexp_fn(args: &[Value]) -> Value {
472 if let Some(err) = check_arity(args, 1, 1) {
473 return err;
474 }
475 match value_to_complex(args[0].clone()) {
476 Err(e) => e,
477 Ok(c) => {
478 let scale = c.re.exp();
479 format_complex(Complex::new(scale * c.im.cos(), scale * c.im.sin()), 'i')
480 }
481 }
482}
483
484pub fn impower_fn(args: &[Value]) -> Value {
488 if let Some(err) = check_arity(args, 2, 2) {
489 return err;
490 }
491 let base = match value_to_complex(args[0].clone()) {
492 Err(e) => return e,
493 Ok(c) => c,
494 };
495 let exp = match value_to_complex(args[1].clone()) {
496 Err(e) => return e,
497 Ok(c) => c,
498 };
499 match base.pow(exp) {
500 None => Value::Error(ErrorKind::Num),
501 Some(result) => format_complex(result, 'i'),
502 }
503}
504
505pub fn imsqrt_fn(args: &[Value]) -> Value {
509 if let Some(err) = check_arity(args, 1, 1) {
510 return err;
511 }
512 match value_to_complex(args[0].clone()) {
513 Err(e) => e,
514 Ok(c) => format_complex(c.sqrt(), 'i'),
515 }
516}
517
518pub fn imsin_fn(args: &[Value]) -> Value {
522 if let Some(err) = check_arity(args, 1, 1) {
523 return err;
524 }
525 match value_to_complex(args[0].clone()) {
526 Err(e) => e,
527 Ok(c) => {
528 let re = c.re.sin() * c.im.cosh();
529 let im = c.re.cos() * c.im.sinh();
530 format_complex(Complex::new(re, im), 'i')
531 }
532 }
533}
534
535pub fn imcos_fn(args: &[Value]) -> Value {
537 if let Some(err) = check_arity(args, 1, 1) {
538 return err;
539 }
540 match value_to_complex(args[0].clone()) {
541 Err(e) => e,
542 Ok(c) => {
543 let re = c.re.cos() * c.im.cosh();
544 let im = -(c.re.sin() * c.im.sinh());
545 format_complex(Complex::new(re, im), 'i')
546 }
547 }
548}
549
550pub fn imtan_fn(args: &[Value]) -> Value {
552 if let Some(err) = check_arity(args, 1, 1) {
553 return err;
554 }
555 match value_to_complex(args[0].clone()) {
556 Err(e) => e,
557 Ok(c) => {
558 let sin_re = c.re.sin() * c.im.cosh();
559 let sin_im = c.re.cos() * c.im.sinh();
560 let cos_re = c.re.cos() * c.im.cosh();
561 let cos_im = -(c.re.sin() * c.im.sinh());
562 let denom = cos_re * cos_re + cos_im * cos_im;
563 if denom == 0.0 {
564 return Value::Error(ErrorKind::DivByZero);
565 }
566 let re = (sin_re * cos_re + sin_im * cos_im) / denom;
567 let im = (sin_im * cos_re - sin_re * cos_im) / denom;
568 format_complex(Complex::new(re, im), 'i')
569 }
570 }
571}
572
573pub fn imcot_fn(args: &[Value]) -> Value {
575 if let Some(err) = check_arity(args, 1, 1) {
576 return err;
577 }
578 match value_to_complex(args[0].clone()) {
579 Err(e) => e,
580 Ok(c) => {
581 let sin_re = c.re.sin() * c.im.cosh();
582 let sin_im = c.re.cos() * c.im.sinh();
583 let cos_re = c.re.cos() * c.im.cosh();
584 let cos_im = -(c.re.sin() * c.im.sinh());
585 let denom = sin_re * sin_re + sin_im * sin_im;
586 if denom == 0.0 {
587 return Value::Error(ErrorKind::DivByZero);
588 }
589 let re = (cos_re * sin_re + cos_im * sin_im) / denom;
590 let im = (cos_im * sin_re - cos_re * sin_im) / denom;
591 format_complex(Complex::new(re, im), 'i')
592 }
593 }
594}
595
596pub fn imcsc_fn(args: &[Value]) -> Value {
598 if let Some(err) = check_arity(args, 1, 1) {
599 return err;
600 }
601 match value_to_complex(args[0].clone()) {
602 Err(e) => e,
603 Ok(c) => {
604 let sin_re = c.re.sin() * c.im.cosh();
605 let sin_im = c.re.cos() * c.im.sinh();
606 let denom = sin_re * sin_re + sin_im * sin_im;
607 if denom == 0.0 {
608 return Value::Error(ErrorKind::Num);
609 }
610 let re = sin_re / denom;
611 let im = -sin_im / denom;
612 format_complex(Complex::new(re, im), 'i')
613 }
614 }
615}
616
617pub fn imsec_fn(args: &[Value]) -> Value {
619 if let Some(err) = check_arity(args, 1, 1) {
620 return err;
621 }
622 match value_to_complex(args[0].clone()) {
623 Err(e) => e,
624 Ok(c) => {
625 let cos_re = c.re.cos() * c.im.cosh();
626 let cos_im = -(c.re.sin() * c.im.sinh());
627 let denom = cos_re * cos_re + cos_im * cos_im;
628 if denom == 0.0 {
629 return Value::Error(ErrorKind::DivByZero);
630 }
631 let re = cos_re / denom;
632 let im = -cos_im / denom;
633 format_complex(Complex::new(re, im), 'i')
634 }
635 }
636}
637
638pub fn imsinh_fn(args: &[Value]) -> Value {
642 if let Some(err) = check_arity(args, 1, 1) {
643 return err;
644 }
645 match value_to_complex(args[0].clone()) {
646 Err(e) => e,
647 Ok(c) => {
648 let re = c.re.sinh() * c.im.cos();
649 let im = c.re.cosh() * c.im.sin();
650 format_complex(Complex::new(re, im), 'i')
651 }
652 }
653}
654
655pub fn imcosh_fn(args: &[Value]) -> Value {
657 if let Some(err) = check_arity(args, 1, 1) {
658 return err;
659 }
660 match value_to_complex(args[0].clone()) {
661 Err(e) => e,
662 Ok(c) => {
663 let re = c.re.cosh() * c.im.cos();
664 let im = c.re.sinh() * c.im.sin();
665 format_complex(Complex::new(re, im), 'i')
666 }
667 }
668}
669
670pub fn imtanh_fn(args: &[Value]) -> Value {
672 if let Some(err) = check_arity(args, 1, 1) {
673 return err;
674 }
675 match value_to_complex(args[0].clone()) {
676 Err(e) => e,
677 Ok(c) => {
678 let sinh_re = c.re.sinh() * c.im.cos();
679 let sinh_im = c.re.cosh() * c.im.sin();
680 let cosh_re = c.re.cosh() * c.im.cos();
681 let cosh_im = c.re.sinh() * c.im.sin();
682 let denom = cosh_re * cosh_re + cosh_im * cosh_im;
683 if denom == 0.0 {
684 return Value::Error(ErrorKind::DivByZero);
685 }
686 let re = (sinh_re * cosh_re + sinh_im * cosh_im) / denom;
687 let im = (sinh_im * cosh_re - sinh_re * cosh_im) / denom;
688 format_complex(Complex::new(re, im), 'i')
689 }
690 }
691}
692
693pub fn imcoth_fn(args: &[Value]) -> Value {
695 if let Some(err) = check_arity(args, 1, 1) {
696 return err;
697 }
698 match value_to_complex(args[0].clone()) {
699 Err(e) => e,
700 Ok(c) => {
701 let sinh_re = c.re.sinh() * c.im.cos();
702 let sinh_im = c.re.cosh() * c.im.sin();
703 let cosh_re = c.re.cosh() * c.im.cos();
704 let cosh_im = c.re.sinh() * c.im.sin();
705 let denom = sinh_re * sinh_re + sinh_im * sinh_im;
706 if denom == 0.0 {
707 return Value::Error(ErrorKind::DivByZero);
708 }
709 let re = (cosh_re * sinh_re + cosh_im * sinh_im) / denom;
710 let im = (cosh_im * sinh_re - cosh_re * sinh_im) / denom;
711 format_complex(Complex::new(re, im), 'i')
712 }
713 }
714}
715
716pub fn imcsch_fn(args: &[Value]) -> Value {
718 if let Some(err) = check_arity(args, 1, 1) {
719 return err;
720 }
721 match value_to_complex(args[0].clone()) {
722 Err(e) => e,
723 Ok(c) => {
724 let sinh_re = c.re.sinh() * c.im.cos();
725 let sinh_im = c.re.cosh() * c.im.sin();
726 let denom = sinh_re * sinh_re + sinh_im * sinh_im;
727 if denom == 0.0 {
728 return Value::Error(ErrorKind::DivByZero);
729 }
730 let re = sinh_re / denom;
731 let im = -sinh_im / denom;
732 format_complex(Complex::new(re, im), 'i')
733 }
734 }
735}
736
737pub fn imsech_fn(args: &[Value]) -> Value {
739 if let Some(err) = check_arity(args, 1, 1) {
740 return err;
741 }
742 match value_to_complex(args[0].clone()) {
743 Err(e) => e,
744 Ok(c) => {
745 let cosh_re = c.re.cosh() * c.im.cos();
746 let cosh_im = c.re.sinh() * c.im.sin();
747 let denom = cosh_re * cosh_re + cosh_im * cosh_im;
748 if denom == 0.0 {
749 return Value::Error(ErrorKind::DivByZero);
750 }
751 let re = cosh_re / denom;
752 let im = -cosh_im / denom;
753 format_complex(Complex::new(re, im), 'i')
754 }
755 }
756}
757
758#[cfg(test)]
759mod tests;