1use super::utils::{ARG_ANY_TWO, ARG_NUM_LENIENT_TWO, coerce_num};
5use crate::args::ArgSchema;
6use crate::function::Function;
7use crate::traits::{ArgumentHandle, FunctionContext};
8use formualizer_common::{ExcelError, LiteralValue};
9use formualizer_macros::func_caps;
10
11fn to_bitwise_int(v: &LiteralValue) -> Result<i64, ExcelError> {
14 let n = coerce_num(v)?;
15 if n < 0.0 || n != n.trunc() || n >= 281474976710656.0 {
16 return Err(ExcelError::new_num());
18 }
19 Ok(n as i64)
20}
21
22#[derive(Debug)]
26pub struct BitAndFn;
27impl Function for BitAndFn {
28 func_caps!(PURE);
29 fn name(&self) -> &'static str {
30 "BITAND"
31 }
32 fn min_args(&self) -> usize {
33 2
34 }
35 fn arg_schema(&self) -> &'static [ArgSchema] {
36 &ARG_NUM_LENIENT_TWO[..]
37 }
38 fn eval<'a, 'b, 'c>(
39 &self,
40 args: &'c [ArgumentHandle<'a, 'b>],
41 _ctx: &dyn FunctionContext<'b>,
42 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
43 let a = match args[0].value()?.into_literal() {
44 LiteralValue::Error(e) => {
45 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
46 }
47 other => match to_bitwise_int(&other) {
48 Ok(n) => n,
49 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
50 },
51 };
52 let b = match args[1].value()?.into_literal() {
53 LiteralValue::Error(e) => {
54 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
55 }
56 other => match to_bitwise_int(&other) {
57 Ok(n) => n,
58 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
59 },
60 };
61 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
62 (a & b) as f64,
63 )))
64 }
65}
66
67#[derive(Debug)]
71pub struct BitOrFn;
72impl Function for BitOrFn {
73 func_caps!(PURE);
74 fn name(&self) -> &'static str {
75 "BITOR"
76 }
77 fn min_args(&self) -> usize {
78 2
79 }
80 fn arg_schema(&self) -> &'static [ArgSchema] {
81 &ARG_NUM_LENIENT_TWO[..]
82 }
83 fn eval<'a, 'b, 'c>(
84 &self,
85 args: &'c [ArgumentHandle<'a, 'b>],
86 _ctx: &dyn FunctionContext<'b>,
87 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
88 let a = match args[0].value()?.into_literal() {
89 LiteralValue::Error(e) => {
90 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
91 }
92 other => match to_bitwise_int(&other) {
93 Ok(n) => n,
94 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
95 },
96 };
97 let b = match args[1].value()?.into_literal() {
98 LiteralValue::Error(e) => {
99 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
100 }
101 other => match to_bitwise_int(&other) {
102 Ok(n) => n,
103 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
104 },
105 };
106 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
107 (a | b) as f64,
108 )))
109 }
110}
111
112#[derive(Debug)]
116pub struct BitXorFn;
117impl Function for BitXorFn {
118 func_caps!(PURE);
119 fn name(&self) -> &'static str {
120 "BITXOR"
121 }
122 fn min_args(&self) -> usize {
123 2
124 }
125 fn arg_schema(&self) -> &'static [ArgSchema] {
126 &ARG_NUM_LENIENT_TWO[..]
127 }
128 fn eval<'a, 'b, 'c>(
129 &self,
130 args: &'c [ArgumentHandle<'a, 'b>],
131 _ctx: &dyn FunctionContext<'b>,
132 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
133 let a = match args[0].value()?.into_literal() {
134 LiteralValue::Error(e) => {
135 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
136 }
137 other => match to_bitwise_int(&other) {
138 Ok(n) => n,
139 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
140 },
141 };
142 let b = match args[1].value()?.into_literal() {
143 LiteralValue::Error(e) => {
144 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
145 }
146 other => match to_bitwise_int(&other) {
147 Ok(n) => n,
148 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
149 },
150 };
151 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
152 (a ^ b) as f64,
153 )))
154 }
155}
156
157#[derive(Debug)]
161pub struct BitLShiftFn;
162impl Function for BitLShiftFn {
163 func_caps!(PURE);
164 fn name(&self) -> &'static str {
165 "BITLSHIFT"
166 }
167 fn min_args(&self) -> usize {
168 2
169 }
170 fn arg_schema(&self) -> &'static [ArgSchema] {
171 &ARG_NUM_LENIENT_TWO[..]
172 }
173 fn eval<'a, 'b, 'c>(
174 &self,
175 args: &'c [ArgumentHandle<'a, 'b>],
176 _ctx: &dyn FunctionContext<'b>,
177 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
178 let n = match args[0].value()?.into_literal() {
179 LiteralValue::Error(e) => {
180 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
181 }
182 other => match to_bitwise_int(&other) {
183 Ok(n) => n,
184 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
185 },
186 };
187 let shift = match args[1].value()?.into_literal() {
188 LiteralValue::Error(e) => {
189 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
190 }
191 other => coerce_num(&other)? as i32,
192 };
193
194 let result = if shift >= 0 {
196 if shift >= 48 {
197 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
198 ExcelError::new_num(),
199 )));
200 }
201 let shifted = n << shift;
202 if shifted >= 281474976710656 {
204 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
205 ExcelError::new_num(),
206 )));
207 }
208 shifted
209 } else {
210 let rshift = (-shift) as u32;
211 if rshift >= 48 { 0 } else { n >> rshift }
212 };
213
214 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
215 result as f64,
216 )))
217 }
218}
219
220#[derive(Debug)]
224pub struct BitRShiftFn;
225impl Function for BitRShiftFn {
226 func_caps!(PURE);
227 fn name(&self) -> &'static str {
228 "BITRSHIFT"
229 }
230 fn min_args(&self) -> usize {
231 2
232 }
233 fn arg_schema(&self) -> &'static [ArgSchema] {
234 &ARG_NUM_LENIENT_TWO[..]
235 }
236 fn eval<'a, 'b, 'c>(
237 &self,
238 args: &'c [ArgumentHandle<'a, 'b>],
239 _ctx: &dyn FunctionContext<'b>,
240 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
241 let n = match args[0].value()?.into_literal() {
242 LiteralValue::Error(e) => {
243 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
244 }
245 other => match to_bitwise_int(&other) {
246 Ok(n) => n,
247 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
248 },
249 };
250 let shift = match args[1].value()?.into_literal() {
251 LiteralValue::Error(e) => {
252 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
253 }
254 other => coerce_num(&other)? as i32,
255 };
256
257 let result = if shift >= 0 {
259 if shift >= 48 { 0 } else { n >> shift }
260 } else {
261 let lshift = (-shift) as u32;
262 if lshift >= 48 {
263 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
264 ExcelError::new_num(),
265 )));
266 }
267 let shifted = n << lshift;
268 if shifted >= 281474976710656 {
270 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
271 ExcelError::new_num(),
272 )));
273 }
274 shifted
275 };
276
277 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
278 result as f64,
279 )))
280 }
281}
282
283use super::utils::ARG_ANY_ONE;
286
287fn coerce_base_text(v: &LiteralValue) -> Result<String, ExcelError> {
289 match v {
290 LiteralValue::Text(s) => Ok(s.clone()),
291 LiteralValue::Int(i) => Ok(i.to_string()),
292 LiteralValue::Number(n) => Ok((*n as i64).to_string()),
293 LiteralValue::Error(e) => Err(e.clone()),
294 _ => Err(ExcelError::new_value()),
295 }
296}
297
298#[derive(Debug)]
300pub struct Bin2DecFn;
301impl Function for Bin2DecFn {
302 func_caps!(PURE);
303 fn name(&self) -> &'static str {
304 "BIN2DEC"
305 }
306 fn min_args(&self) -> usize {
307 1
308 }
309 fn arg_schema(&self) -> &'static [ArgSchema] {
310 &ARG_ANY_ONE[..]
311 }
312 fn eval<'a, 'b, 'c>(
313 &self,
314 args: &'c [ArgumentHandle<'a, 'b>],
315 _ctx: &dyn FunctionContext<'b>,
316 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
317 let text = match args[0].value()?.into_literal() {
318 LiteralValue::Error(e) => {
319 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
320 }
321 other => match coerce_base_text(&other) {
322 Ok(s) => s,
323 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
324 },
325 };
326
327 if text.len() > 10 || !text.chars().all(|c| c == '0' || c == '1') {
329 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
330 ExcelError::new_num(),
331 )));
332 }
333
334 let result = if text.len() == 10 && text.starts_with('1') {
336 let val = i64::from_str_radix(&text, 2).unwrap_or(0);
338 val - 1024 } else {
340 i64::from_str_radix(&text, 2).unwrap_or(0)
341 };
342
343 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
344 result as f64,
345 )))
346 }
347}
348
349#[derive(Debug)]
351pub struct Dec2BinFn;
352impl Function for Dec2BinFn {
353 func_caps!(PURE);
354 fn name(&self) -> &'static str {
355 "DEC2BIN"
356 }
357 fn min_args(&self) -> usize {
358 1
359 }
360 fn variadic(&self) -> bool {
361 true
362 }
363 fn arg_schema(&self) -> &'static [ArgSchema] {
364 &ARG_NUM_LENIENT_TWO[..]
365 }
366 fn eval<'a, 'b, 'c>(
367 &self,
368 args: &'c [ArgumentHandle<'a, 'b>],
369 _ctx: &dyn FunctionContext<'b>,
370 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
371 let n = match args[0].value()?.into_literal() {
372 LiteralValue::Error(e) => {
373 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
374 }
375 other => coerce_num(&other)? as i64,
376 };
377
378 if !(-512..=511).contains(&n) {
380 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
381 ExcelError::new_num(),
382 )));
383 }
384
385 let places = if args.len() > 1 {
386 match args[1].value()?.into_literal() {
387 LiteralValue::Error(e) => {
388 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
389 }
390 other => Some(coerce_num(&other)? as usize),
391 }
392 } else {
393 None
394 };
395
396 let binary = if n >= 0 {
397 format!("{:b}", n)
398 } else {
399 format!("{:010b}", (n + 1024) as u64)
401 };
402
403 let result = if let Some(p) = places {
404 if p < binary.len() || p > 10 {
405 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
406 ExcelError::new_num(),
407 )));
408 }
409 format!("{:0>width$}", binary, width = p)
410 } else {
411 binary
412 };
413
414 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
415 }
416}
417
418#[derive(Debug)]
420pub struct Hex2DecFn;
421impl Function for Hex2DecFn {
422 func_caps!(PURE);
423 fn name(&self) -> &'static str {
424 "HEX2DEC"
425 }
426 fn min_args(&self) -> usize {
427 1
428 }
429 fn arg_schema(&self) -> &'static [ArgSchema] {
430 &ARG_ANY_ONE[..]
431 }
432 fn eval<'a, 'b, 'c>(
433 &self,
434 args: &'c [ArgumentHandle<'a, 'b>],
435 _ctx: &dyn FunctionContext<'b>,
436 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
437 let text = match args[0].value()?.into_literal() {
438 LiteralValue::Error(e) => {
439 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
440 }
441 other => match coerce_base_text(&other) {
442 Ok(s) => s.to_uppercase(),
443 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
444 },
445 };
446
447 if text.len() > 10 || !text.chars().all(|c| c.is_ascii_hexdigit()) {
449 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
450 ExcelError::new_num(),
451 )));
452 }
453
454 let result = if text.len() == 10 && text.starts_with(|c| c >= '8') {
455 let val = i64::from_str_radix(&text, 16).unwrap_or(0);
457 val - (1i64 << 40)
458 } else {
459 i64::from_str_radix(&text, 16).unwrap_or(0)
460 };
461
462 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
463 result as f64,
464 )))
465 }
466}
467
468#[derive(Debug)]
470pub struct Dec2HexFn;
471impl Function for Dec2HexFn {
472 func_caps!(PURE);
473 fn name(&self) -> &'static str {
474 "DEC2HEX"
475 }
476 fn min_args(&self) -> usize {
477 1
478 }
479 fn variadic(&self) -> bool {
480 true
481 }
482 fn arg_schema(&self) -> &'static [ArgSchema] {
483 &ARG_NUM_LENIENT_TWO[..]
484 }
485 fn eval<'a, 'b, 'c>(
486 &self,
487 args: &'c [ArgumentHandle<'a, 'b>],
488 _ctx: &dyn FunctionContext<'b>,
489 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
490 let n = match args[0].value()?.into_literal() {
491 LiteralValue::Error(e) => {
492 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
493 }
494 other => coerce_num(&other)? as i64,
495 };
496
497 if !(-(1i64 << 39)..=(1i64 << 39) - 1).contains(&n) {
499 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
500 ExcelError::new_num(),
501 )));
502 }
503
504 let places = if args.len() > 1 {
505 match args[1].value()?.into_literal() {
506 LiteralValue::Error(e) => {
507 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
508 }
509 other => Some(coerce_num(&other)? as usize),
510 }
511 } else {
512 None
513 };
514
515 let hex = if n >= 0 {
516 format!("{:X}", n)
517 } else {
518 format!("{:010X}", (n + (1i64 << 40)) as u64)
520 };
521
522 let result = if let Some(p) = places {
523 if p < hex.len() || p > 10 {
524 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
525 ExcelError::new_num(),
526 )));
527 }
528 format!("{:0>width$}", hex, width = p)
529 } else {
530 hex
531 };
532
533 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
534 }
535}
536
537#[derive(Debug)]
539pub struct Oct2DecFn;
540impl Function for Oct2DecFn {
541 func_caps!(PURE);
542 fn name(&self) -> &'static str {
543 "OCT2DEC"
544 }
545 fn min_args(&self) -> usize {
546 1
547 }
548 fn arg_schema(&self) -> &'static [ArgSchema] {
549 &ARG_ANY_ONE[..]
550 }
551 fn eval<'a, 'b, 'c>(
552 &self,
553 args: &'c [ArgumentHandle<'a, 'b>],
554 _ctx: &dyn FunctionContext<'b>,
555 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
556 let text = match args[0].value()?.into_literal() {
557 LiteralValue::Error(e) => {
558 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
559 }
560 other => match coerce_base_text(&other) {
561 Ok(s) => s,
562 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
563 },
564 };
565
566 if text.len() > 10 || !text.chars().all(|c| ('0'..='7').contains(&c)) {
568 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
569 ExcelError::new_num(),
570 )));
571 }
572
573 let result = if text.len() == 10 && text.starts_with(|c| c >= '4') {
574 let val = i64::from_str_radix(&text, 8).unwrap_or(0);
576 val - (1i64 << 30)
577 } else {
578 i64::from_str_radix(&text, 8).unwrap_or(0)
579 };
580
581 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
582 result as f64,
583 )))
584 }
585}
586
587#[derive(Debug)]
589pub struct Dec2OctFn;
590impl Function for Dec2OctFn {
591 func_caps!(PURE);
592 fn name(&self) -> &'static str {
593 "DEC2OCT"
594 }
595 fn min_args(&self) -> usize {
596 1
597 }
598 fn variadic(&self) -> bool {
599 true
600 }
601 fn arg_schema(&self) -> &'static [ArgSchema] {
602 &ARG_NUM_LENIENT_TWO[..]
603 }
604 fn eval<'a, 'b, 'c>(
605 &self,
606 args: &'c [ArgumentHandle<'a, 'b>],
607 _ctx: &dyn FunctionContext<'b>,
608 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
609 let n = match args[0].value()?.into_literal() {
610 LiteralValue::Error(e) => {
611 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
612 }
613 other => coerce_num(&other)? as i64,
614 };
615
616 if !(-(1i64 << 29)..=(1i64 << 29) - 1).contains(&n) {
618 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
619 ExcelError::new_num(),
620 )));
621 }
622
623 let places = if args.len() > 1 {
624 match args[1].value()?.into_literal() {
625 LiteralValue::Error(e) => {
626 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
627 }
628 other => Some(coerce_num(&other)? as usize),
629 }
630 } else {
631 None
632 };
633
634 let octal = if n >= 0 {
635 format!("{:o}", n)
636 } else {
637 format!("{:010o}", (n + (1i64 << 30)) as u64)
639 };
640
641 let result = if let Some(p) = places {
642 if p < octal.len() || p > 10 {
643 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
644 ExcelError::new_num(),
645 )));
646 }
647 format!("{:0>width$}", octal, width = p)
648 } else {
649 octal
650 };
651
652 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
653 }
654}
655
656#[derive(Debug)]
660pub struct Bin2HexFn;
661impl Function for Bin2HexFn {
662 func_caps!(PURE);
663 fn name(&self) -> &'static str {
664 "BIN2HEX"
665 }
666 fn min_args(&self) -> usize {
667 1
668 }
669 fn variadic(&self) -> bool {
670 true
671 }
672 fn arg_schema(&self) -> &'static [ArgSchema] {
673 &ARG_NUM_LENIENT_TWO[..]
674 }
675 fn eval<'a, 'b, 'c>(
676 &self,
677 args: &'c [ArgumentHandle<'a, 'b>],
678 _ctx: &dyn FunctionContext<'b>,
679 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
680 let text = match args[0].value()?.into_literal() {
681 LiteralValue::Error(e) => {
682 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
683 }
684 other => match coerce_base_text(&other) {
685 Ok(s) => s,
686 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
687 },
688 };
689
690 if text.len() > 10 || !text.chars().all(|c| c == '0' || c == '1') {
691 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
692 ExcelError::new_num(),
693 )));
694 }
695
696 let dec = if text.len() == 10 && text.starts_with('1') {
698 let val = i64::from_str_radix(&text, 2).unwrap_or(0);
699 val - 1024
700 } else {
701 i64::from_str_radix(&text, 2).unwrap_or(0)
702 };
703
704 let places = if args.len() > 1 {
705 match args[1].value()?.into_literal() {
706 LiteralValue::Error(e) => {
707 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
708 }
709 other => Some(coerce_num(&other)? as usize),
710 }
711 } else {
712 None
713 };
714
715 let hex = if dec >= 0 {
716 format!("{:X}", dec)
717 } else {
718 format!("{:010X}", (dec + (1i64 << 40)) as u64)
719 };
720
721 let result = if let Some(p) = places {
722 if p < hex.len() || p > 10 {
723 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
724 ExcelError::new_num(),
725 )));
726 }
727 format!("{:0>width$}", hex, width = p)
728 } else {
729 hex
730 };
731
732 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
733 }
734}
735
736#[derive(Debug)]
738pub struct Hex2BinFn;
739impl Function for Hex2BinFn {
740 func_caps!(PURE);
741 fn name(&self) -> &'static str {
742 "HEX2BIN"
743 }
744 fn min_args(&self) -> usize {
745 1
746 }
747 fn variadic(&self) -> bool {
748 true
749 }
750 fn arg_schema(&self) -> &'static [ArgSchema] {
751 &ARG_ANY_TWO[..]
752 }
753 fn eval<'a, 'b, 'c>(
754 &self,
755 args: &'c [ArgumentHandle<'a, 'b>],
756 _ctx: &dyn FunctionContext<'b>,
757 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
758 let text = match args[0].value()?.into_literal() {
759 LiteralValue::Error(e) => {
760 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
761 }
762 other => match coerce_base_text(&other) {
763 Ok(s) => s.to_uppercase(),
764 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
765 },
766 };
767
768 if text.len() > 10 || !text.chars().all(|c| c.is_ascii_hexdigit()) {
769 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
770 ExcelError::new_num(),
771 )));
772 }
773
774 let dec = if text.len() == 10 && text.starts_with(|c| c >= '8') {
776 let val = i64::from_str_radix(&text, 16).unwrap_or(0);
777 val - (1i64 << 40)
778 } else {
779 i64::from_str_radix(&text, 16).unwrap_or(0)
780 };
781
782 if !(-512..=511).contains(&dec) {
784 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
785 ExcelError::new_num(),
786 )));
787 }
788
789 let places = if args.len() > 1 {
790 match args[1].value()?.into_literal() {
791 LiteralValue::Error(e) => {
792 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
793 }
794 other => Some(coerce_num(&other)? as usize),
795 }
796 } else {
797 None
798 };
799
800 let binary = if dec >= 0 {
801 format!("{:b}", dec)
802 } else {
803 format!("{:010b}", (dec + 1024) as u64)
804 };
805
806 let result = if let Some(p) = places {
807 if p < binary.len() || p > 10 {
808 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
809 ExcelError::new_num(),
810 )));
811 }
812 format!("{:0>width$}", binary, width = p)
813 } else {
814 binary
815 };
816
817 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
818 }
819}
820
821#[derive(Debug)]
823pub struct Bin2OctFn;
824impl Function for Bin2OctFn {
825 func_caps!(PURE);
826 fn name(&self) -> &'static str {
827 "BIN2OCT"
828 }
829 fn min_args(&self) -> usize {
830 1
831 }
832 fn variadic(&self) -> bool {
833 true
834 }
835 fn arg_schema(&self) -> &'static [ArgSchema] {
836 &ARG_NUM_LENIENT_TWO[..]
837 }
838 fn eval<'a, 'b, 'c>(
839 &self,
840 args: &'c [ArgumentHandle<'a, 'b>],
841 _ctx: &dyn FunctionContext<'b>,
842 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
843 let text = match args[0].value()?.into_literal() {
844 LiteralValue::Error(e) => {
845 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
846 }
847 other => match coerce_base_text(&other) {
848 Ok(s) => s,
849 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
850 },
851 };
852
853 if text.len() > 10 || !text.chars().all(|c| c == '0' || c == '1') {
854 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
855 ExcelError::new_num(),
856 )));
857 }
858
859 let dec = if text.len() == 10 && text.starts_with('1') {
860 let val = i64::from_str_radix(&text, 2).unwrap_or(0);
861 val - 1024
862 } else {
863 i64::from_str_radix(&text, 2).unwrap_or(0)
864 };
865
866 let places = if args.len() > 1 {
867 match args[1].value()?.into_literal() {
868 LiteralValue::Error(e) => {
869 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
870 }
871 other => Some(coerce_num(&other)? as usize),
872 }
873 } else {
874 None
875 };
876
877 let octal = if dec >= 0 {
878 format!("{:o}", dec)
879 } else {
880 format!("{:010o}", (dec + (1i64 << 30)) as u64)
881 };
882
883 let result = if let Some(p) = places {
884 if p < octal.len() || p > 10 {
885 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
886 ExcelError::new_num(),
887 )));
888 }
889 format!("{:0>width$}", octal, width = p)
890 } else {
891 octal
892 };
893
894 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
895 }
896}
897
898#[derive(Debug)]
900pub struct Oct2BinFn;
901impl Function for Oct2BinFn {
902 func_caps!(PURE);
903 fn name(&self) -> &'static str {
904 "OCT2BIN"
905 }
906 fn min_args(&self) -> usize {
907 1
908 }
909 fn variadic(&self) -> bool {
910 true
911 }
912 fn arg_schema(&self) -> &'static [ArgSchema] {
913 &ARG_NUM_LENIENT_TWO[..]
914 }
915 fn eval<'a, 'b, 'c>(
916 &self,
917 args: &'c [ArgumentHandle<'a, 'b>],
918 _ctx: &dyn FunctionContext<'b>,
919 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
920 let text = match args[0].value()?.into_literal() {
921 LiteralValue::Error(e) => {
922 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
923 }
924 other => match coerce_base_text(&other) {
925 Ok(s) => s,
926 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
927 },
928 };
929
930 if text.len() > 10 || !text.chars().all(|c| ('0'..='7').contains(&c)) {
931 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
932 ExcelError::new_num(),
933 )));
934 }
935
936 let dec = if text.len() == 10 && text.starts_with(|c| c >= '4') {
937 let val = i64::from_str_radix(&text, 8).unwrap_or(0);
938 val - (1i64 << 30)
939 } else {
940 i64::from_str_radix(&text, 8).unwrap_or(0)
941 };
942
943 if !(-512..=511).contains(&dec) {
945 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
946 ExcelError::new_num(),
947 )));
948 }
949
950 let places = if args.len() > 1 {
951 match args[1].value()?.into_literal() {
952 LiteralValue::Error(e) => {
953 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
954 }
955 other => Some(coerce_num(&other)? as usize),
956 }
957 } else {
958 None
959 };
960
961 let binary = if dec >= 0 {
962 format!("{:b}", dec)
963 } else {
964 format!("{:010b}", (dec + 1024) as u64)
965 };
966
967 let result = if let Some(p) = places {
968 if p < binary.len() || p > 10 {
969 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
970 ExcelError::new_num(),
971 )));
972 }
973 format!("{:0>width$}", binary, width = p)
974 } else {
975 binary
976 };
977
978 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
979 }
980}
981
982#[derive(Debug)]
984pub struct Hex2OctFn;
985impl Function for Hex2OctFn {
986 func_caps!(PURE);
987 fn name(&self) -> &'static str {
988 "HEX2OCT"
989 }
990 fn min_args(&self) -> usize {
991 1
992 }
993 fn variadic(&self) -> bool {
994 true
995 }
996 fn arg_schema(&self) -> &'static [ArgSchema] {
997 &ARG_ANY_TWO[..]
998 }
999 fn eval<'a, 'b, 'c>(
1000 &self,
1001 args: &'c [ArgumentHandle<'a, 'b>],
1002 _ctx: &dyn FunctionContext<'b>,
1003 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1004 let text = match args[0].value()?.into_literal() {
1005 LiteralValue::Error(e) => {
1006 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1007 }
1008 other => match coerce_base_text(&other) {
1009 Ok(s) => s.to_uppercase(),
1010 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1011 },
1012 };
1013
1014 if text.len() > 10 || !text.chars().all(|c| c.is_ascii_hexdigit()) {
1015 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1016 ExcelError::new_num(),
1017 )));
1018 }
1019
1020 let dec = if text.len() == 10 && text.starts_with(|c| c >= '8') {
1021 let val = i64::from_str_radix(&text, 16).unwrap_or(0);
1022 val - (1i64 << 40)
1023 } else {
1024 i64::from_str_radix(&text, 16).unwrap_or(0)
1025 };
1026
1027 if !(-(1i64 << 29)..=(1i64 << 29) - 1).contains(&dec) {
1029 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1030 ExcelError::new_num(),
1031 )));
1032 }
1033
1034 let places = if args.len() > 1 {
1035 match args[1].value()?.into_literal() {
1036 LiteralValue::Error(e) => {
1037 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1038 }
1039 other => Some(coerce_num(&other)? as usize),
1040 }
1041 } else {
1042 None
1043 };
1044
1045 let octal = if dec >= 0 {
1046 format!("{:o}", dec)
1047 } else {
1048 format!("{:010o}", (dec + (1i64 << 30)) as u64)
1049 };
1050
1051 let result = if let Some(p) = places {
1052 if p < octal.len() || p > 10 {
1053 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1054 ExcelError::new_num(),
1055 )));
1056 }
1057 format!("{:0>width$}", octal, width = p)
1058 } else {
1059 octal
1060 };
1061
1062 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
1063 }
1064}
1065
1066#[derive(Debug)]
1068pub struct Oct2HexFn;
1069impl Function for Oct2HexFn {
1070 func_caps!(PURE);
1071 fn name(&self) -> &'static str {
1072 "OCT2HEX"
1073 }
1074 fn min_args(&self) -> usize {
1075 1
1076 }
1077 fn variadic(&self) -> bool {
1078 true
1079 }
1080 fn arg_schema(&self) -> &'static [ArgSchema] {
1081 &ARG_NUM_LENIENT_TWO[..]
1082 }
1083 fn eval<'a, 'b, 'c>(
1084 &self,
1085 args: &'c [ArgumentHandle<'a, 'b>],
1086 _ctx: &dyn FunctionContext<'b>,
1087 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1088 let text = match args[0].value()?.into_literal() {
1089 LiteralValue::Error(e) => {
1090 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1091 }
1092 other => match coerce_base_text(&other) {
1093 Ok(s) => s,
1094 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1095 },
1096 };
1097
1098 if text.len() > 10 || !text.chars().all(|c| ('0'..='7').contains(&c)) {
1099 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1100 ExcelError::new_num(),
1101 )));
1102 }
1103
1104 let dec = if text.len() == 10 && text.starts_with(|c| c >= '4') {
1105 let val = i64::from_str_radix(&text, 8).unwrap_or(0);
1106 val - (1i64 << 30)
1107 } else {
1108 i64::from_str_radix(&text, 8).unwrap_or(0)
1109 };
1110
1111 let places = if args.len() > 1 {
1112 match args[1].value()?.into_literal() {
1113 LiteralValue::Error(e) => {
1114 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1115 }
1116 other => Some(coerce_num(&other)? as usize),
1117 }
1118 } else {
1119 None
1120 };
1121
1122 let hex = if dec >= 0 {
1123 format!("{:X}", dec)
1124 } else {
1125 format!("{:010X}", (dec + (1i64 << 40)) as u64)
1126 };
1127
1128 let result = if let Some(p) = places {
1129 if p < hex.len() || p > 10 {
1130 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1131 ExcelError::new_num(),
1132 )));
1133 }
1134 format!("{:0>width$}", hex, width = p)
1135 } else {
1136 hex
1137 };
1138
1139 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
1140 }
1141}
1142
1143#[derive(Debug)]
1147pub struct DeltaFn;
1148impl Function for DeltaFn {
1149 func_caps!(PURE);
1150 fn name(&self) -> &'static str {
1151 "DELTA"
1152 }
1153 fn min_args(&self) -> usize {
1154 1
1155 }
1156 fn variadic(&self) -> bool {
1157 true
1158 }
1159 fn arg_schema(&self) -> &'static [ArgSchema] {
1160 &ARG_NUM_LENIENT_TWO[..]
1161 }
1162 fn eval<'a, 'b, 'c>(
1163 &self,
1164 args: &'c [ArgumentHandle<'a, 'b>],
1165 _ctx: &dyn FunctionContext<'b>,
1166 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1167 let n1 = match args[0].value()?.into_literal() {
1168 LiteralValue::Error(e) => {
1169 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1170 }
1171 other => coerce_num(&other)?,
1172 };
1173 let n2 = if args.len() > 1 {
1174 match args[1].value()?.into_literal() {
1175 LiteralValue::Error(e) => {
1176 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1177 }
1178 other => coerce_num(&other)?,
1179 }
1180 } else {
1181 0.0
1182 };
1183
1184 let result = if (n1 - n2).abs() < 1e-12 { 1.0 } else { 0.0 };
1185 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
1186 result,
1187 )))
1188 }
1189}
1190
1191#[derive(Debug)]
1193pub struct GestepFn;
1194impl Function for GestepFn {
1195 func_caps!(PURE);
1196 fn name(&self) -> &'static str {
1197 "GESTEP"
1198 }
1199 fn min_args(&self) -> usize {
1200 1
1201 }
1202 fn variadic(&self) -> bool {
1203 true
1204 }
1205 fn arg_schema(&self) -> &'static [ArgSchema] {
1206 &ARG_NUM_LENIENT_TWO[..]
1207 }
1208 fn eval<'a, 'b, 'c>(
1209 &self,
1210 args: &'c [ArgumentHandle<'a, 'b>],
1211 _ctx: &dyn FunctionContext<'b>,
1212 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1213 let n = match args[0].value()?.into_literal() {
1214 LiteralValue::Error(e) => {
1215 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1216 }
1217 other => coerce_num(&other)?,
1218 };
1219 let step = if args.len() > 1 {
1220 match args[1].value()?.into_literal() {
1221 LiteralValue::Error(e) => {
1222 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1223 }
1224 other => coerce_num(&other)?,
1225 }
1226 } else {
1227 0.0
1228 };
1229
1230 let result = if n >= step { 1.0 } else { 0.0 };
1231 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
1232 result,
1233 )))
1234 }
1235}
1236
1237#[allow(clippy::excessive_precision)]
1244fn erf_approx(x: f64) -> f64 {
1245 let ax = x.abs();
1246
1247 if ax < 0.5 {
1249 const P: [f64; 5] = [
1251 3.20937758913846947e+03,
1252 3.77485237685302021e+02,
1253 1.13864154151050156e+02,
1254 3.16112374387056560e+00,
1255 1.85777706184603153e-01,
1256 ];
1257 const Q: [f64; 5] = [
1258 2.84423748127893300e+03,
1259 1.28261652607737228e+03,
1260 2.44024637934444173e+02,
1261 2.36012909523441209e+01,
1262 1.00000000000000000e+00,
1263 ];
1264
1265 let x2 = x * x;
1266 let p_val = P[4];
1267 let p_val = p_val * x2 + P[3];
1268 let p_val = p_val * x2 + P[2];
1269 let p_val = p_val * x2 + P[1];
1270 let p_val = p_val * x2 + P[0];
1271
1272 let q_val = Q[4];
1273 let q_val = q_val * x2 + Q[3];
1274 let q_val = q_val * x2 + Q[2];
1275 let q_val = q_val * x2 + Q[1];
1276 let q_val = q_val * x2 + Q[0];
1277
1278 return x * p_val / q_val;
1279 }
1280
1281 if ax < 4.0 {
1283 let erfc_val = erfc_mid(ax);
1284 return if x > 0.0 {
1285 1.0 - erfc_val
1286 } else {
1287 erfc_val - 1.0
1288 };
1289 }
1290
1291 let erfc_val = erfc_large(ax);
1293 if x > 0.0 {
1294 1.0 - erfc_val
1295 } else {
1296 erfc_val - 1.0
1297 }
1298}
1299
1300#[allow(clippy::excessive_precision)]
1302fn erfc_mid(x: f64) -> f64 {
1303 const P: [f64; 9] = [
1304 1.23033935479799725e+03,
1305 2.05107837782607147e+03,
1306 1.71204761263407058e+03,
1307 8.81952221241769090e+02,
1308 2.98635138197400131e+02,
1309 6.61191906371416295e+01,
1310 8.88314979438837594e+00,
1311 5.64188496988670089e-01,
1312 2.15311535474403846e-08,
1313 ];
1314 const Q: [f64; 9] = [
1315 1.23033935480374942e+03,
1316 3.43936767414372164e+03,
1317 4.36261909014324716e+03,
1318 3.29079923573345963e+03,
1319 1.62138957456669019e+03,
1320 5.37181101862009858e+02,
1321 1.17693950891312499e+02,
1322 1.57449261107098347e+01,
1323 1.00000000000000000e+00,
1324 ];
1325
1326 let p_val = P[8];
1327 let p_val = p_val * x + P[7];
1328 let p_val = p_val * x + P[6];
1329 let p_val = p_val * x + P[5];
1330 let p_val = p_val * x + P[4];
1331 let p_val = p_val * x + P[3];
1332 let p_val = p_val * x + P[2];
1333 let p_val = p_val * x + P[1];
1334 let p_val = p_val * x + P[0];
1335
1336 let q_val = Q[8];
1337 let q_val = q_val * x + Q[7];
1338 let q_val = q_val * x + Q[6];
1339 let q_val = q_val * x + Q[5];
1340 let q_val = q_val * x + Q[4];
1341 let q_val = q_val * x + Q[3];
1342 let q_val = q_val * x + Q[2];
1343 let q_val = q_val * x + Q[1];
1344 let q_val = q_val * x + Q[0];
1345
1346 (-x * x).exp() * p_val / q_val
1347}
1348
1349#[allow(clippy::excessive_precision)]
1351fn erfc_large(x: f64) -> f64 {
1352 const P: [f64; 6] = [
1353 6.58749161529837803e-04,
1354 1.60837851487422766e-02,
1355 1.25781726111229246e-01,
1356 3.60344899949804439e-01,
1357 3.05326634961232344e-01,
1358 1.63153871373020978e-02,
1359 ];
1360 const Q: [f64; 6] = [
1361 2.33520497626869185e-03,
1362 6.05183413124413191e-02,
1363 5.27905102951428412e-01,
1364 1.87295284992346047e+00,
1365 2.56852019228982242e+00,
1366 1.00000000000000000e+00,
1367 ];
1368
1369 let x2 = x * x;
1370 let inv_x2 = 1.0 / x2;
1371
1372 let p_val = P[5];
1373 let p_val = p_val * inv_x2 + P[4];
1374 let p_val = p_val * inv_x2 + P[3];
1375 let p_val = p_val * inv_x2 + P[2];
1376 let p_val = p_val * inv_x2 + P[1];
1377 let p_val = p_val * inv_x2 + P[0];
1378
1379 let q_val = Q[5];
1380 let q_val = q_val * inv_x2 + Q[4];
1381 let q_val = q_val * inv_x2 + Q[3];
1382 let q_val = q_val * inv_x2 + Q[2];
1383 let q_val = q_val * inv_x2 + Q[1];
1384 let q_val = q_val * inv_x2 + Q[0];
1385
1386 const FRAC_1_SQRT_PI: f64 = 0.5641895835477563;
1388 (-x2).exp() / x * (FRAC_1_SQRT_PI + inv_x2 * p_val / q_val)
1389}
1390
1391fn erfc_direct(x: f64) -> f64 {
1393 if x < 0.0 {
1394 return 2.0 - erfc_direct(-x);
1395 }
1396 if x < 0.5 {
1397 return 1.0 - erf_approx(x);
1398 }
1399 if x < 4.0 {
1400 return erfc_mid(x);
1401 }
1402 erfc_large(x)
1403}
1404
1405#[derive(Debug)]
1409pub struct ErfFn;
1410impl Function for ErfFn {
1411 func_caps!(PURE);
1412 fn name(&self) -> &'static str {
1413 "ERF"
1414 }
1415 fn min_args(&self) -> usize {
1416 1
1417 }
1418 fn variadic(&self) -> bool {
1419 true
1420 }
1421 fn arg_schema(&self) -> &'static [ArgSchema] {
1422 &ARG_NUM_LENIENT_TWO[..]
1423 }
1424 fn eval<'a, 'b, 'c>(
1425 &self,
1426 args: &'c [ArgumentHandle<'a, 'b>],
1427 _ctx: &dyn FunctionContext<'b>,
1428 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1429 let lower = match args[0].value()?.into_literal() {
1430 LiteralValue::Error(e) => {
1431 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1432 }
1433 other => coerce_num(&other)?,
1434 };
1435
1436 let result = if args.len() > 1 {
1437 let upper = match args[1].value()?.into_literal() {
1439 LiteralValue::Error(e) => {
1440 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1441 }
1442 other => coerce_num(&other)?,
1443 };
1444 erf_approx(upper) - erf_approx(lower)
1445 } else {
1446 erf_approx(lower)
1448 };
1449
1450 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
1451 result,
1452 )))
1453 }
1454}
1455
1456#[derive(Debug)]
1458pub struct ErfcFn;
1459impl Function for ErfcFn {
1460 func_caps!(PURE);
1461 fn name(&self) -> &'static str {
1462 "ERFC"
1463 }
1464 fn min_args(&self) -> usize {
1465 1
1466 }
1467 fn arg_schema(&self) -> &'static [ArgSchema] {
1468 &ARG_ANY_ONE[..]
1469 }
1470 fn eval<'a, 'b, 'c>(
1471 &self,
1472 args: &'c [ArgumentHandle<'a, 'b>],
1473 _ctx: &dyn FunctionContext<'b>,
1474 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1475 let x = match args[0].value()?.into_literal() {
1476 LiteralValue::Error(e) => {
1477 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1478 }
1479 other => coerce_num(&other)?,
1480 };
1481
1482 let result = erfc_direct(x);
1483 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
1484 result,
1485 )))
1486 }
1487}
1488
1489#[derive(Debug)]
1491pub struct ErfPreciseFn;
1492impl Function for ErfPreciseFn {
1493 func_caps!(PURE);
1494 fn name(&self) -> &'static str {
1495 "ERF.PRECISE"
1496 }
1497 fn min_args(&self) -> usize {
1498 1
1499 }
1500 fn arg_schema(&self) -> &'static [ArgSchema] {
1501 &ARG_ANY_ONE[..]
1502 }
1503 fn eval<'a, 'b, 'c>(
1504 &self,
1505 args: &'c [ArgumentHandle<'a, 'b>],
1506 _ctx: &dyn FunctionContext<'b>,
1507 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1508 let x = match args[0].value()?.into_literal() {
1509 LiteralValue::Error(e) => {
1510 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1511 }
1512 other => coerce_num(&other)?,
1513 };
1514
1515 let result = erf_approx(x);
1516 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
1517 result,
1518 )))
1519 }
1520}
1521
1522fn parse_complex(s: &str) -> Result<(f64, f64, char), ExcelError> {
1527 let s = s.trim();
1528 if s.is_empty() {
1529 return Err(ExcelError::new_num());
1530 }
1531
1532 let suffix = if s.ends_with('i') || s.ends_with('I') {
1534 'i'
1535 } else if s.ends_with('j') || s.ends_with('J') {
1536 'j'
1537 } else {
1538 let real: f64 = s.parse().map_err(|_| ExcelError::new_num())?;
1540 return Ok((real, 0.0, 'i'));
1541 };
1542
1543 let s = &s[..s.len() - 1];
1545
1546 if s.is_empty() || s == "+" {
1548 return Ok((0.0, 1.0, suffix));
1549 }
1550 if s == "-" {
1551 return Ok((0.0, -1.0, suffix));
1552 }
1553
1554 let mut split_pos = None;
1557 let bytes = s.as_bytes();
1558
1559 for i in (1..bytes.len()).rev() {
1560 let c = bytes[i] as char;
1561 if c == '+' || c == '-' {
1562 if i > 0 {
1564 let prev = bytes[i - 1] as char;
1565 if prev == 'e' || prev == 'E' {
1566 continue;
1567 }
1568 }
1569 split_pos = Some(i);
1570 break;
1571 }
1572 }
1573
1574 match split_pos {
1575 Some(pos) => {
1576 let real_str = &s[..pos];
1578 let imag_str = &s[pos..];
1579
1580 let real: f64 = if real_str.is_empty() {
1581 0.0
1582 } else {
1583 real_str.parse().map_err(|_| ExcelError::new_num())?
1584 };
1585
1586 let imag: f64 = if imag_str == "+" {
1588 1.0
1589 } else if imag_str == "-" {
1590 -1.0
1591 } else {
1592 imag_str.parse().map_err(|_| ExcelError::new_num())?
1593 };
1594
1595 Ok((real, imag, suffix))
1596 }
1597 None => {
1598 let imag: f64 = s.parse().map_err(|_| ExcelError::new_num())?;
1600 Ok((0.0, imag, suffix))
1601 }
1602 }
1603}
1604
1605fn clean_float(val: f64) -> f64 {
1607 let rounded = val.round();
1608 if (val - rounded).abs() < 1e-10 {
1609 rounded
1610 } else {
1611 val
1612 }
1613}
1614
1615fn format_complex(real: f64, imag: f64, suffix: char) -> String {
1617 let real = clean_float(real);
1619 let imag = clean_float(imag);
1620
1621 let real_is_zero = real.abs() < 1e-15;
1623 let imag_is_zero = imag.abs() < 1e-15;
1624
1625 if real_is_zero && imag_is_zero {
1626 return "0".to_string();
1627 }
1628
1629 if imag_is_zero {
1630 if real == real.trunc() && real.abs() < 1e15 {
1632 return format!("{}", real as i64);
1633 }
1634 return format!("{}", real);
1635 }
1636
1637 if real_is_zero {
1638 if (imag - 1.0).abs() < 1e-15 {
1640 return format!("{}", suffix);
1641 }
1642 if (imag + 1.0).abs() < 1e-15 {
1643 return format!("-{}", suffix);
1644 }
1645 if imag == imag.trunc() && imag.abs() < 1e15 {
1646 return format!("{}{}", imag as i64, suffix);
1647 }
1648 return format!("{}{}", imag, suffix);
1649 }
1650
1651 let real_str = if real == real.trunc() && real.abs() < 1e15 {
1653 format!("{}", real as i64)
1654 } else {
1655 format!("{}", real)
1656 };
1657
1658 let imag_str = if (imag - 1.0).abs() < 1e-15 {
1659 format!("+{}", suffix)
1660 } else if (imag + 1.0).abs() < 1e-15 {
1661 format!("-{}", suffix)
1662 } else if imag > 0.0 {
1663 if imag == imag.trunc() && imag.abs() < 1e15 {
1664 format!("+{}{}", imag as i64, suffix)
1665 } else {
1666 format!("+{}{}", imag, suffix)
1667 }
1668 } else if imag == imag.trunc() && imag.abs() < 1e15 {
1669 format!("{}{}", imag as i64, suffix)
1670 } else {
1671 format!("{}{}", imag, suffix)
1672 };
1673
1674 format!("{}{}", real_str, imag_str)
1675}
1676
1677fn coerce_complex_str(v: &LiteralValue) -> Result<String, ExcelError> {
1679 match v {
1680 LiteralValue::Text(s) => Ok(s.clone()),
1681 LiteralValue::Int(i) => Ok(i.to_string()),
1682 LiteralValue::Number(n) => Ok(n.to_string()),
1683 LiteralValue::Error(e) => Err(e.clone()),
1684 _ => Err(ExcelError::new_value()),
1685 }
1686}
1687
1688static ARG_COMPLEX_THREE: std::sync::LazyLock<Vec<ArgSchema>> =
1690 std::sync::LazyLock::new(|| vec![ArgSchema::any(), ArgSchema::any(), ArgSchema::any()]);
1691
1692#[derive(Debug)]
1694pub struct ComplexFn;
1695impl Function for ComplexFn {
1696 func_caps!(PURE);
1697 fn name(&self) -> &'static str {
1698 "COMPLEX"
1699 }
1700 fn min_args(&self) -> usize {
1701 2
1702 }
1703 fn variadic(&self) -> bool {
1704 true
1705 }
1706 fn arg_schema(&self) -> &'static [ArgSchema] {
1707 &ARG_COMPLEX_THREE[..]
1708 }
1709 fn eval<'a, 'b, 'c>(
1710 &self,
1711 args: &'c [ArgumentHandle<'a, 'b>],
1712 _ctx: &dyn FunctionContext<'b>,
1713 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1714 let real = match args[0].value()?.into_literal() {
1715 LiteralValue::Error(e) => {
1716 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1717 }
1718 other => coerce_num(&other)?,
1719 };
1720
1721 let imag = match args[1].value()?.into_literal() {
1722 LiteralValue::Error(e) => {
1723 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1724 }
1725 other => coerce_num(&other)?,
1726 };
1727
1728 let suffix = if args.len() > 2 {
1729 match args[2].value()?.into_literal() {
1730 LiteralValue::Error(e) => {
1731 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1732 }
1733 LiteralValue::Text(s) => {
1734 let s = s.to_lowercase();
1735 if s == "i" {
1736 'i'
1737 } else if s == "j" {
1738 'j'
1739 } else if s.is_empty() {
1740 'i' } else {
1742 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1743 ExcelError::new_value(),
1744 )));
1745 }
1746 }
1747 LiteralValue::Empty => 'i',
1748 _ => {
1749 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1750 ExcelError::new_value(),
1751 )));
1752 }
1753 }
1754 } else {
1755 'i'
1756 };
1757
1758 let result = format_complex(real, imag, suffix);
1759 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
1760 }
1761}
1762
1763#[derive(Debug)]
1765pub struct ImRealFn;
1766impl Function for ImRealFn {
1767 func_caps!(PURE);
1768 fn name(&self) -> &'static str {
1769 "IMREAL"
1770 }
1771 fn min_args(&self) -> usize {
1772 1
1773 }
1774 fn arg_schema(&self) -> &'static [ArgSchema] {
1775 &ARG_ANY_ONE[..]
1776 }
1777 fn eval<'a, 'b, 'c>(
1778 &self,
1779 args: &'c [ArgumentHandle<'a, 'b>],
1780 _ctx: &dyn FunctionContext<'b>,
1781 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1782 let inumber = match args[0].value()?.into_literal() {
1783 LiteralValue::Error(e) => {
1784 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1785 }
1786 other => match coerce_complex_str(&other) {
1787 Ok(s) => s,
1788 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1789 },
1790 };
1791
1792 let (real, _, _) = match parse_complex(&inumber) {
1793 Ok(c) => c,
1794 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1795 };
1796
1797 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(real)))
1798 }
1799}
1800
1801#[derive(Debug)]
1803pub struct ImaginaryFn;
1804impl Function for ImaginaryFn {
1805 func_caps!(PURE);
1806 fn name(&self) -> &'static str {
1807 "IMAGINARY"
1808 }
1809 fn min_args(&self) -> usize {
1810 1
1811 }
1812 fn arg_schema(&self) -> &'static [ArgSchema] {
1813 &ARG_ANY_ONE[..]
1814 }
1815 fn eval<'a, 'b, 'c>(
1816 &self,
1817 args: &'c [ArgumentHandle<'a, 'b>],
1818 _ctx: &dyn FunctionContext<'b>,
1819 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1820 let inumber = match args[0].value()?.into_literal() {
1821 LiteralValue::Error(e) => {
1822 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1823 }
1824 other => match coerce_complex_str(&other) {
1825 Ok(s) => s,
1826 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1827 },
1828 };
1829
1830 let (_, imag, _) = match parse_complex(&inumber) {
1831 Ok(c) => c,
1832 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1833 };
1834
1835 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(imag)))
1836 }
1837}
1838
1839#[derive(Debug)]
1841pub struct ImAbsFn;
1842impl Function for ImAbsFn {
1843 func_caps!(PURE);
1844 fn name(&self) -> &'static str {
1845 "IMABS"
1846 }
1847 fn min_args(&self) -> usize {
1848 1
1849 }
1850 fn arg_schema(&self) -> &'static [ArgSchema] {
1851 &ARG_ANY_ONE[..]
1852 }
1853 fn eval<'a, 'b, 'c>(
1854 &self,
1855 args: &'c [ArgumentHandle<'a, 'b>],
1856 _ctx: &dyn FunctionContext<'b>,
1857 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1858 let inumber = match args[0].value()?.into_literal() {
1859 LiteralValue::Error(e) => {
1860 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1861 }
1862 other => match coerce_complex_str(&other) {
1863 Ok(s) => s,
1864 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1865 },
1866 };
1867
1868 let (real, imag, _) = match parse_complex(&inumber) {
1869 Ok(c) => c,
1870 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1871 };
1872
1873 let abs = (real * real + imag * imag).sqrt();
1874 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(abs)))
1875 }
1876}
1877
1878#[derive(Debug)]
1880pub struct ImArgumentFn;
1881impl Function for ImArgumentFn {
1882 func_caps!(PURE);
1883 fn name(&self) -> &'static str {
1884 "IMARGUMENT"
1885 }
1886 fn min_args(&self) -> usize {
1887 1
1888 }
1889 fn arg_schema(&self) -> &'static [ArgSchema] {
1890 &ARG_ANY_ONE[..]
1891 }
1892 fn eval<'a, 'b, 'c>(
1893 &self,
1894 args: &'c [ArgumentHandle<'a, 'b>],
1895 _ctx: &dyn FunctionContext<'b>,
1896 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1897 let inumber = match args[0].value()?.into_literal() {
1898 LiteralValue::Error(e) => {
1899 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1900 }
1901 other => match coerce_complex_str(&other) {
1902 Ok(s) => s,
1903 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1904 },
1905 };
1906
1907 let (real, imag, _) = match parse_complex(&inumber) {
1908 Ok(c) => c,
1909 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1910 };
1911
1912 if real.abs() < 1e-15 && imag.abs() < 1e-15 {
1914 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
1915 ExcelError::new_div(),
1916 )));
1917 }
1918
1919 let arg = imag.atan2(real);
1920 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(arg)))
1921 }
1922}
1923
1924#[derive(Debug)]
1926pub struct ImConjugateFn;
1927impl Function for ImConjugateFn {
1928 func_caps!(PURE);
1929 fn name(&self) -> &'static str {
1930 "IMCONJUGATE"
1931 }
1932 fn min_args(&self) -> usize {
1933 1
1934 }
1935 fn arg_schema(&self) -> &'static [ArgSchema] {
1936 &ARG_ANY_ONE[..]
1937 }
1938 fn eval<'a, 'b, 'c>(
1939 &self,
1940 args: &'c [ArgumentHandle<'a, 'b>],
1941 _ctx: &dyn FunctionContext<'b>,
1942 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1943 let inumber = match args[0].value()?.into_literal() {
1944 LiteralValue::Error(e) => {
1945 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
1946 }
1947 other => match coerce_complex_str(&other) {
1948 Ok(s) => s,
1949 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1950 },
1951 };
1952
1953 let (real, imag, suffix) = match parse_complex(&inumber) {
1954 Ok(c) => c,
1955 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
1956 };
1957
1958 let result = format_complex(real, -imag, suffix);
1959 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
1960 }
1961}
1962
1963fn check_suffix_compatibility(s1: char, s2: char) -> Result<char, ExcelError> {
1965 if s1 == s2 {
1969 Ok(s1)
1970 } else {
1971 Ok(s1)
1974 }
1975}
1976
1977#[derive(Debug)]
1979pub struct ImSumFn;
1980impl Function for ImSumFn {
1981 func_caps!(PURE);
1982 fn name(&self) -> &'static str {
1983 "IMSUM"
1984 }
1985 fn min_args(&self) -> usize {
1986 1
1987 }
1988 fn variadic(&self) -> bool {
1989 true
1990 }
1991 fn arg_schema(&self) -> &'static [ArgSchema] {
1992 &ARG_ANY_ONE[..]
1993 }
1994 fn eval<'a, 'b, 'c>(
1995 &self,
1996 args: &'c [ArgumentHandle<'a, 'b>],
1997 _ctx: &dyn FunctionContext<'b>,
1998 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
1999 let mut sum_real = 0.0;
2000 let mut sum_imag = 0.0;
2001 let mut result_suffix = 'i';
2002 let mut first = true;
2003
2004 for arg in args {
2005 let inumber = match arg.value()?.into_literal() {
2006 LiteralValue::Error(e) => {
2007 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2008 }
2009 other => match coerce_complex_str(&other) {
2010 Ok(s) => s,
2011 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2012 },
2013 };
2014
2015 let (real, imag, suffix) = match parse_complex(&inumber) {
2016 Ok(c) => c,
2017 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2018 };
2019
2020 if first {
2021 result_suffix = suffix;
2022 first = false;
2023 } else {
2024 result_suffix = check_suffix_compatibility(result_suffix, suffix)?;
2025 }
2026
2027 sum_real += real;
2028 sum_imag += imag;
2029 }
2030
2031 let result = format_complex(sum_real, sum_imag, result_suffix);
2032 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2033 }
2034}
2035
2036#[derive(Debug)]
2038pub struct ImSubFn;
2039impl Function for ImSubFn {
2040 func_caps!(PURE);
2041 fn name(&self) -> &'static str {
2042 "IMSUB"
2043 }
2044 fn min_args(&self) -> usize {
2045 2
2046 }
2047 fn arg_schema(&self) -> &'static [ArgSchema] {
2048 &ARG_ANY_TWO[..]
2049 }
2050 fn eval<'a, 'b, 'c>(
2051 &self,
2052 args: &'c [ArgumentHandle<'a, 'b>],
2053 _ctx: &dyn FunctionContext<'b>,
2054 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2055 let inumber1 = match args[0].value()?.into_literal() {
2056 LiteralValue::Error(e) => {
2057 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2058 }
2059 other => match coerce_complex_str(&other) {
2060 Ok(s) => s,
2061 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2062 },
2063 };
2064
2065 let inumber2 = match args[1].value()?.into_literal() {
2066 LiteralValue::Error(e) => {
2067 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2068 }
2069 other => match coerce_complex_str(&other) {
2070 Ok(s) => s,
2071 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2072 },
2073 };
2074
2075 let (real1, imag1, suffix1) = match parse_complex(&inumber1) {
2076 Ok(c) => c,
2077 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2078 };
2079
2080 let (real2, imag2, suffix2) = match parse_complex(&inumber2) {
2081 Ok(c) => c,
2082 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2083 };
2084
2085 let result_suffix = check_suffix_compatibility(suffix1, suffix2)?;
2086 let result = format_complex(real1 - real2, imag1 - imag2, result_suffix);
2087 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2088 }
2089}
2090
2091#[derive(Debug)]
2093pub struct ImProductFn;
2094impl Function for ImProductFn {
2095 func_caps!(PURE);
2096 fn name(&self) -> &'static str {
2097 "IMPRODUCT"
2098 }
2099 fn min_args(&self) -> usize {
2100 1
2101 }
2102 fn variadic(&self) -> bool {
2103 true
2104 }
2105 fn arg_schema(&self) -> &'static [ArgSchema] {
2106 &ARG_ANY_ONE[..]
2107 }
2108 fn eval<'a, 'b, 'c>(
2109 &self,
2110 args: &'c [ArgumentHandle<'a, 'b>],
2111 _ctx: &dyn FunctionContext<'b>,
2112 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2113 let mut prod_real = 1.0;
2114 let mut prod_imag = 0.0;
2115 let mut result_suffix = 'i';
2116 let mut first = true;
2117
2118 for arg in args {
2119 let inumber = match arg.value()?.into_literal() {
2120 LiteralValue::Error(e) => {
2121 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2122 }
2123 other => match coerce_complex_str(&other) {
2124 Ok(s) => s,
2125 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2126 },
2127 };
2128
2129 let (real, imag, suffix) = match parse_complex(&inumber) {
2130 Ok(c) => c,
2131 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2132 };
2133
2134 if first {
2135 result_suffix = suffix;
2136 prod_real = real;
2137 prod_imag = imag;
2138 first = false;
2139 } else {
2140 result_suffix = check_suffix_compatibility(result_suffix, suffix)?;
2141 let new_real = prod_real * real - prod_imag * imag;
2143 let new_imag = prod_real * imag + prod_imag * real;
2144 prod_real = new_real;
2145 prod_imag = new_imag;
2146 }
2147 }
2148
2149 let result = format_complex(prod_real, prod_imag, result_suffix);
2150 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2151 }
2152}
2153
2154#[derive(Debug)]
2156pub struct ImDivFn;
2157impl Function for ImDivFn {
2158 func_caps!(PURE);
2159 fn name(&self) -> &'static str {
2160 "IMDIV"
2161 }
2162 fn min_args(&self) -> usize {
2163 2
2164 }
2165 fn arg_schema(&self) -> &'static [ArgSchema] {
2166 &ARG_ANY_TWO[..]
2167 }
2168 fn eval<'a, 'b, 'c>(
2169 &self,
2170 args: &'c [ArgumentHandle<'a, 'b>],
2171 _ctx: &dyn FunctionContext<'b>,
2172 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2173 let inumber1 = match args[0].value()?.into_literal() {
2174 LiteralValue::Error(e) => {
2175 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2176 }
2177 other => match coerce_complex_str(&other) {
2178 Ok(s) => s,
2179 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2180 },
2181 };
2182
2183 let inumber2 = match args[1].value()?.into_literal() {
2184 LiteralValue::Error(e) => {
2185 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2186 }
2187 other => match coerce_complex_str(&other) {
2188 Ok(s) => s,
2189 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2190 },
2191 };
2192
2193 let (a, b, suffix1) = match parse_complex(&inumber1) {
2194 Ok(c) => c,
2195 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2196 };
2197
2198 let (c, d, suffix2) = match parse_complex(&inumber2) {
2199 Ok(c) => c,
2200 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2201 };
2202
2203 let denom = c * c + d * d;
2205 if denom.abs() < 1e-15 {
2206 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2207 ExcelError::new_div(),
2208 )));
2209 }
2210
2211 let result_suffix = check_suffix_compatibility(suffix1, suffix2)?;
2212
2213 let real = (a * c + b * d) / denom;
2215 let imag = (b * c - a * d) / denom;
2216
2217 let result = format_complex(real, imag, result_suffix);
2218 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2219 }
2220}
2221
2222#[derive(Debug)]
2225pub struct ImExpFn;
2226impl Function for ImExpFn {
2227 func_caps!(PURE);
2228 fn name(&self) -> &'static str {
2229 "IMEXP"
2230 }
2231 fn min_args(&self) -> usize {
2232 1
2233 }
2234 fn arg_schema(&self) -> &'static [ArgSchema] {
2235 &ARG_ANY_ONE[..]
2236 }
2237 fn eval<'a, 'b, 'c>(
2238 &self,
2239 args: &'c [ArgumentHandle<'a, 'b>],
2240 _ctx: &dyn FunctionContext<'b>,
2241 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2242 let inumber = match args[0].value()?.into_literal() {
2243 LiteralValue::Error(e) => {
2244 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2245 }
2246 other => match coerce_complex_str(&other) {
2247 Ok(s) => s,
2248 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2249 },
2250 };
2251
2252 let (a, b, suffix) = match parse_complex(&inumber) {
2253 Ok(c) => c,
2254 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2255 };
2256
2257 let exp_a = a.exp();
2259 let real = exp_a * b.cos();
2260 let imag = exp_a * b.sin();
2261
2262 let result = format_complex(real, imag, suffix);
2263 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2264 }
2265}
2266
2267#[derive(Debug)]
2270pub struct ImLnFn;
2271impl Function for ImLnFn {
2272 func_caps!(PURE);
2273 fn name(&self) -> &'static str {
2274 "IMLN"
2275 }
2276 fn min_args(&self) -> usize {
2277 1
2278 }
2279 fn arg_schema(&self) -> &'static [ArgSchema] {
2280 &ARG_ANY_ONE[..]
2281 }
2282 fn eval<'a, 'b, 'c>(
2283 &self,
2284 args: &'c [ArgumentHandle<'a, 'b>],
2285 _ctx: &dyn FunctionContext<'b>,
2286 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2287 let inumber = match args[0].value()?.into_literal() {
2288 LiteralValue::Error(e) => {
2289 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2290 }
2291 other => match coerce_complex_str(&other) {
2292 Ok(s) => s,
2293 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2294 },
2295 };
2296
2297 let (a, b, suffix) = match parse_complex(&inumber) {
2298 Ok(c) => c,
2299 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2300 };
2301
2302 let modulus = (a * a + b * b).sqrt();
2304 if modulus < 1e-15 {
2305 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2306 ExcelError::new_num(),
2307 )));
2308 }
2309
2310 let real = modulus.ln();
2312 let imag = b.atan2(a);
2313
2314 let result = format_complex(real, imag, suffix);
2315 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2316 }
2317}
2318
2319#[derive(Debug)]
2322pub struct ImLog10Fn;
2323impl Function for ImLog10Fn {
2324 func_caps!(PURE);
2325 fn name(&self) -> &'static str {
2326 "IMLOG10"
2327 }
2328 fn min_args(&self) -> usize {
2329 1
2330 }
2331 fn arg_schema(&self) -> &'static [ArgSchema] {
2332 &ARG_ANY_ONE[..]
2333 }
2334 fn eval<'a, 'b, 'c>(
2335 &self,
2336 args: &'c [ArgumentHandle<'a, 'b>],
2337 _ctx: &dyn FunctionContext<'b>,
2338 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2339 let inumber = match args[0].value()?.into_literal() {
2340 LiteralValue::Error(e) => {
2341 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2342 }
2343 other => match coerce_complex_str(&other) {
2344 Ok(s) => s,
2345 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2346 },
2347 };
2348
2349 let (a, b, suffix) = match parse_complex(&inumber) {
2350 Ok(c) => c,
2351 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2352 };
2353
2354 let modulus = (a * a + b * b).sqrt();
2356 if modulus < 1e-15 {
2357 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2358 ExcelError::new_num(),
2359 )));
2360 }
2361
2362 let ln10 = 10.0_f64.ln();
2364 let real = modulus.ln() / ln10;
2365 let imag = b.atan2(a) / ln10;
2366
2367 let result = format_complex(real, imag, suffix);
2368 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2369 }
2370}
2371
2372#[derive(Debug)]
2375pub struct ImLog2Fn;
2376impl Function for ImLog2Fn {
2377 func_caps!(PURE);
2378 fn name(&self) -> &'static str {
2379 "IMLOG2"
2380 }
2381 fn min_args(&self) -> usize {
2382 1
2383 }
2384 fn arg_schema(&self) -> &'static [ArgSchema] {
2385 &ARG_ANY_ONE[..]
2386 }
2387 fn eval<'a, 'b, 'c>(
2388 &self,
2389 args: &'c [ArgumentHandle<'a, 'b>],
2390 _ctx: &dyn FunctionContext<'b>,
2391 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2392 let inumber = match args[0].value()?.into_literal() {
2393 LiteralValue::Error(e) => {
2394 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2395 }
2396 other => match coerce_complex_str(&other) {
2397 Ok(s) => s,
2398 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2399 },
2400 };
2401
2402 let (a, b, suffix) = match parse_complex(&inumber) {
2403 Ok(c) => c,
2404 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2405 };
2406
2407 let modulus = (a * a + b * b).sqrt();
2409 if modulus < 1e-15 {
2410 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2411 ExcelError::new_num(),
2412 )));
2413 }
2414
2415 let ln2 = 2.0_f64.ln();
2417 let real = modulus.ln() / ln2;
2418 let imag = b.atan2(a) / ln2;
2419
2420 let result = format_complex(real, imag, suffix);
2421 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2422 }
2423}
2424
2425#[derive(Debug)]
2428pub struct ImPowerFn;
2429impl Function for ImPowerFn {
2430 func_caps!(PURE);
2431 fn name(&self) -> &'static str {
2432 "IMPOWER"
2433 }
2434 fn min_args(&self) -> usize {
2435 2
2436 }
2437 fn arg_schema(&self) -> &'static [ArgSchema] {
2438 &ARG_ANY_TWO[..]
2439 }
2440 fn eval<'a, 'b, 'c>(
2441 &self,
2442 args: &'c [ArgumentHandle<'a, 'b>],
2443 _ctx: &dyn FunctionContext<'b>,
2444 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2445 let inumber = match args[0].value()?.into_literal() {
2446 LiteralValue::Error(e) => {
2447 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2448 }
2449 other => match coerce_complex_str(&other) {
2450 Ok(s) => s,
2451 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2452 },
2453 };
2454
2455 let n = match args[1].value()?.into_literal() {
2456 LiteralValue::Error(e) => {
2457 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2458 }
2459 other => coerce_num(&other)?,
2460 };
2461
2462 let (a, b, suffix) = match parse_complex(&inumber) {
2463 Ok(c) => c,
2464 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2465 };
2466
2467 let modulus = (a * a + b * b).sqrt();
2468 let theta = b.atan2(a);
2469
2470 if modulus < 1e-15 {
2472 if n > 0.0 {
2473 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
2474 "0".to_string(),
2475 )));
2476 } else {
2477 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2479 ExcelError::new_num(),
2480 )));
2481 }
2482 }
2483
2484 let r_n = modulus.powf(n);
2486 let n_theta = n * theta;
2487 let real = r_n * n_theta.cos();
2488 let imag = r_n * n_theta.sin();
2489
2490 let result = format_complex(real, imag, suffix);
2491 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2492 }
2493}
2494
2495#[derive(Debug)]
2498pub struct ImSqrtFn;
2499impl Function for ImSqrtFn {
2500 func_caps!(PURE);
2501 fn name(&self) -> &'static str {
2502 "IMSQRT"
2503 }
2504 fn min_args(&self) -> usize {
2505 1
2506 }
2507 fn arg_schema(&self) -> &'static [ArgSchema] {
2508 &ARG_ANY_ONE[..]
2509 }
2510 fn eval<'a, 'b, 'c>(
2511 &self,
2512 args: &'c [ArgumentHandle<'a, 'b>],
2513 _ctx: &dyn FunctionContext<'b>,
2514 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2515 let inumber = match args[0].value()?.into_literal() {
2516 LiteralValue::Error(e) => {
2517 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2518 }
2519 other => match coerce_complex_str(&other) {
2520 Ok(s) => s,
2521 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2522 },
2523 };
2524
2525 let (a, b, suffix) = match parse_complex(&inumber) {
2526 Ok(c) => c,
2527 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2528 };
2529
2530 let modulus = (a * a + b * b).sqrt();
2531 let theta = b.atan2(a);
2532
2533 let sqrt_r = modulus.sqrt();
2535 let half_theta = theta / 2.0;
2536 let real = sqrt_r * half_theta.cos();
2537 let imag = sqrt_r * half_theta.sin();
2538
2539 let result = format_complex(real, imag, suffix);
2540 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2541 }
2542}
2543
2544#[derive(Debug)]
2547pub struct ImSinFn;
2548impl Function for ImSinFn {
2549 func_caps!(PURE);
2550 fn name(&self) -> &'static str {
2551 "IMSIN"
2552 }
2553 fn min_args(&self) -> usize {
2554 1
2555 }
2556 fn arg_schema(&self) -> &'static [ArgSchema] {
2557 &ARG_ANY_ONE[..]
2558 }
2559 fn eval<'a, 'b, 'c>(
2560 &self,
2561 args: &'c [ArgumentHandle<'a, 'b>],
2562 _ctx: &dyn FunctionContext<'b>,
2563 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2564 let inumber = match args[0].value()?.into_literal() {
2565 LiteralValue::Error(e) => {
2566 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2567 }
2568 other => match coerce_complex_str(&other) {
2569 Ok(s) => s,
2570 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2571 },
2572 };
2573
2574 let (a, b, suffix) = match parse_complex(&inumber) {
2575 Ok(c) => c,
2576 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2577 };
2578
2579 let real = a.sin() * b.cosh();
2581 let imag = a.cos() * b.sinh();
2582
2583 let result = format_complex(real, imag, suffix);
2584 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2585 }
2586}
2587
2588#[derive(Debug)]
2591pub struct ImCosFn;
2592impl Function for ImCosFn {
2593 func_caps!(PURE);
2594 fn name(&self) -> &'static str {
2595 "IMCOS"
2596 }
2597 fn min_args(&self) -> usize {
2598 1
2599 }
2600 fn arg_schema(&self) -> &'static [ArgSchema] {
2601 &ARG_ANY_ONE[..]
2602 }
2603 fn eval<'a, 'b, 'c>(
2604 &self,
2605 args: &'c [ArgumentHandle<'a, 'b>],
2606 _ctx: &dyn FunctionContext<'b>,
2607 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2608 let inumber = match args[0].value()?.into_literal() {
2609 LiteralValue::Error(e) => {
2610 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2611 }
2612 other => match coerce_complex_str(&other) {
2613 Ok(s) => s,
2614 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2615 },
2616 };
2617
2618 let (a, b, suffix) = match parse_complex(&inumber) {
2619 Ok(c) => c,
2620 Err(e) => return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2621 };
2622
2623 let real = a.cos() * b.cosh();
2625 let imag = -a.sin() * b.sinh();
2626
2627 let result = format_complex(real, imag, suffix);
2628 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(result)))
2629 }
2630}
2631
2632#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2636enum UnitCategory {
2637 Length,
2638 Mass,
2639 Temperature,
2640}
2641
2642struct UnitInfo {
2644 category: UnitCategory,
2645 to_base: f64,
2648}
2649
2650fn get_unit_info(unit: &str) -> Option<UnitInfo> {
2652 match unit {
2654 "m" => Some(UnitInfo {
2656 category: UnitCategory::Length,
2657 to_base: 1.0,
2658 }),
2659 "km" => Some(UnitInfo {
2660 category: UnitCategory::Length,
2661 to_base: 1000.0,
2662 }),
2663 "cm" => Some(UnitInfo {
2664 category: UnitCategory::Length,
2665 to_base: 0.01,
2666 }),
2667 "mm" => Some(UnitInfo {
2668 category: UnitCategory::Length,
2669 to_base: 0.001,
2670 }),
2671 "mi" => Some(UnitInfo {
2673 category: UnitCategory::Length,
2674 to_base: 1609.344,
2675 }),
2676 "ft" => Some(UnitInfo {
2677 category: UnitCategory::Length,
2678 to_base: 0.3048,
2679 }),
2680 "in" => Some(UnitInfo {
2681 category: UnitCategory::Length,
2682 to_base: 0.0254,
2683 }),
2684 "yd" => Some(UnitInfo {
2685 category: UnitCategory::Length,
2686 to_base: 0.9144,
2687 }),
2688 "Nmi" => Some(UnitInfo {
2689 category: UnitCategory::Length,
2690 to_base: 1852.0,
2691 }),
2692
2693 "g" => Some(UnitInfo {
2695 category: UnitCategory::Mass,
2696 to_base: 1.0,
2697 }),
2698 "kg" => Some(UnitInfo {
2699 category: UnitCategory::Mass,
2700 to_base: 1000.0,
2701 }),
2702 "mg" => Some(UnitInfo {
2703 category: UnitCategory::Mass,
2704 to_base: 0.001,
2705 }),
2706 "lbm" => Some(UnitInfo {
2707 category: UnitCategory::Mass,
2708 to_base: 453.59237,
2709 }),
2710 "oz" => Some(UnitInfo {
2711 category: UnitCategory::Mass,
2712 to_base: 28.349523125,
2713 }),
2714 "ozm" => Some(UnitInfo {
2715 category: UnitCategory::Mass,
2716 to_base: 28.349523125,
2717 }),
2718 "ton" => Some(UnitInfo {
2719 category: UnitCategory::Mass,
2720 to_base: 907184.74,
2721 }),
2722
2723 "C" | "cel" => Some(UnitInfo {
2725 category: UnitCategory::Temperature,
2726 to_base: 0.0, }),
2728 "F" | "fah" => Some(UnitInfo {
2729 category: UnitCategory::Temperature,
2730 to_base: 0.0, }),
2732 "K" | "kel" => Some(UnitInfo {
2733 category: UnitCategory::Temperature,
2734 to_base: 0.0, }),
2736
2737 _ => None,
2738 }
2739}
2740
2741fn normalize_temp_unit(unit: &str) -> &str {
2743 match unit {
2744 "C" | "cel" => "C",
2745 "F" | "fah" => "F",
2746 "K" | "kel" => "K",
2747 _ => unit,
2748 }
2749}
2750
2751fn convert_temperature(value: f64, from: &str, to: &str) -> f64 {
2753 let from = normalize_temp_unit(from);
2754 let to = normalize_temp_unit(to);
2755
2756 if from == to {
2757 return value;
2758 }
2759
2760 let celsius = match from {
2762 "C" => value,
2763 "F" => (value - 32.0) * 5.0 / 9.0,
2764 "K" => value - 273.15,
2765 _ => value,
2766 };
2767
2768 match to {
2770 "C" => celsius,
2771 "F" => celsius * 9.0 / 5.0 + 32.0,
2772 "K" => celsius + 273.15,
2773 _ => celsius,
2774 }
2775}
2776
2777fn convert_units(value: f64, from: &str, to: &str) -> Result<f64, ExcelError> {
2779 let from_info = get_unit_info(from).ok_or_else(ExcelError::new_na)?;
2780 let to_info = get_unit_info(to).ok_or_else(ExcelError::new_na)?;
2781
2782 if from_info.category != to_info.category {
2784 return Err(ExcelError::new_na());
2785 }
2786
2787 if from_info.category == UnitCategory::Temperature {
2789 return Ok(convert_temperature(value, from, to));
2790 }
2791
2792 let base_value = value * from_info.to_base;
2794 Ok(base_value / to_info.to_base)
2795}
2796
2797#[derive(Debug)]
2799pub struct ConvertFn;
2800impl Function for ConvertFn {
2801 func_caps!(PURE);
2802 fn name(&self) -> &'static str {
2803 "CONVERT"
2804 }
2805 fn min_args(&self) -> usize {
2806 3
2807 }
2808 fn arg_schema(&self) -> &'static [ArgSchema] {
2809 &ARG_COMPLEX_THREE[..]
2810 }
2811 fn eval<'a, 'b, 'c>(
2812 &self,
2813 args: &'c [ArgumentHandle<'a, 'b>],
2814 _ctx: &dyn FunctionContext<'b>,
2815 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
2816 let value = match args[0].value()?.into_literal() {
2818 LiteralValue::Error(e) => {
2819 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2820 }
2821 other => coerce_num(&other)?,
2822 };
2823
2824 let from_unit = match args[1].value()?.into_literal() {
2826 LiteralValue::Error(e) => {
2827 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2828 }
2829 LiteralValue::Text(s) => s,
2830 _ => {
2831 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2832 ExcelError::new_na(),
2833 )));
2834 }
2835 };
2836
2837 let to_unit = match args[2].value()?.into_literal() {
2839 LiteralValue::Error(e) => {
2840 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e)));
2841 }
2842 LiteralValue::Text(s) => s,
2843 _ => {
2844 return Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(
2845 ExcelError::new_na(),
2846 )));
2847 }
2848 };
2849
2850 match convert_units(value, &from_unit, &to_unit) {
2851 Ok(result) => Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(
2852 result,
2853 ))),
2854 Err(e) => Ok(crate::traits::CalcValue::Scalar(LiteralValue::Error(e))),
2855 }
2856 }
2857}
2858
2859pub fn register_builtins() {
2860 use std::sync::Arc;
2861 crate::function_registry::register_function(Arc::new(BitAndFn));
2862 crate::function_registry::register_function(Arc::new(BitOrFn));
2863 crate::function_registry::register_function(Arc::new(BitXorFn));
2864 crate::function_registry::register_function(Arc::new(BitLShiftFn));
2865 crate::function_registry::register_function(Arc::new(BitRShiftFn));
2866 crate::function_registry::register_function(Arc::new(Bin2DecFn));
2867 crate::function_registry::register_function(Arc::new(Dec2BinFn));
2868 crate::function_registry::register_function(Arc::new(Hex2DecFn));
2869 crate::function_registry::register_function(Arc::new(Dec2HexFn));
2870 crate::function_registry::register_function(Arc::new(Oct2DecFn));
2871 crate::function_registry::register_function(Arc::new(Dec2OctFn));
2872 crate::function_registry::register_function(Arc::new(Bin2HexFn));
2873 crate::function_registry::register_function(Arc::new(Hex2BinFn));
2874 crate::function_registry::register_function(Arc::new(Bin2OctFn));
2875 crate::function_registry::register_function(Arc::new(Oct2BinFn));
2876 crate::function_registry::register_function(Arc::new(Hex2OctFn));
2877 crate::function_registry::register_function(Arc::new(Oct2HexFn));
2878 crate::function_registry::register_function(Arc::new(DeltaFn));
2879 crate::function_registry::register_function(Arc::new(GestepFn));
2880 crate::function_registry::register_function(Arc::new(ErfFn));
2881 crate::function_registry::register_function(Arc::new(ErfcFn));
2882 crate::function_registry::register_function(Arc::new(ErfPreciseFn));
2883 crate::function_registry::register_function(Arc::new(ComplexFn));
2885 crate::function_registry::register_function(Arc::new(ImRealFn));
2886 crate::function_registry::register_function(Arc::new(ImaginaryFn));
2887 crate::function_registry::register_function(Arc::new(ImAbsFn));
2888 crate::function_registry::register_function(Arc::new(ImArgumentFn));
2889 crate::function_registry::register_function(Arc::new(ImConjugateFn));
2890 crate::function_registry::register_function(Arc::new(ImSumFn));
2891 crate::function_registry::register_function(Arc::new(ImSubFn));
2892 crate::function_registry::register_function(Arc::new(ImProductFn));
2893 crate::function_registry::register_function(Arc::new(ImDivFn));
2894 crate::function_registry::register_function(Arc::new(ImExpFn));
2896 crate::function_registry::register_function(Arc::new(ImLnFn));
2897 crate::function_registry::register_function(Arc::new(ImLog10Fn));
2898 crate::function_registry::register_function(Arc::new(ImLog2Fn));
2899 crate::function_registry::register_function(Arc::new(ImPowerFn));
2900 crate::function_registry::register_function(Arc::new(ImSqrtFn));
2901 crate::function_registry::register_function(Arc::new(ImSinFn));
2902 crate::function_registry::register_function(Arc::new(ImCosFn));
2903 crate::function_registry::register_function(Arc::new(ConvertFn));
2905}