kalk/kalk_value/
mod.rs

1#[cfg(feature = "rug")]
2pub mod with_rug;
3
4#[cfg(feature = "rug")]
5use rug::{ops::Pow, Float};
6
7#[cfg(not(feature = "rug"))]
8pub mod regular;
9
10mod rounding;
11
12use crate::ast::Expr;
13use crate::errors::KalkError;
14use crate::radix;
15use wasm_bindgen::prelude::*;
16
17use self::rounding::EstimationResult;
18
19const ACCEPTABLE_COMPARISON_MARGIN: f64 = 0.00000001;
20
21#[cfg(feature = "rug")]
22pub(crate) type KalkFloat = rug::Float;
23
24#[cfg(not(feature = "rug"))]
25pub(crate) type KalkFloat = f64;
26
27#[macro_export]
28#[cfg(not(feature = "rug"))]
29macro_rules! float {
30    ($x:expr) => {{
31        $x.clone() as f64
32    }};
33}
34
35#[macro_export]
36#[cfg(feature = "rug")]
37macro_rules! float {
38    ($x:expr) => {{
39        use rug::Float;
40        Float::with_val(1024, $x)
41    }};
42}
43
44#[macro_export]
45#[cfg(not(feature = "rug"))]
46macro_rules! primitive {
47    ($x:expr) => {{
48        $x.clone()
49    }};
50}
51
52#[macro_export]
53#[cfg(feature = "rug")]
54macro_rules! primitive {
55    ($x:expr) => {{
56        $x.to_f64()
57    }};
58}
59
60#[macro_export]
61macro_rules! as_number_or_return {
62    ($x:expr) => {{
63        if let KalkValue::Number(real, imaginary, unit) = $x {
64            (
65                real,
66                if imaginary == -0f64 {
67                    float!(0)
68                } else {
69                    imaginary
70                },
71                unit,
72            )
73        } else {
74            return Err(KalkError::UnexpectedType(
75                $x.get_type_name(),
76                vec![String::from("number")],
77            ));
78        }
79    }};
80}
81
82#[macro_export]
83macro_rules! as_vector_or_return {
84    ($x:expr) => {{
85        if let KalkValue::Vector(values) = $x {
86            if values.len() == 0 {
87                return Err(KalkError::Expected(String::from("a non-empty vector")));
88            }
89
90            values
91        } else {
92            return Err(KalkError::UnexpectedType(
93                $x.get_type_name(),
94                vec![String::from("vector")],
95            ));
96        }
97    }};
98}
99
100#[macro_export]
101macro_rules! as_number_or_zero {
102    ($x:expr) => {{
103        use $crate::float;
104        if let KalkValue::Number(real, imaginary, unit) = $x {
105            (real, imaginary, unit)
106        } else {
107            (float!(0), float!(0), None)
108        }
109    }};
110}
111
112#[wasm_bindgen]
113#[derive(Clone)]
114pub struct ScientificNotation {
115    pub value: f64,
116    pub exponent: i32,
117    pub imaginary: bool,
118}
119
120#[wasm_bindgen]
121#[derive(PartialEq, Eq)]
122pub enum ComplexNumberType {
123    Real,
124    Imaginary,
125}
126
127#[wasm_bindgen]
128#[derive(Clone, Copy)]
129pub enum ScientificNotationFormat {
130    Normal,
131    Engineering,
132}
133
134#[wasm_bindgen]
135impl ScientificNotation {
136    #[wasm_bindgen(js_name = toString)]
137    pub fn to_js_string(&self) -> String {
138        self.to_string()
139    }
140
141    pub fn to_string_format(&self, format: ScientificNotationFormat) -> String {
142        match format {
143            ScientificNotationFormat::Normal => self.to_string(),
144            ScientificNotationFormat::Engineering => self.to_string_eng(),
145        }
146    }
147
148    fn to_string_eng(&self) -> String {
149        let exponent = self.exponent - 1;
150        let modulo = exponent % 3;
151        let value = self.value * 10_f64.powi(modulo);
152
153        ScientificNotation {
154            value,
155            exponent: exponent - modulo + 1,
156            imaginary: self.imaginary,
157        }
158        .to_string()
159    }
160}
161
162impl std::fmt::Display for ScientificNotation {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        let digits_and_mul = if self.value == 1f64 {
165            String::new()
166        } else {
167            format!("{}×", format_number(self.value))
168        };
169
170        write!(
171            f,
172            "{}10^{}{}",
173            digits_and_mul,
174            self.exponent - 1,
175            if self.imaginary { " i" } else { "" }
176        )
177    }
178}
179
180#[derive(PartialEq, Debug, Clone)]
181pub enum KalkValue {
182    #[cfg(not(feature = "rug"))]
183    Number(f64, f64, Option<String>),
184    #[cfg(feature = "rug")]
185    Number(Float, Float, Option<String>),
186    Boolean(bool),
187    Vector(Vec<KalkValue>),
188    Matrix(Vec<Vec<KalkValue>>),
189}
190
191impl std::fmt::Display for KalkValue {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        match self {
194            KalkValue::Number(real, imaginary, _) => {
195                let as_str = format_number_big(real);
196
197                if self.has_imaginary() {
198                    let imaginary_as_str = format_number_big(&imaginary.clone().abs());
199                    let sign = if imaginary < &0f64 { "-" } else { "+" };
200
201                    if &as_str == "0" {
202                        write!(f, "{}", imaginary_as_str)
203                    } else {
204                        write!(f, "{} {} {}i", as_str, sign, imaginary_as_str)
205                    }
206                } else {
207                    write!(f, "{}", as_str)
208                }
209            }
210            KalkValue::Boolean(is_true) => {
211                if *is_true {
212                    write!(f, "true")
213                } else {
214                    write!(f, "false")
215                }
216            }
217            KalkValue::Vector(values) => {
218                let get_estimation: fn(&KalkValue) -> String = |x| {
219                    x.estimate()
220                        .unwrap_or_else(|| EstimationResult {
221                            value: x.to_string(),
222                            is_exact: false,
223                        })
224                        .value
225                };
226
227                write!(
228                    f,
229                    "({})",
230                    values
231                        .iter()
232                        .map(get_estimation)
233                        .collect::<Vec<String>>()
234                        .join(", ")
235                )
236            }
237            KalkValue::Matrix(rows) => {
238                let mut value_strings = Vec::new();
239                let mut longest = 0;
240                for row in rows {
241                    for value in row {
242                        let value_str = value
243                            .estimate()
244                            .unwrap_or_else(|| EstimationResult {
245                                value: value.to_string(),
246                                is_exact: false,
247                            })
248                            .value;
249                        longest = longest.max(value_str.len());
250                        value_strings.push(format!("{},", value_str));
251                    }
252
253                    value_strings.last_mut().unwrap().pop(); // Trailing comma
254                    value_strings.push(String::from("\n"));
255                }
256
257                let mut result = String::from("[");
258                for value_str in value_strings {
259                    if value_str == "\n" {
260                        result.push_str("\n ");
261                    } else {
262                        result.push_str(&format!("{:width$} ", value_str, width = longest + 1));
263                    }
264                }
265
266                result.pop(); // Trailing new-line
267                result.pop(); // Trailing space
268                result.pop(); // Trailing space
269                result.pop(); // Trailing comma
270                result = result.trim().to_string();
271                result.push(']');
272
273                write!(f, "{}", result)
274            }
275        }
276    }
277}
278
279impl KalkValue {
280    pub fn nan() -> Self {
281        KalkValue::Number(float!(f64::NAN), float!(0f64), None)
282    }
283
284    pub fn get_type_name(&self) -> String {
285        match self {
286            KalkValue::Number(_, _, _) => String::from("number"),
287            KalkValue::Boolean(_) => String::from("boolean"),
288            KalkValue::Vector(_) => String::from("vector"),
289            KalkValue::Matrix(_) => String::from("matrix"),
290        }
291    }
292
293    pub fn to_string_big(&self) -> String {
294        fn trim_num(num_str: String) -> String {
295            num_str
296                .trim_end_matches('0')
297                .trim_end_matches('.')
298                .to_string()
299        }
300
301        if let KalkValue::Number(real, imaginary, _) = self {
302            if !self.has_imaginary() {
303                return trim_num(real.to_string());
304            }
305
306            let sign = if imaginary < &0f64 { "-" } else { "+" };
307            format!(
308                "{} {} {}i",
309                spaced(&trim_num(real.to_string())),
310                sign,
311                spaced(&trim_num(imaginary.to_string()))
312            )
313        } else {
314            trim_num(self.to_string())
315        }
316    }
317
318    pub fn to_string_real(&self, radix: u8) -> String {
319        radix::to_radix_pretty(self.to_f64(), radix)
320    }
321
322    pub fn to_string_imaginary(&self, radix: u8, include_i: bool) -> String {
323        let value = radix::to_radix_pretty(self.imaginary_to_f64(), radix);
324        if include_i && value == "1" {
325            String::from("i")
326        } else if include_i && value == "-1" {
327            String::from("-i")
328        } else if include_i {
329            format!("{}i", value)
330        } else {
331            value
332        }
333    }
334
335    pub fn to_string_pretty_radix(&self, radix: u8, format: ScientificNotationFormat) -> String {
336        let (real, imaginary, unit) = match self {
337            KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
338            _ => return self.to_string(),
339        };
340
341        let real_f64 = self.to_f64();
342        let imaginary_f64 = self.imaginary_to_f64();
343        if real_f64.is_nan() || imaginary_f64.is_nan() {
344            return String::from("Not defined.");
345        }
346
347        if real_f64.is_infinite() {
348            return format!("{}∞", if real_f64.is_sign_negative() { "-" } else { "" });
349        }
350
351        let sci_notation_real = self.to_scientific_notation(ComplexNumberType::Real);
352        let mut new_real = real.clone();
353        let mut new_imaginary = imaginary.clone();
354        let mut has_scientific_notation = false;
355        let is_engineering_mode = matches!(format, ScientificNotationFormat::Engineering);
356        let result_str = if is_engineering_mode {
357            has_scientific_notation = true;
358
359            sci_notation_real.to_string_format(ScientificNotationFormat::Engineering)
360        } else if (-6..8).contains(&sci_notation_real.exponent) || real == &0f64 {
361            self.to_string_real(radix)
362        } else if sci_notation_real.exponent <= -14 {
363            new_real = float!(0);
364
365            String::from("0")
366        } else if radix == 10 {
367            has_scientific_notation = true;
368
369            sci_notation_real.to_string_format(format)
370        } else {
371            self.to_string_real(radix)
372        };
373
374        let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
375        let result_str_imaginary = if is_engineering_mode {
376            has_scientific_notation = true;
377
378            sci_notation_imaginary.to_string_format(ScientificNotationFormat::Engineering)
379        } else if (-6..8).contains(&sci_notation_imaginary.exponent)
380            || imaginary == &0f64
381            || imaginary == &1f64
382        {
383            self.to_string_imaginary(radix, true)
384        } else if sci_notation_imaginary.exponent <= -14 {
385            new_imaginary = float!(0);
386            String::from("0")
387        } else if radix == 10 {
388            has_scientific_notation = true;
389
390            sci_notation_imaginary.to_string_format(format)
391        } else {
392            self.to_string_real(radix)
393        };
394
395        let mut output = result_str;
396        if imaginary != &0f64 && new_imaginary != 0f64 && result_str_imaginary != "0" {
397            // If the real value is 0, and there is an imaginary one,
398            // clear the output so that the real value is not shown.
399            if output == "0" {
400                output = String::new();
401            }
402
403            // If there is a real value as well
404            if !output.is_empty() {
405                output.push_str(&format!(
406                    " {} {}",
407                    if imaginary < &0f64 { "-" } else { "+" },
408                    result_str_imaginary.trim_start_matches('-'),
409                ));
410            } else {
411                output.push_str(&result_str_imaginary);
412            }
413        }
414
415        if let Some(unit) = unit {
416            output.push_str(&format!(" {}", unit));
417        }
418
419        let new_value = KalkValue::Number(new_real, new_imaginary, unit.clone());
420
421        if let Some(estimate) = new_value.estimate() {
422            if estimate.value != output && radix == 10 {
423                let equal_sign = if estimate.is_exact { "=" } else { "≈" };
424                output.push_str(&format!(" {equal_sign} {}", estimate.value));
425            }
426        } else if has_scientific_notation && !is_engineering_mode {
427            output.insert_str(0, &format!("{} ≈ ", self));
428        }
429
430        output
431    }
432
433    pub fn to_string_pretty(&self, format: ScientificNotationFormat) -> String {
434        self.to_string_pretty_radix(10, format)
435    }
436
437    pub fn to_string_with_unit(&self) -> String {
438        match self {
439            KalkValue::Number(_, _, unit) => {
440                format!("{} {}", self, unit.as_ref().unwrap_or(&String::new()))
441            }
442            _ => self.to_string(),
443        }
444    }
445
446    /// Get an estimate of what the number is, eg. 3.141592 => π. Does not work properly with scientific notation.
447    pub fn estimate(&self) -> Option<EstimationResult> {
448        let rounded_real = rounding::estimate(self, ComplexNumberType::Real);
449        let rounded_imaginary = rounding::estimate(self, ComplexNumberType::Imaginary);
450
451        if let (None, None) = (&rounded_real, &rounded_imaginary) {
452            return None;
453        }
454
455        let mut output = String::new();
456        let mut real_is_exact = rounded_real.is_none();
457        if let Some(result) = rounded_real {
458            real_is_exact = result.is_exact;
459            output.push_str(&result.value);
460        } else if self.has_real() {
461            output.push_str(&self.to_string_real(10));
462        }
463
464        let mut imaginary_is_exact = rounded_imaginary.is_none();
465        let imaginary_value = if let Some(result) = rounded_imaginary {
466            imaginary_is_exact = result.is_exact;
467
468            Some(result.value)
469        } else if self.has_imaginary() {
470            Some(self.to_string_imaginary(10, false))
471        } else {
472            None
473        };
474
475        let is_exact = real_is_exact && imaginary_is_exact;
476        if let Some(value) = imaginary_value {
477            // Clear output if it's just 0.
478            if output == "0" {
479                output = String::new();
480            }
481
482            if value == "0" {
483                // If both values ended up being estimated as zero,
484                // return zero.
485                if output.is_empty() {
486                    return Some(EstimationResult {
487                        value: String::from("0"),
488                        is_exact,
489                    });
490                }
491            } else {
492                let sign = if value.starts_with('-') { "-" } else { "+" };
493                let value = match value.as_ref() {
494                    "1" => String::from("i"),
495                    "-1" => String::from("-i"),
496                    _ => format!("{}i", value),
497                };
498
499                // If there is a real value as well
500                if !output.is_empty() {
501                    output.push_str(&format!(" {} {}", sign, value.trim_start_matches('-')));
502                } else {
503                    output.push_str(&value);
504                }
505            }
506        }
507
508        Some(EstimationResult {
509            value: output,
510            is_exact,
511        })
512    }
513
514    /// Basic up/down rounding from 0.00xxx or 0.999xxx or xx.000xxx, etc.
515    pub fn round(&self) -> Option<KalkValue> {
516        let rounded_real = rounding::round(self, ComplexNumberType::Real);
517        let rounded_imaginary = rounding::round(self, ComplexNumberType::Imaginary);
518
519        if let (None, None) = (&rounded_real, &rounded_imaginary) {
520            return None;
521        }
522
523        let (original_real, original_imaginary, unit) = match self {
524            KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
525            _ => return None,
526        };
527
528        Some(KalkValue::Number(
529            if let Some(KalkValue::Number(real, _, _)) = rounded_real {
530                real
531            } else {
532                original_real.clone()
533            },
534            if let Some(KalkValue::Number(_, imaginary, _)) = rounded_imaginary {
535                imaginary
536            } else {
537                original_imaginary.clone()
538            },
539            unit.clone(),
540        ))
541    }
542
543    pub fn round_if_needed(self) -> KalkValue {
544        if let Some(rounded) = self.round() {
545            rounded
546        } else {
547            self
548        }
549    }
550
551    pub fn has_real(&self) -> bool {
552        if let KalkValue::Number(real, _, _) = self {
553            real != &0f64
554        } else {
555            false
556        }
557    }
558
559    pub fn has_imaginary(&self) -> bool {
560        if let KalkValue::Number(_, imaginary, _) = self {
561            imaginary != &0f64 && imaginary != &-0f64
562        } else {
563            false
564        }
565    }
566
567    pub fn is_nan(&self) -> bool {
568        if let KalkValue::Number(real, imaginary, _) = self {
569            real.is_nan() || imaginary.is_nan()
570        } else {
571            false
572        }
573    }
574
575    pub fn is_finite(&self) -> bool {
576        //#[cfg(feature = "rug")]
577        if let KalkValue::Number(real, imaginary, _) = self {
578            real.is_finite() && imaginary.is_finite()
579        } else {
580            false
581        }
582        //#[cfg(not(feature = "rug"))]
583        //if let KalkValue::Number(real, imaginary, _) = self {
584        //    real.is_finite() && imaginary.is_finite()
585        //} else {
586        //    false
587        //}
588    }
589
590    pub fn to_scientific_notation(
591        &self,
592        complex_number_type: ComplexNumberType,
593    ) -> ScientificNotation {
594        let value = match complex_number_type {
595            ComplexNumberType::Real => self.to_f64(),
596            ComplexNumberType::Imaginary => self.imaginary_to_f64(),
597        };
598        let exponent = value.abs().log10().floor() as i32 + 1;
599
600        ScientificNotation {
601            value: value / (10f64.powf(exponent as f64 - 1f64)),
602            // I... am not sure what else to do...
603            exponent,
604            imaginary: complex_number_type == ComplexNumberType::Imaginary,
605        }
606    }
607
608    pub fn has_unit(&self) -> bool {
609        if let KalkValue::Number(_, _, unit) = self {
610            unit.is_some()
611        } else {
612            false
613        }
614    }
615
616    pub fn get_unit(&self) -> Option<&String> {
617        if let KalkValue::Number(_, _, unit) = self {
618            unit.as_ref()
619        } else {
620            None
621        }
622    }
623
624    pub(crate) fn convert_to_unit(
625        &self,
626        context: &mut crate::interpreter::Context,
627        to_unit: &str,
628    ) -> Option<KalkValue> {
629        if let KalkValue::Number(real, _, unit) = self {
630            let result = crate::interpreter::convert_unit(
631                context,
632                &Expr::Literal(real.clone()),
633                unit.as_ref(),
634                Some(&to_unit.to_string()),
635            );
636
637            if let Ok(num) = result {
638                Some(num)
639            } else {
640                None
641            }
642        } else {
643            None
644        }
645    }
646
647    pub(crate) fn add(
648        self,
649        context: &mut crate::interpreter::Context,
650        rhs: KalkValue,
651    ) -> Result<KalkValue, KalkError> {
652        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
653        self.add_without_unit(&right)
654    }
655
656    pub(crate) fn sub(
657        self,
658        context: &mut crate::interpreter::Context,
659        rhs: KalkValue,
660    ) -> Result<KalkValue, KalkError> {
661        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
662        self.sub_without_unit(&right)
663    }
664
665    pub(crate) fn mul(
666        self,
667        context: &mut crate::interpreter::Context,
668        rhs: KalkValue,
669    ) -> Result<KalkValue, KalkError> {
670        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
671        self.mul_without_unit(&right)
672    }
673
674    pub(crate) fn div(
675        self,
676        context: &mut crate::interpreter::Context,
677        rhs: KalkValue,
678    ) -> Result<KalkValue, KalkError> {
679        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
680        self.div_without_unit(&right)
681    }
682
683    pub(crate) fn pow(
684        self,
685        context: &mut crate::interpreter::Context,
686        rhs: KalkValue,
687    ) -> Result<KalkValue, KalkError> {
688        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
689        self.pow_without_unit(&right)
690    }
691
692    pub(crate) fn rem(
693        self,
694        context: &mut crate::interpreter::Context,
695        rhs: KalkValue,
696    ) -> Result<KalkValue, KalkError> {
697        Ok(if let KalkValue::Number(real, _, _) = &self {
698            let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
699            if let KalkValue::Number(right_real, _, right_unit) = right {
700                KalkValue::Number(real % right_real, float!(0f64), right_unit)
701            } else {
702                self
703            }
704        } else {
705            self
706        })
707    }
708
709    pub(crate) fn eq(
710        self,
711        context: &mut crate::interpreter::Context,
712        rhs: KalkValue,
713    ) -> Result<KalkValue, KalkError> {
714        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
715        self.eq_without_unit(&right)
716    }
717
718    pub(crate) fn not_eq(
719        self,
720        context: &mut crate::interpreter::Context,
721        rhs: KalkValue,
722    ) -> Result<KalkValue, KalkError> {
723        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
724        self.not_eq_without_unit(&right)
725    }
726
727    pub(crate) fn greater_than(
728        self,
729        context: &mut crate::interpreter::Context,
730        rhs: KalkValue,
731    ) -> Result<KalkValue, KalkError> {
732        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
733        self.greater_than_without_unit(&right)
734    }
735
736    pub(crate) fn less_than(
737        self,
738        context: &mut crate::interpreter::Context,
739        rhs: KalkValue,
740    ) -> Result<KalkValue, KalkError> {
741        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
742        self.less_than_without_unit(&right)
743    }
744
745    pub(crate) fn greater_or_equals(
746        self,
747        context: &mut crate::interpreter::Context,
748        rhs: KalkValue,
749    ) -> Result<KalkValue, KalkError> {
750        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
751        if let (KalkValue::Boolean(greater), KalkValue::Boolean(equal)) = (
752            self.greater_than_without_unit(&right)?,
753            self.eq_without_unit(&right)?,
754        ) {
755            Ok(KalkValue::Boolean(greater || equal))
756        } else {
757            unreachable!()
758        }
759    }
760
761    pub(crate) fn less_or_equals(
762        self,
763        context: &mut crate::interpreter::Context,
764        rhs: KalkValue,
765    ) -> Result<KalkValue, KalkError> {
766        let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
767        if let (KalkValue::Boolean(less), KalkValue::Boolean(equal)) = (
768            self.less_than_without_unit(&right)?,
769            self.eq_without_unit(&right)?,
770        ) {
771            Ok(KalkValue::Boolean(less || equal))
772        } else {
773            unreachable!()
774        }
775    }
776
777    pub(crate) fn and(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
778        match (self, rhs) {
779            (KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
780                Ok(KalkValue::Boolean(boolean && *boolean_rhs))
781            }
782            (lhs, rhs) => Err(KalkError::IncompatibleTypesForOperation(
783                String::from("and"),
784                lhs.get_type_name(),
785                rhs.get_type_name(),
786            )),
787        }
788    }
789
790    pub(crate) fn or(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
791        match (self, rhs) {
792            (KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
793                Ok(KalkValue::Boolean(boolean || *boolean_rhs))
794            }
795            (lhs, rhs) => Err(KalkError::IncompatibleTypesForOperation(
796                String::from("or"),
797                lhs.get_type_name(),
798                rhs.get_type_name(),
799            )),
800        }
801    }
802
803    pub(crate) fn add_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
804        match (self.clone(), rhs) {
805            (
806                KalkValue::Number(real, imaginary, _),
807                KalkValue::Number(real_rhs, imaginary_rhs, unit),
808            ) => Ok(KalkValue::Number(
809                real + real_rhs,
810                imaginary + imaginary_rhs,
811                unit.clone(),
812            )),
813            (KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
814                calculate_matrix(self, rhs, &KalkValue::add_without_unit)
815            }
816            (KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
817                calculate_vector(self, rhs, &KalkValue::add_without_unit)
818            }
819            _ => Err(KalkError::IncompatibleTypesForOperation(
820                String::from("addition"),
821                self.get_type_name(),
822                rhs.get_type_name(),
823            )),
824        }
825    }
826
827    pub(crate) fn sub_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
828        match (self.clone(), rhs) {
829            (
830                KalkValue::Number(real, imaginary, _),
831                KalkValue::Number(real_rhs, imaginary_rhs, unit),
832            ) => Ok(KalkValue::Number(
833                real - real_rhs,
834                imaginary - imaginary_rhs,
835                unit.clone(),
836            )),
837            (KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
838                calculate_matrix(self, rhs, &KalkValue::sub_without_unit)
839            }
840            (KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
841                calculate_vector(self, rhs, &KalkValue::sub_without_unit)
842            }
843            _ => Err(KalkError::IncompatibleTypesForOperation(
844                String::from("subtraction"),
845                self.get_type_name(),
846                rhs.get_type_name(),
847            )),
848        }
849    }
850
851    pub(crate) fn mul_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
852        // Make sure matrix is always first to avoid having to match
853        // different orders in the next match expression.
854        let (lhs, rhs) = match (&self, rhs) {
855            (KalkValue::Matrix(_), KalkValue::Matrix(_)) => (&self, rhs),
856            (_, KalkValue::Matrix(_)) => (rhs, &self),
857            _ => (&self, rhs),
858        };
859
860        match (lhs, rhs) {
861            (
862                KalkValue::Number(real, imaginary, _),
863                KalkValue::Number(real_rhs, imaginary_rhs, unit),
864            ) => Ok(KalkValue::Number(
865                // (a + bi)(c + di) = ac + adi + bci + bdi²
866                real.clone() * real_rhs - imaginary.clone() * imaginary_rhs,
867                real.clone() * imaginary_rhs + imaginary * real_rhs,
868                unit.clone(),
869            )),
870            (KalkValue::Matrix(_), KalkValue::Number(_, _, _)) => {
871                calculate_matrix(lhs.clone(), rhs, &KalkValue::mul_without_unit)
872            }
873            (KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
874                if rows.first().unwrap().len() != values_rhs.len() {
875                    return Err(KalkError::IncompatibleVectorsMatrixes);
876                }
877
878                let mut new_values: Vec<KalkValue> = Vec::new();
879                for row in rows {
880                    let mut sum = KalkValue::from(0);
881                    for (x, y) in row.iter().zip(values_rhs) {
882                        sum = sum
883                            .clone()
884                            .add_without_unit(&x.clone().mul_without_unit(y)?)?;
885                    }
886
887                    new_values.push(sum);
888                }
889
890                Ok(KalkValue::Vector(new_values))
891            }
892            (KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
893                let lhs_columns = rows.first().unwrap();
894                if lhs_columns.len() != rows_rhs.len() {
895                    return Err(KalkError::IncompatibleVectorsMatrixes);
896                }
897
898                let rhs_columns = rows_rhs.first().unwrap();
899                let mut result = vec![vec![KalkValue::from(0f64); rhs_columns.len()]; rows.len()];
900
901                // For every row in lhs
902                for i in 0..rows.len() {
903                    // For every column in rhs
904                    for j in 0..rhs_columns.len() {
905                        let mut sum = KalkValue::from(0f64);
906
907                        // For every value in the current lhs row
908                        for (k, value) in rows[i].iter().enumerate() {
909                            let value_rhs = &rows_rhs[k][j];
910                            sum =
911                                sum.add_without_unit(&value.clone().mul_without_unit(value_rhs)?)?;
912                        }
913
914                        result[i][j] = sum;
915                    }
916                }
917
918                Ok(KalkValue::Matrix(result))
919            }
920            (KalkValue::Vector(values), KalkValue::Number(_, _, _)) => {
921                let mut multiplied_values = Vec::new();
922                for value in values {
923                    multiplied_values.push(value.clone().mul_without_unit(rhs)?);
924                }
925
926                Ok(KalkValue::Vector(multiplied_values))
927            }
928            (KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
929                if values.len() != values_rhs.len() {
930                    return Err(KalkError::IncompatibleVectorsMatrixes);
931                }
932
933                let mut sum = KalkValue::from(0f64);
934                for (value, value_rhs) in values.iter().zip(values_rhs) {
935                    sum = sum.add_without_unit(&value.clone().mul_without_unit(value_rhs)?)?;
936                }
937
938                Ok(sum)
939            }
940            _ => Err(KalkError::IncompatibleTypesForOperation(
941                String::from("multiplication"),
942                self.get_type_name(),
943                rhs.get_type_name(),
944            )),
945        }
946    }
947
948    pub(crate) fn div_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
949        match (self.clone(), rhs.clone()) {
950            (KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, unit)) => {
951                // Avoid unecessary calculations
952                if !self.has_imaginary() && !rhs.has_imaginary() {
953                    Ok(KalkValue::Number(real / real_rhs, float!(0f64), unit))
954                } else {
955                    // Multiply both the numerator and denominator
956                    // with the conjugate of the denominator, and divide.
957                    let conjugate = rhs.get_conjugate()?;
958                    let (numerator, numerator_imaginary) =
959                        self.mul_without_unit(&conjugate)?.values();
960                    let (denominator, _) = rhs.clone().mul_without_unit(&conjugate)?.values();
961                    Ok(KalkValue::Number(
962                        numerator / denominator.clone(),
963                        numerator_imaginary / denominator,
964                        unit,
965                    ))
966                }
967            }
968            (KalkValue::Matrix(_), _) | (_, KalkValue::Matrix(_)) => {
969                calculate_matrix(self, rhs, &KalkValue::div_without_unit)
970            }
971            (KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
972                calculate_vector(self, rhs, &KalkValue::div_without_unit)
973            }
974            _ => Err(KalkError::IncompatibleTypesForOperation(
975                String::from("division"),
976                self.get_type_name(),
977                rhs.get_type_name(),
978            )),
979        }
980    }
981
982    pub(crate) fn pow_without_unit(self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
983        match (self.clone(), rhs) {
984            (
985                KalkValue::Number(real, imaginary, _),
986                KalkValue::Number(real_rhs, imaginary_rhs, unit),
987            ) => {
988                if self.has_imaginary()
989                    || imaginary_rhs != &0f64
990                    || (real < 0f64 && real_rhs.clone().abs() < 1f64)
991                {
992                    let a = real;
993                    let b = imaginary;
994                    let c = real_rhs;
995                    let d = imaginary_rhs;
996                    let arg = crate::prelude::funcs::arg(self)?.values().0;
997                    let raised = a.clone() * a + b.clone() * b;
998                    let exp =
999                        pow(raised.clone(), c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
1000                    let polar = c * arg + d.clone() / 2f64 * raised.ln();
1001
1002                    Ok(KalkValue::Number(
1003                        polar.clone().cos() * exp.clone(),
1004                        polar.sin() * exp,
1005                        unit.clone(),
1006                    ))
1007                } else {
1008                    Ok(KalkValue::Number(
1009                        pow(real, real_rhs.clone()),
1010                        float!(0),
1011                        unit.clone(),
1012                    ))
1013                }
1014            }
1015            (KalkValue::Matrix(rows), KalkValue::Number(real, _, _)) => {
1016                if real < &0f64 || real.clone().fract() > 0.000001f64 {
1017                    return Err(KalkError::Expected(String::from("a positive integer")));
1018                }
1019
1020                if rhs.has_imaginary() {
1021                    return Err(KalkError::ExpectedReal);
1022                }
1023
1024                if rows.len() != rows.first().unwrap().len() {
1025                    return Err(KalkError::Expected(String::from("a square matrix")));
1026                }
1027
1028                if real == &0f64 {
1029                    return Ok(KalkValue::from(1f64));
1030                }
1031
1032                let mut result = KalkValue::from(1f64);
1033                for _ in 0..primitive!(real) as i32 {
1034                    result = result.mul_without_unit(&self)?;
1035                }
1036
1037                Ok(result)
1038            }
1039            (KalkValue::Number(_, _, _), KalkValue::Matrix(rows)) => {
1040                let mut new_rows = Vec::new();
1041                for row in rows {
1042                    new_rows.push(Vec::new());
1043                    for item in row {
1044                        new_rows
1045                            .last_mut()
1046                            .unwrap()
1047                            .push(self.clone().pow_without_unit(item)?);
1048                    }
1049                }
1050
1051                Ok(KalkValue::Matrix(new_rows))
1052            }
1053            (KalkValue::Vector(_), _) | (_, KalkValue::Vector(_)) => {
1054                calculate_vector(self, rhs, &KalkValue::pow_without_unit)
1055            }
1056            _ => Err(KalkError::IncompatibleTypesForOperation(
1057                String::from("pow"),
1058                self.get_type_name(),
1059                rhs.get_type_name(),
1060            )),
1061        }
1062    }
1063
1064    pub(crate) fn eq_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
1065        match (self, rhs) {
1066            (
1067                KalkValue::Number(real, imaginary, _),
1068                KalkValue::Number(real_rhs, imaginary_rhs, _),
1069            ) => Ok(KalkValue::Boolean(
1070                (real.clone() - real_rhs.clone()).abs() < ACCEPTABLE_COMPARISON_MARGIN
1071                    && (imaginary.clone() - imaginary_rhs.clone()).abs()
1072                        < ACCEPTABLE_COMPARISON_MARGIN,
1073            )),
1074            (KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
1075                Ok(KalkValue::Boolean(boolean == boolean_rhs))
1076            }
1077            (KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
1078                let mut matrices_are_equal = true;
1079                for (row, row_rhs) in rows.iter().zip(rows_rhs) {
1080                    for (value, value_rhs) in row.iter().zip(row_rhs) {
1081                        if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs)? {
1082                            if !are_equal {
1083                                matrices_are_equal = false;
1084                            }
1085                        }
1086                    }
1087                }
1088
1089                Ok(KalkValue::Boolean(matrices_are_equal))
1090            }
1091
1092            (KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
1093                let mut vecs_are_equal = true;
1094                for (value, value_rhs) in values.iter().zip(values_rhs) {
1095                    if let KalkValue::Boolean(are_equal) = value.eq_without_unit(value_rhs)? {
1096                        if !are_equal {
1097                            vecs_are_equal = false;
1098                        }
1099                    }
1100                }
1101
1102                Ok(KalkValue::Boolean(vecs_are_equal))
1103            }
1104            _ => Err(KalkError::IncompatibleTypesForOperation(
1105                String::from("equal"),
1106                self.get_type_name(),
1107                rhs.get_type_name(),
1108            )),
1109        }
1110    }
1111
1112    pub(crate) fn not_eq_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
1113        match (self, rhs) {
1114            (
1115                KalkValue::Number(real, imaginary, _),
1116                KalkValue::Number(real_rhs, imaginary_rhs, _),
1117            ) => Ok(KalkValue::Boolean(
1118                (real.clone() - real_rhs.clone()).abs() > ACCEPTABLE_COMPARISON_MARGIN
1119                    || (imaginary.clone() - imaginary_rhs.clone()).abs()
1120                        > ACCEPTABLE_COMPARISON_MARGIN,
1121            )),
1122            (KalkValue::Boolean(boolean), KalkValue::Boolean(boolean_rhs)) => {
1123                Ok(KalkValue::Boolean(boolean != boolean_rhs))
1124            }
1125            (KalkValue::Vector(_), KalkValue::Vector(_))
1126            | (KalkValue::Matrix(_), KalkValue::Matrix(_)) => {
1127                if let KalkValue::Boolean(boolean) = self.eq_without_unit(rhs)? {
1128                    Ok(KalkValue::Boolean(!boolean))
1129                } else {
1130                    unreachable!()
1131                }
1132            }
1133            _ => Err(KalkError::IncompatibleTypesForOperation(
1134                String::from("not equal"),
1135                self.get_type_name(),
1136                rhs.get_type_name(),
1137            )),
1138        }
1139    }
1140
1141    pub(crate) fn greater_than_without_unit(
1142        &self,
1143        rhs: &KalkValue,
1144    ) -> Result<KalkValue, KalkError> {
1145        if self.has_imaginary() || rhs.has_imaginary() {
1146            return Err(KalkError::ExpectedReal);
1147        }
1148
1149        match (self, rhs) {
1150            (KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
1151                KalkValue::Boolean(real.clone() - real_rhs.clone() > ACCEPTABLE_COMPARISON_MARGIN),
1152            ),
1153            _ => Err(KalkError::IncompatibleTypesForOperation(
1154                String::from("greater than"),
1155                self.get_type_name(),
1156                rhs.get_type_name(),
1157            )),
1158        }
1159    }
1160
1161    pub(crate) fn less_than_without_unit(&self, rhs: &KalkValue) -> Result<KalkValue, KalkError> {
1162        if self.has_imaginary() || rhs.has_imaginary() {
1163            return Err(KalkError::ExpectedReal);
1164        }
1165
1166        match (self, rhs) {
1167            (KalkValue::Number(real, _, _), KalkValue::Number(real_rhs, _, _)) => Ok(
1168                KalkValue::Boolean(real.clone() - real_rhs.clone() < -ACCEPTABLE_COMPARISON_MARGIN),
1169            ),
1170            _ => Err(KalkError::IncompatibleTypesForOperation(
1171                String::from("less than"),
1172                self.get_type_name(),
1173                rhs.get_type_name(),
1174            )),
1175        }
1176    }
1177
1178    pub fn get_conjugate(&self) -> Result<KalkValue, KalkError> {
1179        match self {
1180            KalkValue::Number(real, imaginary, unit) => Ok(KalkValue::Number(
1181                real.clone(),
1182                imaginary.clone() * (-1f64),
1183                unit.clone(),
1184            )),
1185            _ => Err(KalkError::UnexpectedType(
1186                self.get_type_name(),
1187                vec![String::from("number")],
1188            )),
1189        }
1190    }
1191}
1192
1193pub fn format_number(input: f64) -> String {
1194    let rounded = format!("{:.1$}", input, 10);
1195    let result = if rounded.contains('.') {
1196        rounded
1197            .trim_end_matches('0')
1198            .trim_end_matches('.')
1199            .to_string()
1200    } else {
1201        rounded
1202    };
1203
1204    spaced(&result)
1205}
1206
1207#[cfg(feature = "rug")]
1208pub fn format_number_big(input: &Float) -> String {
1209    if input.clone().abs().log10() < 0f64 {
1210        return input.to_f64().to_string();
1211    }
1212
1213    let input_str = input.to_string();
1214    let mut result = if input_str.contains('.') {
1215        input_str
1216            .trim_end_matches('0')
1217            .trim_end_matches('.')
1218            .to_string()
1219    } else {
1220        input_str
1221    };
1222
1223    if let Some(dot_index) = result.find('.') {
1224        let decimal_count = result.len() - dot_index;
1225        if decimal_count > 10 {
1226            result = result[..(result.len() - decimal_count + 10)].to_string();
1227        }
1228    }
1229
1230    spaced(&result)
1231}
1232
1233#[cfg(not(feature = "rug"))]
1234pub fn format_number_big(input: &f64) -> String {
1235    format_number(*input)
1236}
1237
1238fn calculate_vector(
1239    x: KalkValue,
1240    y: &KalkValue,
1241    action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
1242) -> Result<KalkValue, KalkError> {
1243    match (x, y) {
1244        (KalkValue::Vector(values), KalkValue::Number(_, _, _)) => {
1245            let mut new_values = Vec::new();
1246            for value in values {
1247                new_values.push(action(value.clone(), y)?);
1248            }
1249
1250            Ok(KalkValue::Vector(new_values))
1251        }
1252        (KalkValue::Number(_, _, _), KalkValue::Vector(values_rhs)) => {
1253            let mut new_values = Vec::new();
1254            for value in values_rhs {
1255                new_values.push(action(y.clone(), value)?);
1256            }
1257
1258            Ok(KalkValue::Vector(new_values))
1259        }
1260        (KalkValue::Vector(values), KalkValue::Vector(values_rhs)) => {
1261            if values.len() != values_rhs.len() {
1262                return Err(KalkError::IncompatibleVectorsMatrixes);
1263            }
1264
1265            let mut new_values = Vec::new();
1266            for (value, value_rhs) in values.iter().zip(values_rhs) {
1267                new_values.push(action(value.clone(), value_rhs)?);
1268            }
1269
1270            Ok(KalkValue::Vector(new_values))
1271        }
1272        (x, y) => Err(KalkError::IncompatibleTypesForOperation(
1273            String::from("vector operation"),
1274            x.get_type_name(),
1275            y.get_type_name(),
1276        )),
1277    }
1278}
1279
1280fn calculate_matrix(
1281    x: KalkValue,
1282    y: &KalkValue,
1283    action: &dyn Fn(KalkValue, &KalkValue) -> Result<KalkValue, KalkError>,
1284) -> Result<KalkValue, KalkError> {
1285    // Make sure matrix is always first to avoid having to match
1286    // different orders in the next match expression.
1287    let (x, y) = match (&x, y) {
1288        (KalkValue::Matrix(_), KalkValue::Matrix(_)) => (&x, y),
1289        (_, KalkValue::Matrix(_)) => (y, &x),
1290        _ => (&x, y),
1291    };
1292
1293    match (x, y) {
1294        (KalkValue::Matrix(rows), KalkValue::Number(_, _, _)) => {
1295            let mut new_rows = Vec::new();
1296            for row in rows {
1297                new_rows.push(Vec::new());
1298                for item in row {
1299                    new_rows.last_mut().unwrap().push(action(item.clone(), y)?);
1300                }
1301            }
1302
1303            Ok(KalkValue::Matrix(new_rows))
1304        }
1305        (KalkValue::Matrix(rows), KalkValue::Vector(values_rhs)) => {
1306            if rows.len() != values_rhs.len() {
1307                return Err(KalkError::IncompatibleVectorsMatrixes);
1308            }
1309
1310            let mut new_rows = Vec::new();
1311            for (i, row) in rows.iter().enumerate() {
1312                new_rows.push(Vec::new());
1313                for value in row {
1314                    new_rows
1315                        .last_mut()
1316                        .unwrap()
1317                        .push(action(value.clone(), &values_rhs[i])?)
1318                }
1319            }
1320
1321            Ok(KalkValue::Matrix(new_rows))
1322        }
1323        (KalkValue::Matrix(rows), KalkValue::Matrix(rows_rhs)) => {
1324            if rows.len() != rows_rhs.len()
1325                || rows.first().unwrap().len() != rows_rhs.first().unwrap().len()
1326            {
1327                return Err(KalkError::IncompatibleVectorsMatrixes);
1328            }
1329
1330            let mut new_rows = Vec::new();
1331            for (i, row) in rows.iter().enumerate() {
1332                new_rows.push(Vec::new());
1333                for (j, value) in row.iter().enumerate() {
1334                    new_rows
1335                        .last_mut()
1336                        .unwrap()
1337                        .push(action(value.clone(), &rows_rhs[i][j])?)
1338                }
1339            }
1340
1341            Ok(KalkValue::Matrix(new_rows))
1342        }
1343        _ => Err(KalkError::IncompatibleTypesForOperation(
1344            String::from("matrix operation"),
1345            x.get_type_name(),
1346            y.get_type_name(),
1347        )),
1348    }
1349}
1350
1351fn spaced(number_str: &str) -> String {
1352    let dot_pos = number_str.find('.');
1353    let integer_boundary = if let Some(dot_pos) = dot_pos {
1354        dot_pos
1355    } else {
1356        number_str.len()
1357    };
1358
1359    if integer_boundary < 5 {
1360        return number_str.into();
1361    }
1362
1363    let bytes = number_str.as_bytes();
1364    let mut at_decimals = dot_pos.is_some();
1365    let mut i = number_str.len() - 1;
1366    let mut c = 0;
1367    let mut new_str = String::new();
1368    while i > 0 {
1369        if bytes[i] as char == '.' {
1370            new_str.push('.');
1371            at_decimals = false;
1372            i -= 1;
1373            c = 0;
1374            continue;
1375        }
1376
1377        if !at_decimals && c == 3 {
1378            new_str.push(' ');
1379            c = 0;
1380        }
1381
1382        new_str.push(bytes[i] as char);
1383        c += 1;
1384        i -= 1;
1385    }
1386
1387    if c == 3 {
1388        new_str.push(' ');
1389    }
1390    new_str.push(bytes[0] as char);
1391
1392    new_str.chars().rev().collect::<String>()
1393}
1394
1395fn calculate_unit(
1396    context: &mut crate::interpreter::Context,
1397    left: &KalkValue,
1398    right: KalkValue,
1399) -> Option<KalkValue> {
1400    if let (KalkValue::Number(_, _, unit_left), KalkValue::Number(real_right, imaginary_right, _)) =
1401        (left, &right)
1402    {
1403        if left.has_unit() && right.has_unit() {
1404            right.convert_to_unit(context, unit_left.as_ref().unwrap())
1405        } else {
1406            Some(KalkValue::Number(
1407                real_right.clone(),
1408                imaginary_right.clone(),
1409                unit_left.clone(),
1410            ))
1411        }
1412    } else {
1413        None
1414    }
1415}
1416
1417#[cfg(not(feature = "rug"))]
1418fn pow(x: f64, y: f64) -> f64 {
1419    x.powf(y)
1420}
1421
1422#[cfg(feature = "rug")]
1423fn pow(x: Float, y: Float) -> Float {
1424    x.pow(y)
1425}
1426
1427impl From<ScientificNotation> for String {
1428    fn from(val: ScientificNotation) -> Self {
1429        val.to_string()
1430    }
1431}
1432
1433/*impl std::iter::Sum<KalkValue> for KalkValue {
1434    fn sum<I>(iter: I) -> KalkValue
1435    where
1436        I: std::iter::Iterator<Item = KalkValue>,
1437    {
1438        let mut sum = KalkValue::from(0f64);
1439        for x in iter {
1440            sum = sum.add_without_unit(&x);
1441        }
1442
1443        sum
1444    }
1445}*/
1446
1447impl From<KalkValue> for String {
1448    fn from(val: KalkValue) -> Self {
1449        val.to_string()
1450    }
1451}
1452
1453impl From<KalkValue> for f64 {
1454    fn from(val: KalkValue) -> Self {
1455        val.to_f64()
1456    }
1457}
1458
1459impl From<f64> for KalkValue {
1460    fn from(x: f64) -> Self {
1461        KalkValue::Number(float!(x), float!(0), None)
1462    }
1463}
1464
1465impl From<f32> for KalkValue {
1466    fn from(x: f32) -> Self {
1467        KalkValue::Number(float!(x), float!(0), None)
1468    }
1469}
1470
1471impl From<i128> for KalkValue {
1472    fn from(x: i128) -> Self {
1473        KalkValue::Number(float!(x), float!(0), None)
1474    }
1475}
1476
1477impl From<i64> for KalkValue {
1478    fn from(x: i64) -> Self {
1479        KalkValue::Number(float!(x), float!(0), None)
1480    }
1481}
1482
1483impl From<i32> for KalkValue {
1484    fn from(x: i32) -> Self {
1485        KalkValue::Number(float!(x), float!(0), None)
1486    }
1487}
1488
1489#[cfg(test)]
1490mod tests {
1491    use crate::kalk_value::{spaced, KalkValue, ScientificNotationFormat};
1492    use crate::test_helpers::cmp;
1493
1494    use super::ScientificNotation;
1495
1496    #[test]
1497    fn test_spaced() {
1498        assert_eq!(spaced("1"), String::from("1"));
1499        assert_eq!(spaced("10"), String::from("10"));
1500        assert_eq!(spaced("100"), String::from("100"));
1501        assert_eq!(spaced("1000"), String::from("1000"));
1502        assert_eq!(spaced("10000"), String::from("10 000"));
1503        assert_eq!(spaced("100000"), String::from("100 000"));
1504        assert_eq!(spaced("1000000"), String::from("1 000 000"));
1505        assert_eq!(spaced("10000000"), String::from("10 000 000"));
1506        assert_eq!(spaced("1.12345"), String::from("1.12345"));
1507        assert_eq!(spaced("10.12345"), String::from("10.12345"));
1508        assert_eq!(spaced("100.12345"), String::from("100.12345"));
1509        assert_eq!(spaced("1000.12345"), String::from("1000.12345"));
1510        assert_eq!(spaced("10000.12345"), String::from("10 000.12345"));
1511        assert_eq!(spaced("100000.12345"), String::from("100 000.12345"));
1512        assert_eq!(spaced("1000000.12345"), String::from("1 000 000.12345"));
1513        assert_eq!(spaced("10000000.12345"), String::from("10 000 000.12345"));
1514    }
1515
1516    #[test]
1517    fn test_add_complex() {
1518        let in_out = vec![
1519            ((0f64, 0f64), (0f64, 0f64), (0f64, 0f64)),
1520            ((2f64, 0f64), (3f64, 4f64), (5f64, 4f64)),
1521            ((0f64, 2f64), (3f64, 4f64), (3f64, 6f64)),
1522            ((3f64, -2f64), (-3f64, 4f64), (0f64, 2f64)),
1523        ];
1524
1525        for (a, b, expected_result) in in_out {
1526            let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
1527                .add_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
1528                .unwrap();
1529            assert_eq!(actual_result.to_f64(), expected_result.0);
1530            assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
1531        }
1532    }
1533
1534    #[test]
1535    fn test_sub_complex() {
1536        let in_out = vec![
1537            ((0f64, 0f64), (0f64, 0f64), (0f64, 0f64)),
1538            ((2f64, 0f64), (3f64, 4f64), (-1f64, -4f64)),
1539            ((0f64, 2f64), (3f64, 4f64), (-3f64, -2f64)),
1540            ((3f64, -2f64), (-3f64, 4f64), (6f64, -6f64)),
1541        ];
1542
1543        for (a, b, expected_result) in in_out {
1544            let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
1545                .sub_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
1546                .unwrap();
1547            assert_eq!(actual_result.to_f64(), expected_result.0);
1548            assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
1549        }
1550    }
1551
1552    #[test]
1553    fn test_mul_complex() {
1554        let in_out = vec![
1555            ((0f64, 0f64), (0f64, 0f64), (0f64, 0f64)),
1556            ((2f64, 0f64), (3f64, 4f64), (6f64, 8f64)),
1557            ((0f64, 2f64), (3f64, 4f64), (-8f64, 6f64)),
1558            ((3f64, -2f64), (-3f64, 4f64), (-1f64, 18f64)),
1559        ];
1560
1561        for (a, b, expected_result) in in_out {
1562            let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
1563                .mul_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
1564                .unwrap();
1565            assert_eq!(actual_result.to_f64(), expected_result.0);
1566            assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
1567        }
1568    }
1569
1570    #[test]
1571    fn test_div_complex() {
1572        let in_out = vec![
1573            ((2f64, 0f64), (3f64, 4f64), (0.24f64, -0.32f64)),
1574            ((0f64, 2f64), (3f64, 4f64), (0.32f64, 0.24f64)),
1575            ((3f64, -2f64), (-3f64, 4f64), (-0.68f64, -0.24f64)),
1576        ];
1577
1578        for (a, b, expected_result) in in_out {
1579            let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
1580                .div_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
1581                .unwrap();
1582            assert_eq!(actual_result.to_f64(), expected_result.0);
1583            assert_eq!(actual_result.imaginary_to_f64(), expected_result.1);
1584        }
1585    }
1586
1587    #[test]
1588    fn test_pow_complex() {
1589        let in_out = vec![
1590            ((2f64, 0f64), (0f64, 3f64), (-0.4869944f64, 0.8734050f64)),
1591            ((2f64, 0f64), (2f64, 3f64), (-1.9479776f64, 3.4936203f64)),
1592            ((0f64, 2f64), (0f64, 3f64), (-0.0043748f64, 0.0078460f64)),
1593            ((3f64, 2f64), (0f64, 3f64), (-0.1304148f64, -0.111153f64)),
1594            ((3f64, 2f64), (4f64, 3f64), (28.8577819f64, -2.422530f64)),
1595            ((-9f64, 0f64), (0.5f64, 0f64), (0f64, 3f64)),
1596            ((-9f64, 0f64), (-0.5f64, 0f64), (0f64, -1f64 / 3f64)),
1597            (
1598                (3f64, 0f64),
1599                (0f64, 1f64 / 3f64),
1600                (0.9336932f64, 0.3580738f64),
1601            ),
1602            (
1603                (3f64, 4f64),
1604                (0f64, 1f64 / 4f64),
1605                (0.7297490f64, 0.3105648f64),
1606            ),
1607        ];
1608
1609        for (a, b, expected_result) in in_out {
1610            let actual_result = KalkValue::Number(float!(a.0), float!(a.1), None)
1611                .pow_without_unit(&KalkValue::Number(float!(b.0), float!(b.1), None))
1612                .unwrap();
1613            assert!(cmp(actual_result.to_f64(), expected_result.0));
1614            assert!(cmp(actual_result.imaginary_to_f64(), expected_result.1));
1615        }
1616    }
1617
1618    #[test]
1619    fn test_to_string_pretty() {
1620        let in_out = vec![
1621            (float!(0.99999), float!(0.0), "0.99999 ≈ 1"),
1622            (float!(0.00000001), float!(0.0), "0.00000001 ≈ 10^-8"),
1623            (float!(-0.99999), float!(0.0), "-0.99999 ≈ -1"),
1624            (float!(0.0), float!(0.99999), "0.99999i ≈ i"),
1625            (float!(0.000000001), float!(0.0), "10^-9 ≈ 0"),
1626            (float!(0.0), float!(0.000000001), "10^-9 i ≈ 0"),
1627            (
1628                float!(0.99999),
1629                float!(0.999999),
1630                "0.99999 + 0.999999i ≈ 1 + i",
1631            ),
1632            (float!(1.0), float!(0.99999), "1 + 0.99999i ≈ 1 + i"),
1633            (
1634                float!(-0.99999),
1635                float!(0.999999),
1636                "-0.99999 + 0.999999i ≈ -1 + i",
1637            ),
1638            (
1639                float!(0.99999),
1640                float!(-0.999999),
1641                "0.99999 - 0.999999i ≈ 1 - i",
1642            ),
1643            (float!(-1.0), float!(0.99999), "-1 + 0.99999i ≈ -1 + i"),
1644            (float!(1.0), float!(-0.99999), "1 - 0.99999i ≈ 1 - i"),
1645            (float!(-0.99999), float!(1.0), "-0.99999 + i ≈ -1 + i"),
1646            (float!(0.99999), float!(-1.0), "0.99999 - i ≈ 1 - i"),
1647            (
1648                float!(0.000000001),
1649                float!(0.000000001),
1650                "10^-9 + 10^-9 i ≈ 0",
1651            ),
1652            (float!(1.0), float!(0.000000001), "1 + 10^-9 i ≈ 1"),
1653            (float!(0.000000001), float!(1.0), "10^-9 + i ≈ i"),
1654            (float!(-1.0), float!(0.000000001), "-1 + 10^-9 i ≈ -1"),
1655            (float!(0.000000001), float!(-1.0), "10^-9 - i ≈ -i"),
1656            (float!(10e-17), float!(1.0), "i"),
1657            (float!(1.0), float!(10e-17), "1"),
1658            (float!(10e-16), float!(0.0), "0"),
1659            (float!(3.00000000004), float!(0.0), "3"),
1660        ];
1661        for (real, imaginary, output) in in_out {
1662            let result = KalkValue::Number(real, imaginary, None)
1663                .to_string_pretty(ScientificNotationFormat::Normal);
1664            assert_eq!(output, result);
1665        }
1666    }
1667
1668    #[test]
1669    fn test_eng_mode() {
1670        let in_out = vec![
1671            (1.23, 0, "1.23×10^0"),
1672            (1.23, 1, "12.3×10^0"),
1673            (1.23, 2, "123×10^0"),
1674            (1.23, 3, "1.23×10^3"),
1675            (1.23, 4, "12.3×10^3"),
1676            (1.23, 5, "123×10^3"),
1677            (1.23, 6, "1.23×10^6"),
1678        ];
1679        for (value, exponent, output) in in_out {
1680            let sci = ScientificNotation {
1681                value,
1682                exponent: exponent + 1,
1683                imaginary: false,
1684            };
1685
1686            assert_eq!(
1687                sci.to_string_format(ScientificNotationFormat::Engineering),
1688                output
1689            );
1690        }
1691    }
1692}