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 {
150 let re = c.re;
151 let im = c.im;
152
153 if im == 0.0 {
154 return Value::Text(format_num(re));
155 }
156
157 let re_str = if re == 0.0 {
158 String::new()
159 } else {
160 format_num(re)
161 };
162
163 let im_str = if im == 1.0 {
164 suffix.to_string()
165 } else if im == -1.0 {
166 format!("-{}", suffix)
167 } else {
168 format!("{}{}", format_num(im), suffix)
169 };
170
171 let result = if re == 0.0 {
172 im_str
173 } else if im > 0.0 {
174 format!("{}+{}", re_str, im_str)
175 } else {
176 format!("{}{}", re_str, im_str)
177 };
178
179 Value::Text(result)
180}
181
182fn format_num(n: f64) -> String {
189 if n == 0.0 {
190 return "0".to_string();
191 }
192 if n.fract() == 0.0 && n.abs() < 1e15 {
193 return format!("{}", n as i64);
194 }
195
196 let abs = n.abs();
197
198 if !(1e-9..1e15).contains(&abs) {
199 let s = format!("{:.14e}", n);
201 let (mantissa, exp_part) = s.split_once('e').unwrap();
202 let exp_num: i32 = exp_part.parse().unwrap();
203 let mantissa = mantissa.trim_end_matches('0').trim_end_matches('.');
204 format!("{}E{:+03}", mantissa, exp_num)
206 } else {
207 let s = format!("{:.14e}", n);
209 let (mantissa, exp_part) = s.split_once('e').unwrap();
210 let exp_num: i32 = exp_part.parse().unwrap();
211 let mantissa_stripped = mantissa.trim_end_matches('0').trim_end_matches('.');
212 let sign = if n < 0.0 { "-" } else { "" };
213 let mantissa_abs = mantissa_stripped.trim_start_matches('-');
214 let digits: String = mantissa_abs.chars().filter(|c| *c != '.').collect();
215
216 if exp_num < 0 {
217 let leading_zeros = (-exp_num - 1) as usize;
218 format!("{}0.{}{}", sign, "0".repeat(leading_zeros), digits)
219 } else {
220 let int_part_len = (exp_num + 1) as usize;
221 if int_part_len >= digits.len() {
222 format!(
223 "{}{}{}",
224 sign,
225 digits,
226 "0".repeat(int_part_len - digits.len())
227 )
228 } else {
229 let (int_part, frac_part) = digits.split_at(int_part_len);
230 format!("{}{}.{}", sign, int_part, frac_part)
231 }
232 }
233 }
234}
235
236fn value_to_complex(v: Value) -> Result<Complex, Value> {
238 match v {
239 Value::Number(n) | Value::Date(n) => Ok(Complex::new(n, 0.0)),
240 Value::Text(s) => {
241 parse_complex(&s).ok_or(Value::Error(ErrorKind::Value))
242 }
243 Value::Error(_) => Err(v),
244 _ => {
245 match to_number(v) {
246 Ok(n) => Ok(Complex::new(n, 0.0)),
247 Err(e) => Err(e),
248 }
249 }
250 }
251}
252
253pub fn complex_fn(args: &[Value]) -> Value {
257 if let Some(err) = check_arity(args, 2, 3) {
258 return err;
259 }
260 let re = match to_number(args[0].clone()) {
261 Err(e) => return e,
262 Ok(v) => v,
263 };
264 let im = match to_number(args[1].clone()) {
265 Err(e) => return e,
266 Ok(v) => v,
267 };
268 let suffix = if args.len() == 3 {
269 match to_string_val(args[2].clone()) {
270 Err(e) => return e,
271 Ok(s) => {
272 if s == "i" || s == "j" {
273 s.chars().next().unwrap()
274 } else {
275 return Value::Error(ErrorKind::Value);
276 }
277 }
278 }
279 } else {
280 'i'
281 };
282 format_complex(Complex::new(re, im), suffix)
283}
284
285pub fn imreal_fn(args: &[Value]) -> Value {
289 if let Some(err) = check_arity(args, 1, 1) {
290 return err;
291 }
292 match value_to_complex(args[0].clone()) {
293 Err(e) => e,
294 Ok(c) => Value::Number(c.re),
295 }
296}
297
298pub fn imaginary_fn(args: &[Value]) -> Value {
300 if let Some(err) = check_arity(args, 1, 1) {
301 return err;
302 }
303 match value_to_complex(args[0].clone()) {
304 Err(e) => e,
305 Ok(c) => Value::Number(c.im),
306 }
307}
308
309pub fn imabs_fn(args: &[Value]) -> Value {
313 if let Some(err) = check_arity(args, 1, 1) {
314 return err;
315 }
316 match value_to_complex(args[0].clone()) {
317 Err(e) => e,
318 Ok(c) => Value::Number(c.abs()),
319 }
320}
321
322pub fn improduct_fn(args: &[Value]) -> Value {
326 if let Some(err) = check_arity(args, 1, usize::MAX) {
327 return err;
328 }
329 let mut result = Complex::new(1.0, 0.0);
330 for arg in args {
331 match value_to_complex(arg.clone()) {
332 Err(e) => return e,
333 Ok(c) => result = result.mul(c),
334 }
335 }
336 format_complex(result, 'i')
337}
338
339pub fn imsub_fn(args: &[Value]) -> Value {
343 if let Some(err) = check_arity(args, 2, 2) {
344 return err;
345 }
346 let a = match value_to_complex(args[0].clone()) {
347 Err(e) => return e,
348 Ok(c) => c,
349 };
350 let b = match value_to_complex(args[1].clone()) {
351 Err(e) => return e,
352 Ok(c) => c,
353 };
354 format_complex(Complex::new(a.re - b.re, a.im - b.im), 'i')
355}
356
357pub fn imsum_fn(args: &[Value]) -> Value {
361 if let Some(err) = check_arity(args, 1, usize::MAX) {
362 return err;
363 }
364 let mut re = 0.0f64;
365 let mut im = 0.0f64;
366 for arg in args {
367 match value_to_complex(arg.clone()) {
368 Err(e) => return e,
369 Ok(c) => {
370 re += c.re;
371 im += c.im;
372 }
373 }
374 }
375 format_complex(Complex::new(re, im), 'i')
376}
377
378pub fn imdiv_fn(args: &[Value]) -> Value {
382 if let Some(err) = check_arity(args, 2, 2) {
383 return err;
384 }
385 let a = match value_to_complex(args[0].clone()) {
386 Err(e) => return e,
387 Ok(c) => c,
388 };
389 let b = match value_to_complex(args[1].clone()) {
390 Err(e) => return e,
391 Ok(c) => c,
392 };
393 let denom = b.re * b.re + b.im * b.im;
394 if denom == 0.0 {
395 return Value::Error(ErrorKind::DivByZero);
396 }
397 let re = (a.re * b.re + a.im * b.im) / denom;
398 let im = (a.im * b.re - a.re * b.im) / denom;
399 format_complex(Complex::new(re, im), 'i')
400}
401
402pub fn imconjugate_fn(args: &[Value]) -> Value {
406 if let Some(err) = check_arity(args, 1, 1) {
407 return err;
408 }
409 match value_to_complex(args[0].clone()) {
410 Err(e) => e,
411 Ok(c) => format_complex(Complex::new(c.re, -c.im), 'i'),
412 }
413}
414
415pub fn imargument_fn(args: &[Value]) -> Value {
419 if let Some(err) = check_arity(args, 1, 1) {
420 return err;
421 }
422 match value_to_complex(args[0].clone()) {
423 Err(e) => e,
424 Ok(c) => {
425 if c.re == 0.0 && c.im == 0.0 {
426 Value::Error(ErrorKind::DivByZero)
427 } else {
428 Value::Number(c.arg())
429 }
430 }
431 }
432}
433
434pub fn imln_fn(args: &[Value]) -> Value {
438 if let Some(err) = check_arity(args, 1, 1) {
439 return err;
440 }
441 match value_to_complex(args[0].clone()) {
442 Err(e) => e,
443 Ok(c) => match c.ln() {
444 None => Value::Error(ErrorKind::DivByZero),
445 Some(result) => format_complex(result, 'i'),
446 },
447 }
448}
449
450pub fn imlog10_fn(args: &[Value]) -> Value {
454 if let Some(err) = check_arity(args, 1, 1) {
455 return err;
456 }
457 match value_to_complex(args[0].clone()) {
458 Err(e) => e,
459 Ok(c) => match c.ln() {
460 None => Value::Error(ErrorKind::DivByZero),
461 Some(result) => {
462 let ln10 = 10.0f64.ln();
463 format_complex(Complex::new(result.re / ln10, result.im / ln10), 'i')
464 }
465 },
466 }
467}
468
469pub fn imlog2_fn(args: &[Value]) -> Value {
471 if let Some(err) = check_arity(args, 1, 1) {
472 return err;
473 }
474 match value_to_complex(args[0].clone()) {
475 Err(e) => e,
476 Ok(c) => match c.ln() {
477 None => Value::Error(ErrorKind::DivByZero),
478 Some(result) => {
479 let ln2 = 2.0f64.ln();
480 format_complex(Complex::new(result.re / ln2, result.im / ln2), 'i')
481 }
482 },
483 }
484}
485
486pub fn imlog_fn(args: &[Value]) -> Value {
488 if let Some(err) = check_arity(args, 2, 2) {
489 return err;
490 }
491 let c = match value_to_complex(args[0].clone()) {
492 Err(e) => return e,
493 Ok(v) => v,
494 };
495 let base = match to_number(args[1].clone()) {
496 Err(e) => return e,
497 Ok(v) => v,
498 };
499 if base <= 0.0 || base == 1.0 {
500 return Value::Error(ErrorKind::Num);
501 }
502 match c.ln() {
503 None => Value::Error(ErrorKind::DivByZero),
504 Some(result) => {
505 let ln_base = base.ln();
506 format_complex(Complex::new(result.re / ln_base, result.im / ln_base), 'i')
507 }
508 }
509}
510
511pub fn imexp_fn(args: &[Value]) -> Value {
515 if let Some(err) = check_arity(args, 1, 1) {
516 return err;
517 }
518 match value_to_complex(args[0].clone()) {
519 Err(e) => e,
520 Ok(c) => {
521 let scale = c.re.exp();
522 format_complex(Complex::new(scale * c.im.cos(), scale * c.im.sin()), 'i')
523 }
524 }
525}
526
527pub fn impower_fn(args: &[Value]) -> Value {
531 if let Some(err) = check_arity(args, 2, 2) {
532 return err;
533 }
534 let base = match value_to_complex(args[0].clone()) {
535 Err(e) => return e,
536 Ok(c) => c,
537 };
538 let exp = match value_to_complex(args[1].clone()) {
539 Err(e) => return e,
540 Ok(c) => c,
541 };
542 match base.pow(exp) {
543 None => Value::Error(ErrorKind::Num),
544 Some(result) => format_complex(result, 'i'),
545 }
546}
547
548pub fn imsqrt_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) => format_complex(c.sqrt(), 'i'),
558 }
559}
560
561pub fn imsin_fn(args: &[Value]) -> Value {
565 if let Some(err) = check_arity(args, 1, 1) {
566 return err;
567 }
568 match value_to_complex(args[0].clone()) {
569 Err(e) => e,
570 Ok(c) => {
571 let re = c.re.sin() * c.im.cosh();
572 let im = c.re.cos() * c.im.sinh();
573 format_complex(Complex::new(re, im), 'i')
574 }
575 }
576}
577
578pub fn imcos_fn(args: &[Value]) -> Value {
580 if let Some(err) = check_arity(args, 1, 1) {
581 return err;
582 }
583 match value_to_complex(args[0].clone()) {
584 Err(e) => e,
585 Ok(c) => {
586 let re = c.re.cos() * c.im.cosh();
587 let im = -(c.re.sin() * c.im.sinh());
588 format_complex(Complex::new(re, im), 'i')
589 }
590 }
591}
592
593pub fn imtan_fn(args: &[Value]) -> Value {
595 if let Some(err) = check_arity(args, 1, 1) {
596 return err;
597 }
598 match value_to_complex(args[0].clone()) {
599 Err(e) => e,
600 Ok(c) => {
601 let sin_re = c.re.sin() * c.im.cosh();
602 let sin_im = c.re.cos() * c.im.sinh();
603 let cos_re = c.re.cos() * c.im.cosh();
604 let cos_im = -(c.re.sin() * c.im.sinh());
605 let denom = cos_re * cos_re + cos_im * cos_im;
606 if denom == 0.0 {
607 return Value::Error(ErrorKind::DivByZero);
608 }
609 let re = (sin_re * cos_re + sin_im * cos_im) / denom;
610 let im = (sin_im * cos_re - sin_re * cos_im) / denom;
611 format_complex(Complex::new(re, im), 'i')
612 }
613 }
614}
615
616pub fn imcot_fn(args: &[Value]) -> Value {
618 if let Some(err) = check_arity(args, 1, 1) {
619 return err;
620 }
621 match value_to_complex(args[0].clone()) {
622 Err(e) => e,
623 Ok(c) => {
624 let sin_re = c.re.sin() * c.im.cosh();
625 let sin_im = c.re.cos() * c.im.sinh();
626 let cos_re = c.re.cos() * c.im.cosh();
627 let cos_im = -(c.re.sin() * c.im.sinh());
628 let denom = sin_re * sin_re + sin_im * sin_im;
629 if denom == 0.0 {
630 return Value::Error(ErrorKind::DivByZero);
631 }
632 let re = (cos_re * sin_re + cos_im * sin_im) / denom;
633 let im = (cos_im * sin_re - cos_re * sin_im) / denom;
634 format_complex(Complex::new(re, im), 'i')
635 }
636 }
637}
638
639pub fn imcsc_fn(args: &[Value]) -> Value {
641 if let Some(err) = check_arity(args, 1, 1) {
642 return err;
643 }
644 match value_to_complex(args[0].clone()) {
645 Err(e) => e,
646 Ok(c) => {
647 let sin_re = c.re.sin() * c.im.cosh();
648 let sin_im = c.re.cos() * c.im.sinh();
649 let denom = sin_re * sin_re + sin_im * sin_im;
650 if denom == 0.0 {
651 return Value::Error(ErrorKind::Num);
652 }
653 let re = sin_re / denom;
654 let im = -sin_im / denom;
655 format_complex(Complex::new(re, im), 'i')
656 }
657 }
658}
659
660pub fn imsec_fn(args: &[Value]) -> Value {
662 if let Some(err) = check_arity(args, 1, 1) {
663 return err;
664 }
665 match value_to_complex(args[0].clone()) {
666 Err(e) => e,
667 Ok(c) => {
668 let cos_re = c.re.cos() * c.im.cosh();
669 let cos_im = -(c.re.sin() * c.im.sinh());
670 let denom = cos_re * cos_re + cos_im * cos_im;
671 if denom == 0.0 {
672 return Value::Error(ErrorKind::DivByZero);
673 }
674 let re = cos_re / denom;
675 let im = -cos_im / denom;
676 format_complex(Complex::new(re, im), 'i')
677 }
678 }
679}
680
681pub fn imsinh_fn(args: &[Value]) -> Value {
685 if let Some(err) = check_arity(args, 1, 1) {
686 return err;
687 }
688 match value_to_complex(args[0].clone()) {
689 Err(e) => e,
690 Ok(c) => {
691 let re = c.re.sinh() * c.im.cos();
692 let im = c.re.cosh() * c.im.sin();
693 format_complex(Complex::new(re, im), 'i')
694 }
695 }
696}
697
698pub fn imcosh_fn(args: &[Value]) -> Value {
700 if let Some(err) = check_arity(args, 1, 1) {
701 return err;
702 }
703 match value_to_complex(args[0].clone()) {
704 Err(e) => e,
705 Ok(c) => {
706 let re = c.re.cosh() * c.im.cos();
707 let im = c.re.sinh() * c.im.sin();
708 format_complex(Complex::new(re, im), 'i')
709 }
710 }
711}
712
713pub fn imtanh_fn(args: &[Value]) -> Value {
715 if let Some(err) = check_arity(args, 1, 1) {
716 return err;
717 }
718 match value_to_complex(args[0].clone()) {
719 Err(e) => e,
720 Ok(c) => {
721 let sinh_re = c.re.sinh() * c.im.cos();
722 let sinh_im = c.re.cosh() * c.im.sin();
723 let cosh_re = c.re.cosh() * c.im.cos();
724 let cosh_im = c.re.sinh() * c.im.sin();
725 let denom = cosh_re * cosh_re + cosh_im * cosh_im;
726 if denom == 0.0 {
727 return Value::Error(ErrorKind::DivByZero);
728 }
729 let re = (sinh_re * cosh_re + sinh_im * cosh_im) / denom;
730 let im = (sinh_im * cosh_re - sinh_re * cosh_im) / denom;
731 if im == 0.0 {
732 return Value::Text(format!("{}", re));
733 }
734 format_complex(Complex::new(re, im), 'i')
735 }
736 }
737}
738
739pub fn imcoth_fn(args: &[Value]) -> Value {
741 if let Some(err) = check_arity(args, 1, 1) {
742 return err;
743 }
744 match value_to_complex(args[0].clone()) {
745 Err(e) => e,
746 Ok(c) => {
747 let sinh_re = c.re.sinh() * c.im.cos();
748 let sinh_im = c.re.cosh() * c.im.sin();
749 let cosh_re = c.re.cosh() * c.im.cos();
750 let cosh_im = c.re.sinh() * c.im.sin();
751 let denom = sinh_re * sinh_re + sinh_im * sinh_im;
752 if denom == 0.0 {
753 return Value::Error(ErrorKind::DivByZero);
754 }
755 let re = (cosh_re * sinh_re + cosh_im * sinh_im) / denom;
756 let im = (cosh_im * sinh_re - cosh_re * sinh_im) / denom;
757 if im == 0.0 {
758 return Value::Text(format!("{}", re));
759 }
760 format_complex(Complex::new(re, im), 'i')
761 }
762 }
763}
764
765pub fn imcsch_fn(args: &[Value]) -> Value {
767 if let Some(err) = check_arity(args, 1, 1) {
768 return err;
769 }
770 match value_to_complex(args[0].clone()) {
771 Err(e) => e,
772 Ok(c) => {
773 let sinh_re = c.re.sinh() * c.im.cos();
774 let sinh_im = c.re.cosh() * c.im.sin();
775 let denom = sinh_re * sinh_re + sinh_im * sinh_im;
776 if denom == 0.0 {
777 return Value::Error(ErrorKind::DivByZero);
778 }
779 let re = sinh_re / denom;
780 let im = -sinh_im / denom;
781 format_complex(Complex::new(re, im), 'i')
782 }
783 }
784}
785
786pub fn imsech_fn(args: &[Value]) -> Value {
788 if let Some(err) = check_arity(args, 1, 1) {
789 return err;
790 }
791 match value_to_complex(args[0].clone()) {
792 Err(e) => e,
793 Ok(c) => {
794 let cosh_re = c.re.cosh() * c.im.cos();
795 let cosh_im = c.re.sinh() * c.im.sin();
796 let denom = cosh_re * cosh_re + cosh_im * cosh_im;
797 if denom == 0.0 {
798 return Value::Error(ErrorKind::DivByZero);
799 }
800 let re = cosh_re / denom;
801 let im = -cosh_im / denom;
802 format_complex(Complex::new(re, im), 'i')
803 }
804 }
805}
806
807#[cfg(test)]
808mod tests;