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 libm::sqrt(self.re * self.re + self.im * self.im)
20 }
21
22 fn arg(self) -> f64 {
23 libm::atan2(self.im, 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 = libm::log(r);
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 = libm::exp(exp_re);
53 Some(Complex::new(scale * libm::cos(exp_im), scale * libm::sin(exp_im)))
54 }
55
56 fn sqrt(self) -> Self {
57 let r = self.abs();
67 if r == 0.0 {
68 return Complex::new(0.0, 0.0);
69 }
70 if self.im == 0.0 && self.re < 0.0 {
71 let theta = self.arg(); let sqrt_r = libm::sqrt(r);
74 return Complex::new(sqrt_r * libm::cos(theta / 2.0), sqrt_r * libm::sin(theta / 2.0));
75 }
76 let re_out = libm::sqrt((r + self.re) / 2.0);
78 let im_out = libm::sqrt((r - self.re) / 2.0);
79 let im_out = if self.im < 0.0 { -im_out } else { im_out };
80 Complex::new(re_out, im_out)
81 }
82
83 fn ln(self) -> Option<Self> {
84 let r = self.abs();
85 if r == 0.0 {
86 return None;
87 }
88 Some(Complex::new(libm::log(r), self.arg()))
89 }
90}
91
92pub(super) fn parse_complex(s: &str) -> Option<Complex> {
97 let s = s.trim();
98 if s.is_empty() {
99 return None;
100 }
101
102 let suffix = if s.ends_with('i') || s.ends_with('j') {
104 Some(s.chars().last().unwrap())
105 } else {
106 None
107 };
108
109 if suffix.is_none() {
110 let re = s.parse::<f64>().ok()?;
112 return Some(Complex::new(re, 0.0));
113 }
114
115 let s = &s[..s.len() - 1];
117
118 if s.is_empty() || s == "+" {
120 return Some(Complex::new(0.0, 1.0));
121 }
122 if s == "-" {
123 return Some(Complex::new(0.0, -1.0));
124 }
125
126 if !s.contains('+') && !s.contains('-') || s.starts_with('-') && s[1..].find(['+', '-']).is_none() {
128 let im = s.parse::<f64>().ok()?;
130 return Some(Complex::new(0.0, im));
131 }
132
133 let bytes = s.as_bytes();
136 let mut split = None;
137 let start = if bytes[0] == b'-' || bytes[0] == b'+' { 1 } else { 0 };
138 for i in (start + 1..bytes.len()).rev() {
139 if bytes[i] == b'+' || bytes[i] == b'-' {
140 split = Some(i);
141 break;
142 }
143 }
144
145 if let Some(idx) = split {
146 let mut re_str = &s[..idx];
147 let im_str = &s[idx..];
148
149 if !re_str.is_empty()
151 && (re_str.ends_with('+') || re_str.ends_with('-'))
152 && (re_str[..re_str.len()-1].parse::<f64>().is_ok() || re_str.len() == 1)
153 {
154 re_str = &re_str[..re_str.len()-1];
155 }
156
157 let re = if re_str.is_empty() { 0.0 } else { re_str.parse::<f64>().ok()? };
158 let im = if im_str == "+" || im_str.is_empty() {
159 1.0
160 } else if im_str == "-" {
161 -1.0
162 } else {
163 im_str.parse::<f64>().ok()?
164 };
165 Some(Complex::new(re, im))
166 } else {
167 let im = s.parse::<f64>().ok()?;
169 Some(Complex::new(0.0, im))
170 }
171}
172
173pub(super) fn format_complex(c: Complex, suffix: char) -> Value {
177 let re = c.re;
178 let im = c.im;
179
180 if im == 0.0 {
181 return Value::Text(format_num(re));
182 }
183
184 let re_str = if re == 0.0 {
185 String::new()
186 } else {
187 format_num(re)
188 };
189
190 let im_str = if im == 1.0 {
191 suffix.to_string()
192 } else if im == -1.0 {
193 format!("-{}", suffix)
194 } else {
195 format!("{}{}", format_num(im), suffix)
196 };
197
198 let result = if re == 0.0 {
199 im_str
200 } else if im > 0.0 {
201 format!("{}+{}", re_str, im_str)
202 } else {
203 format!("{}{}", re_str, im_str)
204 };
205
206 Value::Text(result)
207}
208
209fn format_num(n: f64) -> String {
216 if n == 0.0 {
217 return "0".to_string();
218 }
219 if n.fract() == 0.0 && n.abs() < 1e15 {
220 return format!("{}", n as i64);
221 }
222
223 let abs = n.abs();
224
225 if !(1e-9..1e15).contains(&abs) {
226 let s = format!("{:.14e}", n);
228 let (mantissa, exp_part) = s.split_once('e').unwrap();
229 let exp_num: i32 = exp_part.parse().unwrap();
230 let mantissa = mantissa.trim_end_matches('0').trim_end_matches('.');
231 format!("{}E{:+03}", mantissa, exp_num)
233 } else {
234 let s = format!("{:.14e}", n);
236 let (mantissa, exp_part) = s.split_once('e').unwrap();
237 let exp_num: i32 = exp_part.parse().unwrap();
238 let mantissa_stripped = mantissa.trim_end_matches('0').trim_end_matches('.');
239 let sign = if n < 0.0 { "-" } else { "" };
240 let mantissa_abs = mantissa_stripped.trim_start_matches('-');
241 let digits: String = mantissa_abs.chars().filter(|c| *c != '.').collect();
242
243 if exp_num < 0 {
244 let leading_zeros = (-exp_num - 1) as usize;
245 format!("{}0.{}{}", sign, "0".repeat(leading_zeros), digits)
246 } else {
247 let int_part_len = (exp_num + 1) as usize;
248 if int_part_len >= digits.len() {
249 format!(
250 "{}{}{}",
251 sign,
252 digits,
253 "0".repeat(int_part_len - digits.len())
254 )
255 } else {
256 let (int_part, frac_part) = digits.split_at(int_part_len);
257 format!("{}{}.{}", sign, int_part, frac_part)
258 }
259 }
260 }
261}
262
263fn value_to_complex(v: Value) -> Result<Complex, Value> {
265 match v {
266 Value::Number(n) | Value::Date(n) => Ok(Complex::new(n, 0.0)),
267 Value::Text(s) => {
268 parse_complex(&s).ok_or(Value::Error(ErrorKind::Num))
269 }
270 Value::Error(_) => Err(v),
271 Value::Bool(_) => Err(Value::Error(ErrorKind::Num)),
273 _ => {
274 match to_number(v) {
275 Ok(n) => Ok(Complex::new(n, 0.0)),
276 Err(e) => Err(e),
277 }
278 }
279 }
280}
281
282fn get_suffix(v: &Value) -> char {
284 if let Value::Text(s) = v {
285 if s.ends_with('j') { return 'j'; }
286 }
287 'i'
288}
289
290fn determine_suffix(args: &[Value]) -> Result<char, Value> {
295 let mut found: Option<char> = None;
296 for arg in args {
297 let s = match arg {
298 Value::Text(s) => s,
299 _ => continue,
300 };
301 let suffix = if s.ends_with('i') {
303 'i'
304 } else if s.ends_with('j') {
305 'j'
306 } else {
307 continue; };
309 match found {
310 None => found = Some(suffix),
311 Some(existing) if existing != suffix => {
312 return Err(Value::Error(ErrorKind::Num));
313 }
314 _ => {}
315 }
316 }
317 Ok(found.unwrap_or('i'))
318}
319
320pub fn complex_fn(args: &[Value]) -> Value {
324 if let Some(err) = check_arity(args, 2, 3) {
325 return err;
326 }
327 let re = match to_number(args[0].clone()) {
328 Err(e) => return e,
329 Ok(v) => v,
330 };
331 let im = match to_number(args[1].clone()) {
332 Err(e) => return e,
333 Ok(v) => v,
334 };
335 let suffix = if args.len() == 3 {
336 match to_string_val(args[2].clone()) {
337 Err(e) => return e,
338 Ok(s) => {
339 if s == "i" || s == "j" {
340 s.chars().next().unwrap()
341 } else {
342 return Value::Error(ErrorKind::Value);
343 }
344 }
345 }
346 } else {
347 'i'
348 };
349 format_complex(Complex::new(re, im), suffix)
350}
351
352pub fn imreal_fn(args: &[Value]) -> Value {
356 if let Some(err) = check_arity(args, 1, 1) {
357 return err;
358 }
359 match value_to_complex(args[0].clone()) {
360 Err(e) => e,
361 Ok(c) => Value::Number(c.re),
362 }
363}
364
365pub fn imaginary_fn(args: &[Value]) -> Value {
367 if let Some(err) = check_arity(args, 1, 1) {
368 return err;
369 }
370 match value_to_complex(args[0].clone()) {
371 Err(e) => e,
372 Ok(c) => Value::Number(c.im),
373 }
374}
375
376pub fn imabs_fn(args: &[Value]) -> Value {
380 if let Some(err) = check_arity(args, 1, 1) {
381 return err;
382 }
383 match value_to_complex(args[0].clone()) {
384 Err(e) => e,
385 Ok(c) => Value::Number(c.abs()),
386 }
387}
388
389pub fn improduct_fn(args: &[Value]) -> Value {
393 if let Some(err) = check_arity(args, 1, usize::MAX) {
394 return err;
395 }
396 let suffix = match determine_suffix(args) {
398 Err(e) => return e,
399 Ok(s) => s,
400 };
401 let mut result = Complex::new(1.0, 0.0);
402 for arg in args {
403 match value_to_complex(arg.clone()) {
404 Err(e) => return e,
405 Ok(c) => result = result.mul(c),
406 }
407 }
408 format_complex(result, suffix)
409}
410
411pub fn imsub_fn(args: &[Value]) -> Value {
415 if let Some(err) = check_arity(args, 2, 2) {
416 return err;
417 }
418 let suffix = match determine_suffix(args) {
420 Err(e) => return e,
421 Ok(s) => s,
422 };
423 let a = match value_to_complex(args[0].clone()) {
424 Err(e) => return e,
425 Ok(c) => c,
426 };
427 let b = match value_to_complex(args[1].clone()) {
428 Err(e) => return e,
429 Ok(c) => c,
430 };
431 format_complex(Complex::new(a.re - b.re, a.im - b.im), suffix)
432}
433
434pub fn imsum_fn(args: &[Value]) -> Value {
438 if let Some(err) = check_arity(args, 1, usize::MAX) {
439 return err;
440 }
441 let suffix = match determine_suffix(args) {
443 Err(e) => return e,
444 Ok(s) => s,
445 };
446 let mut re = 0.0f64;
447 let mut im = 0.0f64;
448 for arg in args {
449 match value_to_complex(arg.clone()) {
450 Err(e) => return e,
451 Ok(c) => {
452 re += c.re;
453 im += c.im;
454 }
455 }
456 }
457 format_complex(Complex::new(re, im), suffix)
458}
459
460pub fn imdiv_fn(args: &[Value]) -> Value {
464 if let Some(err) = check_arity(args, 2, 2) {
465 return err;
466 }
467 let suffix = match determine_suffix(args) {
469 Err(e) => return e,
470 Ok(s) => s,
471 };
472 let a = match value_to_complex(args[0].clone()) {
473 Err(e) => return e,
474 Ok(c) => c,
475 };
476 let b = match value_to_complex(args[1].clone()) {
477 Err(e) => return e,
478 Ok(c) => c,
479 };
480 let denom = b.re * b.re + b.im * b.im;
481 if denom == 0.0 {
482 return Value::Error(ErrorKind::DivByZero);
483 }
484 let re = (a.re * b.re + a.im * b.im) / denom;
485 let im = (a.im * b.re - a.re * b.im) / denom;
486 format_complex(Complex::new(re, im), suffix)
487}
488
489pub fn imconjugate_fn(args: &[Value]) -> Value {
493 if let Some(err) = check_arity(args, 1, 1) {
494 return err;
495 }
496 let suffix = get_suffix(&args[0]);
497 match value_to_complex(args[0].clone()) {
498 Err(e) => e,
499 Ok(c) => format_complex(Complex::new(c.re, -c.im), suffix),
500 }
501}
502
503pub fn imargument_fn(args: &[Value]) -> Value {
507 if let Some(err) = check_arity(args, 1, 1) {
508 return err;
509 }
510 match value_to_complex(args[0].clone()) {
511 Err(e) => e,
512 Ok(c) => {
513 if c.re == 0.0 && c.im == 0.0 {
514 Value::Error(ErrorKind::DivByZero)
515 } else {
516 Value::Number(c.arg())
517 }
518 }
519 }
520}
521
522pub fn imln_fn(args: &[Value]) -> Value {
527 if let Some(err) = check_arity(args, 1, 1) {
528 return err;
529 }
530 match value_to_complex(args[0].clone()) {
531 Err(e) => e,
532 Ok(c) => match c.ln() {
533 None => Value::Error(ErrorKind::DivByZero),
534 Some(result) => format_complex(result, 'i'),
535 },
536 }
537}
538
539pub fn imlog10_fn(args: &[Value]) -> Value {
543 if let Some(err) = check_arity(args, 1, 1) {
544 return err;
545 }
546 match value_to_complex(args[0].clone()) {
547 Err(e) => e,
548 Ok(c) => match c.ln() {
549 None => Value::Error(ErrorKind::DivByZero),
550 Some(result) => {
551 let ln10 = libm::log(10.0f64);
552 format_complex(Complex::new(result.re / ln10, result.im / ln10), 'i')
553 }
554 },
555 }
556}
557
558pub fn imlog2_fn(args: &[Value]) -> Value {
560 if let Some(err) = check_arity(args, 1, 1) {
561 return err;
562 }
563 match value_to_complex(args[0].clone()) {
564 Err(e) => e,
565 Ok(c) => match c.ln() {
566 None => Value::Error(ErrorKind::DivByZero),
567 Some(result) => {
568 let ln2 = libm::log(2.0f64);
569 format_complex(Complex::new(result.re / ln2, result.im / ln2), 'i')
570 }
571 },
572 }
573}
574
575pub fn imlog_fn(args: &[Value]) -> Value {
577 if let Some(err) = check_arity(args, 2, 2) {
578 return err;
579 }
580 let c = match value_to_complex(args[0].clone()) {
581 Err(e) => return e,
582 Ok(v) => v,
583 };
584 let base = match to_number(args[1].clone()) {
585 Err(e) => return e,
586 Ok(v) => v,
587 };
588 if base <= 0.0 || base == 1.0 {
589 return Value::Error(ErrorKind::Num);
590 }
591 match c.ln() {
592 None => Value::Error(ErrorKind::DivByZero),
593 Some(result) => {
594 let ln_base = libm::log(base);
595 format_complex(Complex::new(result.re / ln_base, result.im / ln_base), 'i')
596 }
597 }
598}
599
600pub fn imexp_fn(args: &[Value]) -> Value {
604 if let Some(err) = check_arity(args, 1, 1) {
605 return err;
606 }
607 let suffix = get_suffix(&args[0]);
608 match value_to_complex(args[0].clone()) {
609 Err(e) => e,
610 Ok(c) => {
611 let scale = libm::exp(c.re);
612 format_complex(Complex::new(scale * libm::cos(c.im), scale * libm::sin(c.im)), suffix)
613 }
614 }
615}
616
617pub fn impower_fn(args: &[Value]) -> Value {
621 if let Some(err) = check_arity(args, 2, 2) {
622 return err;
623 }
624 let base = match value_to_complex(args[0].clone()) {
625 Err(e) => return e,
626 Ok(c) => c,
627 };
628 let exp_n = match to_number(args[1].clone()) {
632 Err(e) => return e,
633 Ok(v) => v,
634 };
635 let exp = Complex::new(exp_n, 0.0);
636 let suffix = get_suffix(&args[0]);
637 match base.pow(exp) {
638 None => Value::Error(ErrorKind::Num),
639 Some(mut result) => {
640 if result.re.round() != 0.0
646 && (result.re.round() - result.re).abs() < 1e-9 * result.re.abs().max(1.0)
647 {
648 result.re = result.re.round();
649 }
650 if result.im.round() != 0.0
651 && (result.im.round() - result.im).abs() < 1e-9 * result.im.abs().max(1.0)
652 {
653 result.im = result.im.round();
654 }
655 format_complex(result, suffix)
656 }
657 }
658}
659
660pub fn imsqrt_fn(args: &[Value]) -> Value {
664 if let Some(err) = check_arity(args, 1, 1) {
665 return err;
666 }
667 let suffix = get_suffix(&args[0]);
668 match value_to_complex(args[0].clone()) {
669 Err(e) => e,
670 Ok(c) => format_complex(c.sqrt(), suffix),
671 }
672}
673
674pub fn imsin_fn(args: &[Value]) -> Value {
678 if let Some(err) = check_arity(args, 1, 1) {
679 return err;
680 }
681 let suffix = get_suffix(&args[0]);
682 match value_to_complex(args[0].clone()) {
683 Err(e) => e,
684 Ok(c) => {
685 let re = libm::sin(c.re) * libm::cosh(c.im);
686 let im = libm::cos(c.re) * libm::sinh(c.im);
687 format_complex(Complex::new(re, im), suffix)
688 }
689 }
690}
691
692pub fn imcos_fn(args: &[Value]) -> Value {
694 if let Some(err) = check_arity(args, 1, 1) {
695 return err;
696 }
697 let suffix = get_suffix(&args[0]);
698 match value_to_complex(args[0].clone()) {
699 Err(e) => e,
700 Ok(c) => {
701 let re = libm::cos(c.re) * libm::cosh(c.im);
702 let im = -(libm::sin(c.re) * libm::sinh(c.im));
703 format_complex(Complex::new(re, im), suffix)
704 }
705 }
706}
707
708pub fn imtan_fn(args: &[Value]) -> Value {
712 if let Some(err) = check_arity(args, 1, 1) {
713 return err;
714 }
715 let suffix = get_suffix(&args[0]);
716 match value_to_complex(args[0].clone()) {
717 Err(e) => e,
718 Ok(c) => {
719 let a2 = 2.0 * c.re;
720 let b2 = 2.0 * c.im;
721 let denom = libm::cos(a2) + libm::cosh(b2);
722 if denom == 0.0 {
723 return Value::Error(ErrorKind::DivByZero);
724 }
725 let re = libm::sin(a2) / denom;
726 let im = libm::sinh(b2) / denom;
727 format_complex(Complex::new(re, im), suffix)
728 }
729 }
730}
731
732pub fn imcot_fn(args: &[Value]) -> Value {
736 if let Some(err) = check_arity(args, 1, 1) {
737 return err;
738 }
739 let suffix = get_suffix(&args[0]);
740 match value_to_complex(args[0].clone()) {
741 Err(e) => e,
742 Ok(c) => {
743 let a2 = 2.0 * c.re;
744 let b2 = 2.0 * c.im;
745 let denom = libm::cosh(b2) - libm::cos(a2);
746 if denom == 0.0 {
747 return Value::Error(ErrorKind::DivByZero);
748 }
749 let re = libm::sin(a2) / denom;
750 let im = -(libm::sinh(b2) / denom);
751 format_complex(Complex::new(re, im), suffix)
752 }
753 }
754}
755
756pub fn imcsc_fn(args: &[Value]) -> Value {
758 if let Some(err) = check_arity(args, 1, 1) {
759 return err;
760 }
761 let suffix = get_suffix(&args[0]);
762 match value_to_complex(args[0].clone()) {
763 Err(e) => e,
764 Ok(c) => {
765 let sin_re = libm::sin(c.re) * libm::cosh(c.im);
766 let sin_im = libm::cos(c.re) * libm::sinh(c.im);
767 let denom = sin_re * sin_re + sin_im * sin_im;
768 if denom == 0.0 {
769 return Value::Error(ErrorKind::Num);
770 }
771 let re = sin_re / denom;
772 let im = -sin_im / denom;
773 format_complex(Complex::new(re, im), suffix)
774 }
775 }
776}
777
778pub fn imsec_fn(args: &[Value]) -> Value {
780 if let Some(err) = check_arity(args, 1, 1) {
781 return err;
782 }
783 let suffix = get_suffix(&args[0]);
784 match value_to_complex(args[0].clone()) {
785 Err(e) => e,
786 Ok(c) => {
787 let cos_re = libm::cos(c.re) * libm::cosh(c.im);
788 let cos_im = -(libm::sin(c.re) * libm::sinh(c.im));
789 let denom = cos_re * cos_re + cos_im * cos_im;
790 if denom == 0.0 {
791 return Value::Error(ErrorKind::DivByZero);
792 }
793 let re = cos_re / denom;
794 let im = -cos_im / denom;
795 format_complex(Complex::new(re, im), suffix)
796 }
797 }
798}
799
800pub fn imsinh_fn(args: &[Value]) -> Value {
804 if let Some(err) = check_arity(args, 1, 1) {
805 return err;
806 }
807 let suffix = get_suffix(&args[0]);
808 match value_to_complex(args[0].clone()) {
809 Err(e) => e,
810 Ok(c) => {
811 let re = libm::sinh(c.re) * libm::cos(c.im);
812 let im = libm::cosh(c.re) * libm::sin(c.im);
813 format_complex(Complex::new(re, im), suffix)
814 }
815 }
816}
817
818pub fn imcosh_fn(args: &[Value]) -> Value {
820 if let Some(err) = check_arity(args, 1, 1) {
821 return err;
822 }
823 let suffix = get_suffix(&args[0]);
824 match value_to_complex(args[0].clone()) {
825 Err(e) => e,
826 Ok(c) => {
827 let re = libm::cosh(c.re) * libm::cos(c.im);
828 let im = libm::sinh(c.re) * libm::sin(c.im);
829 format_complex(Complex::new(re, im), suffix)
830 }
831 }
832}
833
834pub fn imtanh_fn(args: &[Value]) -> Value {
838 if let Some(err) = check_arity(args, 1, 1) {
839 return err;
840 }
841 let suffix = get_suffix(&args[0]);
842 match value_to_complex(args[0].clone()) {
843 Err(e) => e,
844 Ok(c) => {
845 let a2 = 2.0 * c.re;
846 let b2 = 2.0 * c.im;
847 let denom = libm::cosh(a2) + libm::cos(b2);
848 if denom == 0.0 {
849 return Value::Error(ErrorKind::DivByZero);
850 }
851 let re = libm::sinh(a2) / denom;
852 let im = libm::sin(b2) / denom;
853 if im == 0.0 {
854 return Value::Text(format_num(re));
855 }
856 format_complex(Complex::new(re, im), suffix)
857 }
858 }
859}
860
861pub fn imcoth_fn(args: &[Value]) -> Value {
865 if let Some(err) = check_arity(args, 1, 1) {
866 return err;
867 }
868 let suffix = get_suffix(&args[0]);
869 match value_to_complex(args[0].clone()) {
870 Err(e) => e,
871 Ok(c) => {
872 let a2 = 2.0 * c.re;
873 let b2 = 2.0 * c.im;
874 let denom = libm::cosh(a2) - libm::cos(b2);
875 if denom == 0.0 {
876 return Value::Error(ErrorKind::DivByZero);
877 }
878 let re = libm::sinh(a2) / denom;
879 let im = -(libm::sin(b2) / denom);
880 if im == 0.0 {
881 return Value::Text(format_num(re));
882 }
883 format_complex(Complex::new(re, im), suffix)
884 }
885 }
886}
887
888pub fn imcsch_fn(args: &[Value]) -> Value {
890 if let Some(err) = check_arity(args, 1, 1) {
891 return err;
892 }
893 let suffix = get_suffix(&args[0]);
894 match value_to_complex(args[0].clone()) {
895 Err(e) => e,
896 Ok(c) => {
897 let sinh_re = libm::sinh(c.re) * libm::cos(c.im);
898 let sinh_im = libm::cosh(c.re) * libm::sin(c.im);
899 let denom = sinh_re * sinh_re + sinh_im * sinh_im;
900 if denom == 0.0 {
901 return Value::Error(ErrorKind::DivByZero);
902 }
903 let re = sinh_re / denom;
904 let im = -sinh_im / denom;
905 format_complex(Complex::new(re, im), suffix)
906 }
907 }
908}
909
910pub fn imsech_fn(args: &[Value]) -> Value {
912 if let Some(err) = check_arity(args, 1, 1) {
913 return err;
914 }
915 let suffix = get_suffix(&args[0]);
916 match value_to_complex(args[0].clone()) {
917 Err(e) => e,
918 Ok(c) => {
919 let cosh_re = libm::cosh(c.re) * libm::cos(c.im);
920 let cosh_im = libm::sinh(c.re) * libm::sin(c.im);
921 let denom = cosh_re * cosh_re + cosh_im * cosh_im;
922 if denom == 0.0 {
923 return Value::Error(ErrorKind::DivByZero);
924 }
925 let re = cosh_re / denom;
926 let im = -cosh_im / denom;
927 format_complex(Complex::new(re, im), suffix)
928 }
929 }
930}
931
932#[cfg(test)]
933mod tests;