num_notation/
number.rs

1use std::ops::{Add,Sub,Mul,Div,Rem,AddAssign,SubAssign,MulAssign,DivAssign,RemAssign,Neg};
2use std::cmp::Ordering;
3
4use standardform::StandardForm;
5use fraction::GenericFraction;
6
7use crate::ParsingNumberError;
8
9/// Represents a numeric value that can be either a decimal, a number in standard form,
10/// or a fraction with a generic numerator and denominator.
11///
12/// This enum is designed for flexible numeric handling in Rust applications.
13#[derive(Debug,Clone,PartialEq,PartialOrd)]
14pub enum Number {
15    /// Represents a floating-point decimal number.
16    Decimal(f64),
17
18    /// Represents a number in the StandardForm notation.
19    StandardForm(StandardForm),
20
21    /// Represents a fraction with a generic numerator and denominator
22    Fraction(GenericFraction<u32>)
23}
24
25impl std::fmt::Display for Number {
26    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27        match self {
28            Number::Decimal(d) => write!(f,"{d}"),
29            Number::StandardForm(sf) => write!(f,"{sf}"),
30            Number::Fraction(fr) => write!(f,"{fr}"),
31        }
32    }
33}
34
35impl From<StandardForm> for Number {
36    fn from(value: StandardForm) -> Self {
37        Number::StandardForm(value)
38    }
39}
40
41impl From<GenericFraction<u32>> for Number {
42    fn from(value: GenericFraction<u32>) -> Self {
43        Number::Fraction(value)
44    }
45}
46
47impl From<f64> for Number {
48    fn from(value: f64) -> Self {
49        Number::Decimal(value)
50    }
51}
52
53impl From<Number> for f64 {
54    fn from(value: Number) -> Self {
55        match value {
56            Number::Decimal(d) => d,
57            Number::StandardForm(sf) => sf.into(),
58            Number::Fraction(fr) => match fr {
59                GenericFraction::Rational(sign,ratio) => match sign.is_positive() {
60                    true => ratio.to_integer() as f64 ,
61                    false => -(ratio.to_integer() as f64)
62                },
63                GenericFraction::Infinity(sign) => match sign.is_positive() {
64                    true => f64::INFINITY,
65                    false => -f64::INFINITY
66                },
67                GenericFraction::NaN => f64::NAN,
68            },
69        }
70    }
71}
72impl TryFrom<&str> for Number {
73    type Error = ParsingNumberError;
74    fn try_from(value : &str) -> Result<Self, Self::Error> {
75
76        let try_into_f64 = value.parse::<f64>();
77
78        if let Ok(double) = try_into_f64 {
79            return Ok(Number::Decimal(double));
80        } 
81
82        let try_into_fraction = value.parse::<GenericFraction<u32>>();
83
84        if let Ok(fraction) = try_into_fraction {
85            return Ok(Number::Fraction(fraction));
86        } 
87    
88        let try_into_sf = StandardForm::try_from(value);
89
90        if let Ok(sf) = try_into_sf {
91            return Ok(Number::StandardForm(sf));
92        } 
93
94        Err(ParsingNumberError::new(
95            try_into_fraction.unwrap_err(),
96            try_into_f64.unwrap_err(),
97            try_into_sf.unwrap_err()
98        ))
99    }
100}
101
102impl Neg for Number {
103    type Output = Self;
104    fn neg(self) -> Self::Output {
105        match self {
106            Number::Decimal(d) => Number::Decimal(-d),
107            Number::StandardForm(sf) => Number::StandardForm(-sf),
108            Number::Fraction(fr) => Number::Fraction(-fr),
109        }
110    }
111}
112
113impl Eq for Number {}
114
115impl Ord for Number {
116    fn cmp(&self, other: &Self) -> Ordering {
117        self.partial_cmp(other).unwrap()
118    }
119}
120
121
122fn from_fraction_rational_to_sf(sign : fraction::Sign,ratio : fraction::Ratio<u32>) -> StandardForm {
123    let (mantissa,exponent) = (match sign{
124        fraction::Sign::Plus => *ratio.numer() as f64,
125        fraction::Sign::Minus => -(*ratio.numer() as f64)
126    }, -(ratio.denom().trailing_zeros() as i8));
127    StandardForm::new(mantissa,exponent)
128}
129
130
131impl Add for Number {
132    type Output = Number;
133
134    fn add(self,other : Number) -> Self::Output {
135        use crate::Number::*;
136        match (self,other) {
137            (Decimal(d1),Decimal(d2)) => (d1 + d2).into(),
138            (Decimal(d),StandardForm(sf)) => (sf + d).into(),
139            (Decimal(d),Fraction(fr)) => (fr + d).into(),
140
141            (StandardForm(sf1),StandardForm(sf2)) => (sf1 + sf2).into(),
142            (StandardForm(sf),Decimal(d)) => (sf + d).into(),
143            (StandardForm(sf),Fraction(fr)) => match fr {
144                GenericFraction::Rational(sign,ratio) => (sf + from_fraction_rational_to_sf(sign,ratio)).into(),
145                _ => fr.into()
146            },
147
148            (Fraction(fr1),Fraction(fr2)) => (fr1 + fr2).into(),
149            (Fraction(fr),Decimal(d)) => (fr + d).into(),
150            (Fraction(fr),StandardForm(sf)) => match fr {
151                GenericFraction::Rational(sign,ratio) => (from_fraction_rational_to_sf(sign,ratio) + sf).into(),
152                _ => fr.into()
153            },
154        }
155    }
156}
157
158impl Sub for Number {
159    type Output = Number;
160
161    fn sub(self,other : Number) -> Self::Output {
162        use crate::Number::*;
163        match (self,other) {
164            (Decimal(d1),Decimal(d2)) => (d1 - d2).into(),
165            (Decimal(d),StandardForm(sf)) => (sf - d).into(),
166            (Decimal(d),Fraction(fr)) => (fr - d).into(),
167
168            (StandardForm(sf1),StandardForm(sf2)) => (sf1 - sf2).into(),
169            (StandardForm(sf),Decimal(d)) => (sf - d).into(),
170            (StandardForm(sf),Fraction(fr)) => match fr {
171                GenericFraction::Rational(sign,ratio) => (sf - from_fraction_rational_to_sf(sign,ratio)).into(),
172                _ => fr.into()
173            },
174
175            (Fraction(fr1),Fraction(fr2)) => (fr1 - fr2).into(),
176            (Fraction(fr),Decimal(d)) => (fr - d).into(),
177            (Fraction(fr),StandardForm(sf)) => match fr {
178                GenericFraction::Rational(sign,ratio) => (from_fraction_rational_to_sf(sign,ratio) - sf).into(),
179                _ => fr.into()
180            },
181        }
182    }
183}
184
185impl Mul for Number {
186    type Output = Number;
187
188    fn mul(self,other : Number) -> Self::Output {
189        use crate::Number::*;
190        match (self,other) {
191            (Decimal(d1),Decimal(d2)) => (d1 * d2).into(),
192            (Decimal(d),StandardForm(sf)) => (sf * d).into(),
193            (Decimal(d),Fraction(fr)) => (fr * d).into(),
194
195            (StandardForm(sf1),StandardForm(sf2)) => (sf1 * sf2).into(),
196            (StandardForm(sf),Decimal(d)) => (sf * d).into(),
197            (StandardForm(sf),Fraction(fr)) => match fr {
198                GenericFraction::Rational(sign,ratio) => (sf * from_fraction_rational_to_sf(sign,ratio)).into(),
199                _ => fr.into()
200            },
201
202            (Fraction(fr1),Fraction(fr2)) => (fr1 * fr2).into(),
203            (Fraction(fr),Decimal(d)) => (fr * d).into(),
204            (Fraction(fr),StandardForm(sf)) => match fr {
205                GenericFraction::Rational(sign,ratio) => (from_fraction_rational_to_sf(sign,ratio) * sf).into(),
206                _ => fr.into()
207            },
208        }
209    }
210}
211
212impl Div for Number {
213    type Output = Number;
214
215    fn div(self,other : Number) -> Self::Output {
216        use crate::Number::*;
217        match (self,other) {
218            (Decimal(d1),Decimal(d2)) => (d1 / d2).into(),
219            (Decimal(d),StandardForm(sf)) => (sf / d).into(),
220            (Decimal(d),Fraction(fr)) => (fr / d).into(),
221
222            (StandardForm(sf1),StandardForm(sf2)) => (sf1 / sf2).into(),
223            (StandardForm(sf),Decimal(d)) => (sf / d).into(),
224            (StandardForm(sf),Fraction(fr)) => match fr {
225                GenericFraction::Rational(sign,ratio) => (sf / from_fraction_rational_to_sf(sign,ratio)).into(),
226                _ => fr.into()
227            },
228
229            (Fraction(fr1),Fraction(fr2)) => (fr1 / fr2).into(),
230            (Fraction(fr),Decimal(d)) => (fr / d).into(),
231            (Fraction(fr),StandardForm(sf)) => match fr {
232                GenericFraction::Rational(sign,ratio) => (from_fraction_rational_to_sf(sign,ratio) / sf).into(),
233                _ => fr.into()
234            },
235        }
236    }
237}
238
239impl Rem for Number {
240    type Output = Number;
241
242    fn rem(self,other : Number) -> Self::Output {
243        use crate::Number::*;
244        match (self,other) {
245            (Decimal(d1),Decimal(d2)) => (d1 % d2).into(),
246            (Decimal(d),StandardForm(sf)) => (sf % d).into(),
247            (Decimal(d),Fraction(fr)) => (fr % d).into(),
248
249            (StandardForm(sf1),StandardForm(sf2)) => (sf1 % sf2).into(),
250            (StandardForm(sf),Decimal(d)) => (sf % d).into(),
251            (StandardForm(sf),Fraction(fr)) => match fr {
252                GenericFraction::Rational(sign,ratio) => (sf % from_fraction_rational_to_sf(sign,ratio)).into(),
253                _ => fr.into()
254            },
255
256            (Fraction(fr1),Fraction(fr2)) => (fr1 % fr2).into(),
257            (Fraction(fr),Decimal(d)) => (fr % d).into(),
258            (Fraction(fr),StandardForm(sf)) => match fr {
259                GenericFraction::Rational(sign,ratio) => (from_fraction_rational_to_sf(sign,ratio) % sf).into(),
260                _ => fr.into()
261            },
262        }
263    }
264}
265
266impl AddAssign for Number {
267    fn add_assign(&mut self, other: Number) {
268        *self = self.clone() + other;
269    }
270}
271
272impl SubAssign for Number {
273    fn sub_assign(&mut self, other: Number) {
274        *self = self.clone() - other;
275    }
276}
277
278impl MulAssign for Number {
279    fn mul_assign(&mut self, other: Number) {
280        *self = self.clone() * other;
281    }
282}
283
284impl DivAssign for Number {
285    fn div_assign(&mut self, other: Number) {
286        *self = self.clone() / other;
287    }
288}
289
290impl RemAssign for Number {
291    fn rem_assign(&mut self, other: Number) {
292        *self = self.clone() % other;
293    }
294}
295
296
297macro_rules! primitives {
298    (eq => $($t : ty),*) => {
299        $(
300            impl PartialEq<$t> for Number {
301                fn eq(&self, other: &$t) -> bool {
302                    match self {
303                        Number::Decimal(d) => d == &(*other as f64),
304                        Number::StandardForm(sf) => {
305                            let xy : StandardForm = (*other).into();
306                            sf == &xy
307                        },
308                        Number::Fraction(fr) => {
309                            let xy : GenericFraction<u32> = (*other).into();
310                            fr == &xy
311                        }
312                    }
313                }
314            }
315        )*
316    };
317    (ord => $($t : ty),*) => {
318        $(
319            impl PartialOrd<$t> for Number {
320                fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
321                    match self {
322                        Number::Decimal(f) => f.partial_cmp(&(*other as f64)),
323                        Number::StandardForm(sf) => {
324                            let xy : StandardForm = (*other).into();
325                            sf.partial_cmp(&xy)
326                        },
327                        Number::Fraction(fr) => {
328                            let xy : GenericFraction<u32> = (*other).into();
329                            fr.partial_cmp(&xy)
330                        }
331                    }
332                }
333            }
334        )*
335    };
336
337    (add => $($t : ty),*) => {
338        $(
339            impl Add<$t> for Number {
340                type Output = Self;
341                fn add(self, other: $t) -> Self {
342                    match self {
343                        Number::Decimal(f) => (f + other as f64).into(),
344                        Number::StandardForm(sf) =>(sf + other).into(),
345                        Number::Fraction(fr) => (fr + other).into()
346                    }
347                }
348            }
349            
350            impl AddAssign<$t> for Number {
351                fn add_assign(&mut self, other: $t) {
352                    *self += Number::Decimal(other as f64)
353                }
354            }
355        )*
356    };
357
358    (sub => $($t : ty),*) => {
359        $(
360            impl Sub<$t> for Number {
361                type Output = Self;
362                fn sub(self, other: $t) -> Self {
363                    match self {
364                        Number::Decimal(f) => Number::Decimal(f - other as f64),
365                        Number::StandardForm(sf) => Number::StandardForm(sf - other),
366                        Number::Fraction(fr) => (fr - other).into()
367
368                    }
369                }
370            }
371            
372            impl SubAssign<$t> for Number {
373                fn sub_assign(&mut self, other: $t) {
374                    *self -= Number::Decimal(other as f64)
375                }
376            }
377        )*
378    };
379    (mul => $($t : ty),*) => {
380        $(
381            impl Mul<$t> for Number {
382                type Output = Self;
383                fn mul(self, other: $t) -> Self {
384                    match self {
385                        Number::Decimal(f) => Number::Decimal(f * other as f64),
386                        Number::StandardForm(sf) => Number::StandardForm(sf * other),
387                        Number::Fraction(fr) => (fr * other).into()
388                    }
389                }
390            }
391            
392            impl MulAssign<$t> for Number {
393                fn mul_assign(&mut self, other: $t) {
394                    *self *= Number::Decimal(other as f64)
395                }
396            }
397        )*
398    };
399    (div => $($t : ty),*) => {
400        $(
401            impl Div<$t> for Number {
402                type Output = Self;
403                fn div(self, other: $t) -> Self {
404                    match self {
405                        Number::Decimal(f) => Number::Decimal(f / other as f64),
406                        Number::StandardForm(sf) => Number::StandardForm(sf / other),
407                        Number::Fraction(fr) => (fr / other).into()
408                    }
409                }
410            }
411            
412            impl DivAssign<$t> for Number {
413                fn div_assign(&mut self, other: $t) {
414                    *self /= Number::Decimal(other as f64)
415                }
416            }
417        )*
418    };
419    (rem => $($t : ty),*) => {
420        $(
421            impl Rem<$t> for Number {
422                type Output = Self;
423                fn rem(self, other: $t) -> Self {
424                    match self {
425                        Number::Decimal(f) => Number::Decimal(f % other as f64),
426                        Number::StandardForm(sf) => Number::StandardForm(sf % other),
427                        Number::Fraction(fr) => (fr % other).into()
428                    }
429                }
430            }
431            
432            impl RemAssign<$t> for Number {
433                fn rem_assign(&mut self, other: $t) {
434                    *self %= Number::Decimal(other as f64)
435                }
436            }
437        )*
438    };
439    (pow => $($t : ty),*) => {
440        $(
441            #[cfg(feature="num")]
442            impl num_traits::Pow<$t> for StandardForm {
443                type Output = f64;
444            
445                #[must_use]
446                fn pow(self, other: $t) -> Self::Output {
447                    f64::from(self).powf(other as f64)
448                }
449            }
450        )*
451    };
452    (operations => $($t:ty),*) => {
453        $(
454            primitives!(add => $t);
455            primitives!(sub => $t);
456            primitives!(mul => $t);
457            primitives!(div => $t);
458            primitives!(rem => $t);
459            primitives!(pow => $t);
460        )*
461    }
462}
463
464primitives!(eq => u8,u16,u32,u64,i8,i16,i32,i64,f32,f64);
465primitives!(ord => u8,u16,u32,u64,i8,i16,i32,i64,f32,f64);
466primitives!(operations => i8, i16, i32, i64, u8, u16, u32, u64,f32,f64);
467
468macro_rules! trig_functions {
469    ($( {
470        $(#[$attr:meta])* $fn : ident
471    })*) => {
472        impl Number {
473            $(
474                $(#[$attr])*
475                pub fn $fn <T : From<f64>>(self) -> T  {
476                    f64::from(self). $fn ().into()
477                }
478            )*
479
480        }
481    };
482}
483
484trig_functions!(
485    { /// Computes the sine of a number (in radians).
486      sin }
487    { /// Computes the cosine of a number (in radians).
488      cos }
489    { /// Computes the tangent of a number (in radians).
490     tan }
491    { /// Computes the arcsine of a number.
492      asin }
493    { /// Computes the arccosine of a number.
494      acos }
495    { /// Computes the arctangent of a number.
496      atan }
497    { /// Computes the hyperbolic sine.
498      sinh }
499    { /// Computes the hyperbolic cosine.
500     cosh }
501    { /// Computes the hyperbolic tangent.
502      tanh }
503    { /// Computes the inverse hyperbolic sine.
504      asinh }
505    { /// Computes the inverse hyperbolic cosine.
506      acosh }
507    { /// Computes the inverse hyperbolic tangent.
508      atanh }
509);
510
511
512#[cfg(test)]
513mod test {
514    use super::*;
515    #[test]
516    fn test_addition() {
517        let num1 = Number::Decimal(2.5);
518        let num2 = Number::Decimal(3.5);
519        let result = num1 + num2;
520        assert_eq!(result, Number::Decimal(6.0));
521    }
522
523    // Test subtraction
524    #[test]
525    fn test_subtraction() {
526        let num1 = Number::Decimal(5.5);
527        let num2 = Number::Decimal(3.5);
528        let result = num1 - num2;
529        assert_eq!(result, Number::Decimal(2.0));
530    }
531
532    // Test multiplication
533    #[test]
534    fn test_multiplication() {
535        let num1 = Number::Decimal(2.5);
536        let num2 = Number::Decimal(3.0);
537        let result = num1 * num2;
538        assert_eq!(result, Number::Decimal(7.5));
539    }
540
541    // Test division
542    #[test]
543    fn test_division() {
544        let num1 = Number::Decimal(10.0);
545        let num2 = Number::Decimal(2.0);
546        let result = num1 / num2;
547        assert_eq!(result, Number::Decimal(5.0));
548    }
549
550    // Test addition assignment
551    #[test]
552    fn test_addition_assignment() {
553        let mut num = Number::Decimal(3.0);
554        let num2 = Number::Decimal(2.0);
555        num += num2;
556        assert_eq!(num, Number::Decimal(5.0));
557    }
558
559    // Test subtraction assignment
560    #[test]
561    fn test_subtraction_assignment() {
562        let mut num = Number::Decimal(5.0);
563        let num2 = Number::Decimal(3.0);
564        num -= num2;
565        assert_eq!(num, Number::Decimal(2.0));
566    }
567
568    // Test multiplication assignment
569    #[test]
570    fn test_multiplication_assignment() {
571        let mut num = Number::Decimal(2.5);
572        let num2 = Number::Decimal(3.0);
573        num *= num2;
574        assert_eq!(num, Number::Decimal(7.5));
575    }
576
577    // Test division assignment
578    #[test]
579    fn test_division_assignment() {
580        let mut num = Number::Decimal(10.0);
581        let num2 = Number::Decimal(2.0);
582        num /= num2;
583        assert_eq!(num, Number::Decimal(5.0));
584    }
585
586    #[test]
587    fn test_display_decimal() {
588        let number = Number::Decimal(3.14);
589        assert_eq!(format!("{}", number), "3.14");
590        assert_eq!(number.to_string(), "3.14");
591    }
592
593    #[test]
594    fn test_try_from_valid_number() {
595        // Test a valid number conversion
596        let input = "3.14";
597        let result = Number::try_from(input);
598        assert!(result.is_ok());
599
600        // Check if the correct variant and value are returned
601        if let Ok(Number::Decimal(value)) = result {
602            assert_eq!(value, 3.14);
603        } else {
604            assert!(false, "Expected Ok(Number::Decimal(_)), but got an error.");
605        }
606    }
607
608    #[test]
609    fn test_try_from_invalid_number() {
610        // Test an invalid number conversion
611        let input = "abc"; // This is not a valid floating-point number
612        let result = Number::try_from(input);
613        assert!(result.is_err());
614
615        // Check if the correct error variant is returned
616        if let Err(_) = result {
617        } else {
618            assert!(false, "Expected Err(ParseFloatError), but got a success.");
619        }
620    }
621
622    #[test]
623    fn test_try_from_empty_string() {
624        // Test conversion from an empty string
625        let input = "";
626        let result = Number::try_from(input);
627        assert!(result.is_err());
628
629        // Check if the correct error variant is returned
630        if let Err(_) = result {
631        } else {
632            assert!(false, "Expected Err(ParseFloatError), but got a success.");
633        }
634    }
635}