arkley_numerics/
standardform.rs

1use std::ops::{Add,Sub,Mul,Div,AddAssign,SubAssign,MulAssign,DivAssign};
2
3use std::cmp::max;
4use std::num::ParseFloatError;
5
6use arkley_traits::Power;
7
8use crate::ParsingStandardFormError;
9
10/// Represents a number in standard form.
11///
12/// The `Standardform` struct holds the significand (mantissa) of the number 
13/// and an exponent that determines the power of 10 by which the significand should be multiplied.
14#[derive(Debug,PartialEq)]
15pub struct StandardForm  {
16    mantissa : f64,
17    exponent : i8
18}
19
20impl StandardForm {
21    /// Creates a new instance of StandardForm with the given mantissa and exponent
22    pub fn new(mantissa : f64,exponent : i8) -> Self {
23        let mut instance = Self { mantissa , exponent};
24        instance.adjust();
25        instance
26    }
27
28
29    fn in_range(&self) -> bool {
30        (self.mantissa >= 1.0 && self.mantissa <= 10.0) || (self.mantissa >= -10.0 && self.mantissa <= -1.0)
31    }
32
33    fn adjust(&mut self) {
34        if self.in_range() || self.mantissa == 0.0 {
35            return;
36        }
37
38        // means its things like 0.2323 not -700
39        match self.mantissa > -1.0 && self.mantissa < 1.0 {
40            true => while !self.in_range() {
41                self.mantissa *= 10.0;
42                self.exponent -= 1; 
43            },
44            false => while !self.in_range() {
45                self.mantissa /= 10.0;
46                self.exponent += 1; 
47            }
48        }
49    }
50
51    /// Returns a reference to the StandardForm representing the significand (mantissa) of the number.
52    pub const fn mantissa(&self) -> &f64 {
53        &self.mantissa
54    }
55
56    /// Returns the exponent that determines the power of 10 by which the significand should be multiplied.
57    pub const fn exponent(&self) -> &i8 {
58        &self.exponent
59    }
60
61    /// Returns the string representation of the number in scientific notation.
62    pub fn to_scientific_notation(&self) -> String {
63        format!("{}e{}", self.mantissa, self.exponent)
64    }
65        
66    /// Returns the string representation of the number in engineering notation.
67    pub fn to_engineering_notation(&self) -> String {
68        format!("{}*10^{}", self.mantissa, self.exponent)
69    }
70
71    /// Converts the `StandardForm` into a decimal floating-point number in base 10.
72    /// If successful, it returns the decimal value as an `f64`.
73    /// If parsing fails, it returns a `ParseFloatError`.
74    pub fn as_decimal(&self) -> Result<f64, ParseFloatError>{
75        self.to_engineering_notation().parse()
76    }
77
78}
79
80impl Default for StandardForm {
81    fn default() -> Self {
82        Self { mantissa : 1.0, exponent : 0 }
83    }
84}
85
86impl std::fmt::Display for StandardForm {
87    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88        if self.exponent > 4 {
89            return write!(f,"{}",self.to_scientific_notation());
90        };
91
92        write!(f,"{}",self.mantissa * 10_i32.pow(self.exponent as u32) as f64)
93    }
94}
95
96impl PartialOrd for StandardForm {
97    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
98        match self.exponent == other.exponent {
99            true => self.mantissa.partial_cmp(&other.mantissa),
100            false => self.exponent.partial_cmp(&other.exponent)
101        }
102    }
103}
104
105impl TryFrom<&str> for StandardForm {
106    type Error = ParsingStandardFormError;
107
108    fn try_from(value: &str) -> Result<Self, Self::Error> {
109        if let Ok(number) = value.parse::<f64>() {
110            return Ok(number.into());
111        }
112
113        if let Some(index) = value.find('e') {
114            let m_str : f64 = value[0..index].parse().map_err(|error| ParsingStandardFormError::Mantissa(error) )?;
115            let e_str : i8 = value[index + 1..].parse().map_err(|error| ParsingStandardFormError::Exponent(error) )?;
116            return Ok(StandardForm::new(m_str,e_str));
117        }
118        
119        if let Some(index) = value.find('^') {
120            let m_str : f64 = value[0..index - 2].parse().map_err(|error| ParsingStandardFormError::Mantissa(error) )?;
121            let e_str : i8 = value[index + 1..].parse().map_err(|error| ParsingStandardFormError::Exponent(error) )?;
122            return Ok(StandardForm::new(m_str,e_str));
123        }
124
125        Err(ParsingStandardFormError::InvalidFormat)
126    }
127}
128
129impl Add for StandardForm {
130    type Output = Self;
131    fn add(self, other: Self) -> Self {
132        let max_power = max(self.exponent, other.exponent);
133        let num_sum = self.mantissa * 10.0_f64.to_the_power_of((self.exponent - max_power) as f64) + other.mantissa * 10.0_f64.to_the_power_of((other.exponent - max_power) as f64);
134        StandardForm::new(num_sum, max_power)
135    }
136}
137
138impl AddAssign for StandardForm {
139    fn add_assign(&mut self, other: Self) {
140        let max_power = max(self.exponent, other.exponent);
141        let num_sum = self.mantissa * 10.0_f64.to_the_power_of((self.exponent - max_power) as f64) + other.mantissa * 10.0_f64.to_the_power_of((other.exponent - max_power) as f64);
142
143        self.mantissa = num_sum;
144        self.exponent = max_power;
145
146        self.adjust();
147    }
148}
149
150impl Sub for StandardForm {
151    type Output = Self;
152    fn sub(self, other: Self) -> Self {
153        let min = self.exponent.min(other.exponent);
154
155        let x = self.mantissa * 10_i32.pow((self.exponent - min) as u32) as f64;
156        let y = other.mantissa * 10_i32.pow((other.exponent - min) as u32) as f64;
157
158        let result = x - y;
159        let rounded = (result * 1.0e6).round() / 1.0e6;
160
161        StandardForm::new(rounded,min)
162    }
163}
164
165impl SubAssign for StandardForm {
166    fn sub_assign(&mut self, other: Self) {
167        let min = self.exponent.min(other.exponent);
168
169        let x = self.mantissa * 10_i32.pow((self.exponent - min) as u32) as f64;
170        let y = other.mantissa * 10_i32.pow((other.exponent - min) as u32) as f64;
171
172        let result = x - y;
173        let rounded = (result * 1.0e6).round() / 1.0e6;
174
175        self.mantissa = rounded;
176        self.exponent = min;
177        self.adjust(); 
178    }
179}
180
181impl Mul for StandardForm {
182    type Output = Self;
183    fn mul(self, other: Self) -> Self {
184        let exponent = self.exponent + other.exponent;
185        let mantissa = self.mantissa * other.mantissa;
186        let rounded = (mantissa * 1.0e6).round() / 1.0e6;
187        StandardForm::new(rounded,exponent)
188    }
189}
190
191impl MulAssign for StandardForm {
192    fn mul_assign(&mut self, other: Self) {
193        let exponent = self.exponent + other.exponent;
194        let mantissa = self.mantissa * other.mantissa;
195        let rounded = (mantissa * 1.0e6).round() / 1.0e6;
196
197        self.mantissa = rounded;
198        self.exponent = exponent;
199
200        self.adjust();
201    }
202}
203
204impl Div for StandardForm {
205    type Output = Self;
206    fn div(self, other: Self) -> Self {
207        StandardForm::new(self.mantissa / other.mantissa,self.exponent - other.exponent)
208    }
209}
210
211impl DivAssign for StandardForm {
212    fn div_assign(&mut self, other: Self) {
213        self.mantissa /= other.mantissa;
214        self.exponent /= other.exponent;
215        self.adjust();
216    }
217}
218
219macro_rules! primitives {
220    (form => $($t:ty),*) => {
221        $(
222            impl From<$t> for StandardForm {
223                fn from(value: $t) -> Self {
224                    StandardForm::new(value as f64,0)
225                }
226            }
227        )*
228    };
229
230    (eq => $($t:ty),*) => {
231        $(
232            impl PartialEq<$t> for StandardForm {
233                fn eq(&self,other: &$t) -> bool {
234                    let rhs : Self = (*other).into();
235                    *self == rhs
236                }
237            }
238        )*
239    };
240    (ord => $($t:ty),*) => {
241        $(
242            impl PartialOrd<$t> for StandardForm {
243                fn partial_cmp(&self, other: &$t) -> Option<std::cmp::Ordering> {
244                    let rhs : Self = (*other).into();
245                    self.partial_cmp(&rhs)
246                }
247            }
248        )*
249    };
250
251
252    (add => $($t : ty),*) => {
253        $(
254            impl Add<$t> for StandardForm {
255                type Output = Self;
256                fn add(self, other: $t) -> Self {
257                    let rhs : Self = other.into();
258                    self + rhs
259                }
260            }
261            
262            impl AddAssign<$t> for StandardForm {
263                fn add_assign(&mut self, other: $t) {
264                    let rhs : Self = other.into();
265                    *self += rhs;
266                }
267            }
268        )*
269    };
270
271    (sub => $($t : ty),*) => {
272        $(
273            impl Sub<$t> for StandardForm {
274                type Output = Self;
275                fn sub(self, other: $t) -> Self {
276                    let rhs : Self = other.into();
277                    self - rhs
278                }
279            }
280            
281            impl SubAssign<$t> for StandardForm {
282                fn sub_assign(&mut self, other: $t) {
283                    let rhs : Self = other.into();
284                    *self -= rhs;
285                }
286            }
287        )*
288    };
289    (mul => $($t : ty),*) => {
290        $(
291            impl Mul<$t> for StandardForm {
292                type Output = Self;
293                fn mul(self, other: $t) -> Self {
294                    let rhs : Self = other.into();
295                    self * rhs
296                }
297            }
298            
299            impl MulAssign<$t> for StandardForm {
300                fn mul_assign(&mut self, other: $t) {
301                    let rhs : Self = other.into();
302                    *self *= rhs;
303                }
304            }
305        )*
306    };
307    (div => $($t : ty),*) => {
308        $(
309            impl Div<$t> for StandardForm {
310                type Output = Self;
311                fn div(self, other: $t) -> Self {
312                    let rhs : Self = other.into();
313                    self / rhs
314                }
315            }
316            
317            impl DivAssign<$t> for StandardForm {
318                fn div_assign(&mut self, other: $t) {
319                    let rhs : Self = other.into();
320                    *self /= rhs;
321                }
322            }
323        )*
324    };
325    (operations => $($t:ty),*) => {
326        $(
327            primitives!(add => $t);
328            primitives!(sub => $t);
329            primitives!(mul => $t);
330            primitives!(div => $t);
331        )*
332    }
333}
334
335primitives!(operations => i8, i16, i32, i64, u8, u16, u32, u64,f32,f64);
336primitives!(form => u8,u16,u32,u64,i8,i16,i32,i64,f32,f64);
337primitives!(eq => u8,u16,u32,u64,i8,i16,i32,i64,f32,f64);
338primitives!(ord => u8,u16,u32,u64,i8,i16,i32,i64,f32,f64);
339
340#[cfg(test)]
341mod tests {
342    use super::*;
343    use std::cmp::Ordering;
344
345    #[test]
346    fn assignment_issue() {
347        let sf1 = StandardForm::new(1.0,5);
348        assert_eq!(*sf1.mantissa(),1.0);
349        assert_eq!(*sf1.exponent(),5);
350    }
351
352    #[test]
353    fn from_u8_standardform(){
354        let n = 2u8;
355        let r : StandardForm = n.into();
356
357        assert_eq!(r,StandardForm { mantissa : 2.0,exponent : 0 });
358    }
359
360    #[test]
361    fn test_normalize_with_valid_range() {
362        let mut sf = StandardForm::new(2.5, 3);
363        sf.adjust();
364        assert_eq!(sf.mantissa, 2.5);
365        assert_eq!(sf.exponent, 3);
366    }
367
368    #[test]
369    fn test_normalize_with_invalid_range() {
370        let mut sf = StandardForm::new(20.0, 3);
371        sf.adjust();
372        assert_eq!(sf.mantissa, 2.0);
373        assert_eq!(sf.exponent, 4);
374    }
375
376    #[test]
377    fn test_normalize_with_small_mantissa() {
378        let mut sf = StandardForm::new(-0.25, 2);
379        sf.adjust();
380        assert_eq!(sf.mantissa, -2.5);
381        assert_eq!(sf.exponent, 1);
382    }
383
384    #[test]
385    fn test_normalize_with_large_negative_mantissa() {
386        let mut sf = StandardForm::new(-750.0, 4);
387        sf.adjust();
388        assert_eq!(sf.mantissa, -7.5);
389        assert_eq!(sf.exponent, 6);
390    }
391
392    #[test]
393    fn addition() {
394        // Test addition between StandardForm instances
395        let a = StandardForm::new(1.2, 3);
396        let b = StandardForm::new(3.4, 2);
397        let result = a + b;
398        assert_eq!(result, StandardForm::new(1.54,3) );
399    }
400
401    #[test]
402    fn addition_u8() {
403        // Test addition with u8
404        let a = StandardForm::new(1.0, 1);
405        let b = 2u8;
406        let result = a + b;
407        assert_eq!(result, StandardForm::new(1.2,1));
408    }
409
410    #[test]
411    fn test_subtraction() {
412        // Test subtraction between StandardForm instances
413        let a = StandardForm::new(4.6, 2);
414        let b = StandardForm::new(3.4, 2);
415        let result = a - b;
416        assert_eq!(result, StandardForm::new(1.2,2));
417    }
418
419    #[test]
420    fn subtraction_u8() {
421        //210
422        let a = StandardForm::new(21.0, 1);
423        println!("{a}");
424        //2
425        let b = 2u8;
426        let result = a - b;
427        assert_eq!(result.mantissa, 2.18);
428        assert_eq!(result.exponent, 2);
429    }
430
431    #[test]
432    fn multiplication() {
433        // Test multiplication between StandardForm instances
434        let a = StandardForm::new(1.2, 3);
435        let b = StandardForm::new(3.0, 2);
436        let result = a * b;
437        assert_eq!(result.mantissa, 3.6);
438        assert_eq!(result.exponent, 5);
439    }
440
441    #[test]
442    fn multiplication_u8() {
443        // Test multiplication with u8
444        let a = StandardForm::new(1.0, 1);        
445        let b = 2u8;
446        let result = a * b;
447        assert_eq!(result.mantissa, 2.0);
448        assert_eq!(result.exponent, 1);
449    }
450
451    #[test]
452    fn division() {
453        // Test division between StandardForm instances
454        let a = StandardForm::new(4.0, 2);
455        let b = StandardForm::new(2.0, 1);
456        let result = a / b;
457        assert_eq!(result.mantissa, 2.0);
458        assert_eq!(result.exponent, 1);
459    }
460
461    #[test]
462    fn division_u8() {
463        // Test division with u8
464        let a = StandardForm::new(2.0, 1);
465        let b = 2u8;
466        let result = a / b;
467        assert_eq!(result.mantissa, 1.0);
468        assert_eq!(result.exponent, 1);
469    }
470
471
472    #[test]
473    fn add_assign() {
474        let mut a = StandardForm::new(1.0, 1);
475        let b = StandardForm::new(2.0, 1);
476        a += b;
477        assert_eq!(a.mantissa, 3.0);
478        assert_eq!(a.exponent, 1);
479    }
480
481    #[test]
482    fn add_assign_u8() {
483        // Test AddAssign with u8
484        let mut a = StandardForm::new(1.0, 1);
485
486        let b = 2u8;
487
488        a += b;
489        assert_eq!(a.mantissa, 1.2);
490        assert_eq!(a.exponent, 1);
491    }
492
493    #[test]
494    fn test_partial_cmp_equal() {
495        let sf1 = StandardForm::new(1.23, 3);
496        let sf2 = StandardForm::new(1.23, 3);
497
498        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Equal));
499    }
500
501    #[test]
502    fn test_partial_cmp_greater() {
503
504        //300
505        let sf1 = StandardForm::new(3.0, 2);
506        // 250
507        let sf2 = StandardForm::new(2.5, 2);
508
509        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Greater));
510    }
511
512    #[test]
513    fn test_partial_cmp_less() {
514        let sf1 = StandardForm::new(2.5, 2);
515        let sf2 = StandardForm::new(3.0, 2);
516
517        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Less));
518    }
519
520    #[test]
521    fn test_partial_cmp_different_exponents() {
522        let sf1 = StandardForm::new(1.5, 2);
523        let sf2 = StandardForm::new(1.5, 3);
524
525        // When exponents are different, the comparison is based on the magnitude
526        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Less));
527    }
528
529    #[test]
530    fn test_partial_cmp_zero() {
531        let sf1 = StandardForm::new(0.0, 0);
532        let sf2 = StandardForm::new(0.0, 0);
533
534        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Equal));
535    }
536
537    #[test]
538    fn test_partial_cmp_mixed_sign() {
539        let sf1 = StandardForm::new(-1.0, 2);
540        let sf2 = StandardForm::new(1.0, 2);
541
542        // Negative numbers are considered less than positive numbers with the same magnitude
543        assert_eq!(sf1.partial_cmp(&sf2), Some(Ordering::Less));
544    }
545}