1#![doc = include_str!("../README.md")]
2#![deny(
3 missing_docs,
4 missing_debug_implementations,
5 unused_mut,
6 unused_allocation,
7 unused_must_use,
8 unreachable_patterns,
9 unstable_features,
10 trivial_casts,
11 overflowing_literals,
12 clippy::cargo,
13 clippy::perf,
14 clippy::complexity,
15 clippy::style,
16 clippy::suspicious
17)]
18#![cfg_attr(
19 not(feature = "python"),
20 forbid(non_snake_case, unsafe_op_in_unsafe_fn, unsafe_code)
21)]
22#![cfg_attr(
23 feature = "python",
24 allow(non_snake_case, unsafe_op_in_unsafe_fn, unsafe_code)
25)]
26
27#[cfg(all(feature = "nom", not(feature = "_bindings")))]
28mod nom;
29
30#[cfg(all(feature = "nom", not(feature = "_bindings")))]
31pub use nom::*;
32
33#[cfg(feature = "python")]
34mod python;
35
36#[cfg(feature = "wasm")]
37mod wasm;
38
39use core::f64;
40use core::num::{ParseFloatError, ParseIntError};
41use core::str::Utf8Error;
42
43use decorum::Finite;
44use num_traits::real::Real;
45use num_traits::{One, Zero};
46
47use thiserror::Error;
48
49#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
54#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
55#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56pub struct StandardForm {
57 mantissa: Finite<f64>,
58 exponent: i8,
59}
60
61impl StandardForm {
62 pub fn new(mantissa: Finite<f64>, exponent: i8) -> Self {
75 let mut instance = Self::new_unchecked(mantissa, exponent);
76 instance.adjust();
77 instance
78 }
79
80 pub fn as_finite(self) -> Finite<f64> {
82 self.mantissa * 10f64.powi(self.exponent.into())
83 }
84
85 pub(crate) const fn new_unchecked(mantissa: Finite<f64>, exponent: i8) -> Self {
86 Self { mantissa, exponent }
87 }
88
89 fn in_range(&self) -> bool {
90 let abs = self.mantissa.abs();
94
95 #[allow(clippy::manual_range_contains)]
99 {
100 abs >= 1.0 && abs < 10.0
101 }
102 }
103
104 fn adjust(&mut self) {
105 if self.in_range() || self.mantissa == 0.0 {
106 return;
107 }
108
109 use num_traits::real::Real;
110
111 let log10_mantissa = self.mantissa.abs().log10();
112
113 let adjustment = log10_mantissa.floor();
115
116 if adjustment != 0.0 {
117 self.mantissa /= Finite::from_inner(10f64).powf(adjustment);
118 self.exponent += adjustment.into_inner() as i8;
119 }
120
121 if !self.in_range() {
123 if self.mantissa > -1.0 && self.mantissa < 1.0 {
124 self.mantissa *= 10.0;
125 self.exponent -= 1;
126 } else {
127 self.mantissa /= 10.0;
128 self.exponent += 1;
129 }
130 }
131 }
132}
133
134impl Default for StandardForm {
135 #[must_use]
136 fn default() -> Self {
137 Self::one()
138 }
139}
140
141impl core::fmt::Display for StandardForm {
142 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
143 if self.exponent > 4 {
144 return write!(f, "{}", self.to_scientific_notation());
145 };
146
147 write!(f, "{}", self.mantissa * 10_f64.powi(self.exponent as i32))
148 }
149}
150
151impl StandardForm {
152 #[must_use]
154 pub const fn mantissa(&self) -> &Finite<f64> {
155 &self.mantissa
156 }
157
158 #[must_use]
160 pub const fn exponent(&self) -> &i8 {
161 &self.exponent
162 }
163}
164
165#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
166impl StandardForm {
167 #[must_use]
169 #[cfg(feature = "std")]
170 #[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
171 pub fn to_scientific_notation(&self) -> String {
172 format!("{}e{}", self.mantissa, self.exponent)
173 }
174
175 #[must_use]
177 #[cfg(feature = "std")]
178 #[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
179 pub fn to_engineering_notation(&self) -> String {
180 format!("{}*10^{}", self.mantissa, self.exponent)
181 }
182}
183
184#[cfg(feature = "std")]
185impl TryFrom<&str> for StandardForm {
186 type Error = crate::ParsingStandardFormError;
187
188 fn try_from(value: &str) -> Result<Self, Self::Error> {
189 if let Ok(number) = value.parse::<f64>() {
190 let output: Result<Self, ConversionError> = number.try_into();
191 return output.map_err(|e| e.into());
192 }
193
194 if let Some(index) = value.find('e').or_else(|| value.find('E')) {
195 let m_str: Finite<f64> = value[0..index].parse()?;
196 let e_str: i8 = value[index + 1..].parse()?;
197 return Ok(StandardForm::new(m_str, e_str));
198 }
199
200 if let Some(index) = value.find('^') {
201 let m_str: Finite<f64> = value[0..index - 3].parse()?;
202 let e_str: i8 = value[index + 1..].parse()?;
203 return Ok(StandardForm::new(m_str, e_str));
204 }
205
206 Err(crate::ParsingStandardFormError::InvalidFormat)
207 }
208}
209
210#[derive(Error, Debug, Clone, PartialEq, Eq)]
212pub enum ParsingStandardFormError {
213 #[error("Failed parsing mantissa due to {0}")]
215 Mantissa(#[from] ParseFloatError),
216 #[error("Failed parsing exponent due to {0}")]
218 Exponent(#[from] ParseIntError),
219 #[error("Invalid format")]
221 InvalidFormat,
222 #[error("Given bytes are not formatted in UTF-8")]
224 InvalidBytes(#[from] Utf8Error),
225
226 #[error("Invalid radix : Only radix 10 is supported")]
228 InvalidRadix,
229
230 #[error("{0}")]
232 ConstraintsVoliated(#[from] ConversionError),
233}
234
235impl core::ops::Neg for StandardForm {
236 type Output = Self;
237 #[must_use]
238 fn neg(self) -> Self::Output {
239 Self::new_unchecked(-self.mantissa, self.exponent)
240 }
241}
242impl core::ops::Add for StandardForm {
243 type Output = Self;
244 fn add(self, other: Self) -> Self {
245 let max_power = self.exponent.max(other.exponent);
246 let num_sum = self.mantissa * 10.0_f64.powf((self.exponent - max_power) as f64)
247 + other.mantissa * 10.0_f64.powf((other.exponent - max_power) as f64);
248 StandardForm::new(num_sum, max_power)
249 }
250}
251
252impl core::ops::AddAssign for StandardForm {
253 fn add_assign(&mut self, other: Self) {
254 let max_power = self.exponent.max(other.exponent);
255 let num_sum = self.mantissa * 10.0_f64.powf((self.exponent - max_power) as f64)
256 + other.mantissa * 10.0_f64.powf((other.exponent - max_power) as f64);
257
258 self.mantissa = num_sum;
259 self.exponent = max_power;
260
261 self.adjust();
262 }
263}
264
265pub(crate) fn round(result: Finite<f64>) -> Finite<f64> {
266 const TOLERANCE: f64 = 1.0e6;
267 (result * TOLERANCE).round() / TOLERANCE
268}
269
270impl core::ops::Sub for StandardForm {
271 type Output = Self;
272 #[must_use]
273 fn sub(self, other: Self) -> Self {
274 let min = self.exponent.min(other.exponent);
275
276 let x = self.mantissa * 10_f64.powi((self.exponent - min) as i32);
277 let y = other.mantissa * 10_f64.powi((other.exponent - min) as i32);
278
279 let result = x - y;
280
281 StandardForm::new(round(result), min)
282 }
283}
284
285impl core::ops::SubAssign for StandardForm {
286 fn sub_assign(&mut self, other: Self) {
287 let min = self.exponent.min(other.exponent);
288
289 let x = self.mantissa * 10_i32.pow((self.exponent - min) as u32) as f64;
290 let y = other.mantissa * 10_i32.pow((other.exponent - min) as u32) as f64;
291
292 self.mantissa = x - y;
293 self.exponent = min;
294 self.adjust();
295 }
296}
297
298impl core::ops::Mul for StandardForm {
299 type Output = Self;
300 #[must_use]
301 fn mul(self, other: Self) -> Self {
302 let exponent = self.exponent + other.exponent;
303 let mantissa = self.mantissa * other.mantissa;
304 StandardForm::new(round(mantissa), exponent)
305 }
306}
307
308impl core::ops::MulAssign for StandardForm {
309 fn mul_assign(&mut self, other: Self) {
310 let exponent = self.exponent + other.exponent;
311 let mantissa = self.mantissa * other.mantissa;
312
313 self.mantissa = round(mantissa);
314 self.exponent = exponent;
315
316 self.adjust();
317 }
318}
319
320impl core::ops::Div for StandardForm {
321 type Output = Self;
322 #[must_use]
323 fn div(self, other: Self) -> Self {
324 StandardForm::new(
325 self.mantissa / other.mantissa,
326 self.exponent - other.exponent,
327 )
328 }
329}
330
331impl core::ops::DivAssign for StandardForm {
332 fn div_assign(&mut self, other: Self) {
333 self.mantissa /= other.mantissa;
334 self.exponent /= other.exponent;
335 self.adjust();
336 }
337}
338
339impl core::ops::Rem for StandardForm {
340 type Output = Self;
341
342 fn rem(self, rhs: Self) -> Self::Output {
343 StandardForm::from(self.as_finite() % rhs.as_finite())
344 }
345}
346
347impl core::ops::RemAssign for StandardForm {
348 fn rem_assign(&mut self, other: StandardForm) {
349 *self = self.clone() % other;
350 }
351}
352
353macro_rules! primitives {
354 (ints => $($t:ty),*) => {
355 $(
356 impl From<$t> for StandardForm {
357 #[must_use]
358 fn from(value: $t) -> Self {
359 StandardForm::new((value as f64).into(),0)
360 }
361 }
362
363 primitives!(ops => $t);
364 )*
365 };
366
367 (ops => $($t:ty),*) => {
368 $(
369 impl PartialEq<$t> for StandardForm {
370 fn eq(&self,other: &$t) -> bool {
371 let rhs : Self = (*other).into();
372 *self == rhs
373 }
374 }
375
376 impl PartialOrd<$t> for StandardForm {
377 fn partial_cmp(&self, other: &$t) -> Option<std::cmp::Ordering> {
378 let rhs : Self = (*other).into();
379 self.partial_cmp(&rhs)
380 }
381 }
382
383 impl core::ops::Add<$t> for StandardForm {
384 type Output = Self;
385 #[must_use]
386 fn add(self, other: $t) -> Self {
387 let rhs : Self = other.into();
388 self + rhs
389 }
390 }
391
392 impl core::ops::AddAssign<$t> for StandardForm {
393 fn add_assign(&mut self, other: $t) {
394 let rhs : Self = other.into();
395 *self += rhs;
396 }
397 }
398
399 impl core::ops::Sub<$t> for StandardForm {
400 type Output = Self;
401 #[must_use]
402 fn sub(self, other: $t) -> Self {
403 let rhs : Self = other.into();
404 self - rhs
405 }
406 }
407
408 impl core::ops::SubAssign<$t> for StandardForm {
409 fn sub_assign(&mut self, other: $t) {
410 let rhs : Self = other.into();
411 *self -= rhs;
412 }
413 }
414
415 impl core::ops::Mul<$t> for StandardForm {
416 type Output = Self;
417 #[must_use]
418 fn mul(self, other: $t) -> Self {
419 let rhs : Self = other.into();
420 self * rhs
421 }
422 }
423
424 impl core::ops::MulAssign<$t> for StandardForm {
425 fn mul_assign(&mut self, other: $t) {
426 let rhs : Self = other.into();
427 *self *= rhs;
428 }
429 }
430
431 impl core::ops:: Div<$t> for StandardForm {
432 type Output = Self;
433 #[must_use]
434 fn div(self, other: $t) -> Self {
435 let rhs : Self = other.into();
436 self / rhs
437 }
438 }
439
440 impl core::ops::DivAssign<$t> for StandardForm {
441 fn div_assign(&mut self, other: $t) {
442 let rhs : Self = other.into();
443 *self /= rhs;
444 }
445 }
446
447 impl core::ops::Rem<$t> for StandardForm {
448 type Output = Self;
449 #[must_use]
450 fn rem(self, other: $t) -> Self {
451 let rhs : Self = other.into();
452 self % rhs
453 }
454 }
455
456 impl core::ops::RemAssign<$t> for StandardForm {
457 fn rem_assign(&mut self, other: $t) {
458 let rhs : Self = other.into();
459 *self %= rhs;
460 }
461 }
462 )*
463 };
464}
465
466primitives!(ints => u8,u16,u32,u64,i8,i16,i32,i64);
467primitives!(ops => Finite<f64>);
468
469impl From<Finite<f64>> for StandardForm {
470 fn from(value: Finite<f64>) -> Self {
471 Self::new(value, Zero::zero())
472 }
473}
474
475#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
476#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
477pub enum ConversionError {
479 #[error("Constraint of Finite<f64> is voliated by NaN")]
481 NaN,
482
483 #[error("Constraint of Finite<f64> is voliated by Infinity")]
485 Infinity,
486}
487
488impl TryFrom<f64> for StandardForm {
489 type Error = ConversionError;
490 fn try_from(value: f64) -> Result<Self, Self::Error> {
491 if value.is_nan() {
493 return Err(ConversionError::NaN);
494 }
495
496 if value.is_infinite() {
498 return Err(ConversionError::Infinity);
499 }
500
501 Ok(Self::from(Finite::from(value)))
502 }
503}
504
505impl TryFrom<f32> for StandardForm {
506 type Error = ConversionError;
507 fn try_from(value: f32) -> Result<Self, Self::Error> {
508 Self::try_from(value as f64)
509 }
510}
511
512impl num_traits::Zero for StandardForm {
567 fn zero() -> Self {
568 Self::new_unchecked(Finite::zero(), num_traits::Zero::zero())
569 }
570
571 fn is_zero(&self) -> bool {
572 self.mantissa.is_zero() && self.exponent.is_zero()
573 }
574}
575
576impl num_traits::One for StandardForm {
577 fn one() -> Self {
578 Self::new_unchecked(Finite::one(), num_traits::Zero::zero())
579 }
580}
581
582impl num_traits::Num for StandardForm {
583 type FromStrRadixErr = crate::ParsingStandardFormError;
584
585 fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
586 match radix != 10 {
587 true => Err(crate::ParsingStandardFormError::InvalidRadix),
588 false => Self::try_from(s),
589 }
590 }
591}
592
593impl num_traits::Signed for StandardForm {
594 #[must_use]
595 fn abs(&self) -> Self {
596 Self::new_unchecked(self.mantissa().abs(), *self.exponent())
597 }
598
599 #[must_use]
600 fn abs_sub(&self, other: &Self) -> Self {
601 match *self <= *other {
602 true => Self::zero(),
603 false => self.clone() - other.clone(),
604 }
605 }
606
607 #[must_use]
608 fn signum(&self) -> Self {
609 match self.mantissa().into_inner().signum() as i8 {
610 1 => Self::one(),
611 0 => Self::zero(),
612 _ => -Self::one(),
613 }
614 }
615
616 #[must_use]
617 fn is_positive(&self) -> bool {
618 self.mantissa().is_sign_positive()
619 }
620
621 #[must_use]
622 fn is_negative(&self) -> bool {
623 self.mantissa().is_sign_negative()
624 }
625}
626
627impl num_traits::FromPrimitive for StandardForm {
628 #[must_use]
630 fn from_i64(n: i64) -> Option<Self> {
631 Some(Self::from(n))
632 }
633 #[must_use]
634 fn from_u64(n: u64) -> Option<Self> {
635 Some(Self::from(n))
636 }
637
638 fn from_f64(n: f64) -> Option<Self> {
639 Self::try_from(n).ok()
640 }
641
642 fn from_f32(n: f32) -> Option<Self> {
643 Self::try_from(n).ok()
644 }
645}
646
647impl num_traits::ToPrimitive for StandardForm {
648 fn to_f64(&self) -> Option<f64> {
649 10i8.checked_pow(self.exponent as u32)
650 .map(|v: i8| self.mantissa.into_inner() * (v as f64))
651 }
652
653 fn to_i64(&self) -> Option<i64> {
654 self.to_f64().and_then(|val| {
655 if val.is_nan() || val.is_infinite() {
657 return None;
658 }
659
660 if val < i64::MIN as f64 || val > i64::MAX as f64 {
662 return None;
663 }
664
665 Some(val as i64)
667 })
668 }
669
670 fn to_u64(&self) -> Option<u64> {
671 self.to_i64().and_then(|val| val.try_into().ok())
672 }
673}
674
675const FIRST_SMALLER_VALUE_THEN_10: f64 = 10.0 - f64::EPSILON;
676impl num_traits::Bounded for StandardForm {
677 fn max_value() -> Self {
678 Self::new_unchecked(FIRST_SMALLER_VALUE_THEN_10.into(), i8::MAX)
679 }
680
681 fn min_value() -> Self {
682 Self::new_unchecked((-FIRST_SMALLER_VALUE_THEN_10).into(), i8::MIN)
683 }
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689 use test_case::test_case;
690
691 const FALIURE_MSG: &str = "Failed parsing standardform";
692
693 #[test_case( 1.0, 2, "1.00e+2"; "already_in_scientific_notation")]
694 #[test_case( 0.01, 4, "1.00e+2"; "small_number_adjustment")]
695 #[test_case( 1234.0, 0, "1.234e+3"; "large_number_adjustment")]
696 #[test_case( -5678.9, 2, "-5.6789e+5"; "negative_number_adjustment")]
697 #[test_case( 0.000567, -3, "5.67e-7"; "small_negative_exponent_adjustment")]
698 #[test_case( 98765.432, 3, "9.8765432e+7"; "large_mantissa_adjustment")]
699 #[test_case( 0.99999, -1, "9.9999e-2"; "rounding_edge_case")]
700 #[test_case( 1.5, 10, "1.50e+10"; "zero_adjustment_required")]
701 #[test_case( -0.0001, 2, "-1.00e-2"; "negative_small_number_adjustment")]
702 #[test_case( 999.999, -5, "9.99999e-3"; "high_precision_adjustment")]
703 fn correct_adjustment(mantissa: f64, exponent: i8, expected_in_science_notation: &str) {
704 assert_eq!(
705 StandardForm::new(Finite::from_inner(mantissa), exponent).to_scientific_notation(),
706 StandardForm::try_from(expected_in_science_notation)
707 .expect(FALIURE_MSG)
708 .to_scientific_notation()
709 )
710 }
711
712 #[test_case("1.0e2", "1.00e+2"; "parse_correct_scientific_notation")]
713 #[test_case("12345.678", "1.2345678e+4"; "parse_large_number")]
714 #[test_case("0.000567", "5.67e-4"; "parse_small_number")]
715 #[test_case("1.2345e3", "1.2345e+3"; "parse_exponent_included")]
716 #[test_case("-5678.9", "-5.6789e+3"; "parse_negative_number")]
717 #[test_case("0.00000123", "1.23e-6"; "parse_tiny_number")]
718 #[test_case("9999999.0", "9.999999e6"; "parse_large_integer")]
719 #[test_case("-0.005", "-5.00e-3"; "parse_negative_small_number")]
720 #[test_case("98765e1", "9.8765e+5"; "parse_large_scientific")]
721 #[test_case("0.0012345678", "1.2345678e-3"; "parse_high_precision")]
722 fn parsing_standardform(input: &str, expected_in_science_notation: &str) {
723 assert_eq!(
724 StandardForm::try_from(input).map(|v| v.to_scientific_notation()),
725 Ok(StandardForm::try_from(expected_in_science_notation)
726 .expect(FALIURE_MSG)
727 .to_scientific_notation())
728 )
729 }
730
731 #[test_case("1.0e2", "2.0e2", "3.00e+2"; "addition_simple")]
732 #[test_case("1.5e3", "2.5e3", "4.00e+3"; "addition_large_numbers")]
733 #[test_case("1.0e-2", "2.0e-2", "3.00e-2"; "addition_small_numbers")]
734 #[test_case("-1.0e3", "2.0e3", "1.00e+3"; "addition_with_negative")]
735 #[test_case("3.5e4", "4.5e4", "8.00e+4"; "addition_similar_exponent")]
736 #[test_case("5.0e1", "5.0e2", "5.50e+2"; "addition_different_exponent")]
737 #[test_case("1.23e2", "-2.46e2", "-1.23e+2"; "addition_negative_result")]
738 #[test_case("1.0e6", "1.0e6", "2.00e+6"; "addition_large_equal_numbers")]
739 #[test_case("5.0e-5", "5.0e-5", "1.00e-4"; "addition_small_equal_numbers")]
740 #[test_case("9.9e1", "1.1e1", "1.10e+2"; "addition_with_carry")]
741 fn add_standardform(lhs: &str, rhs: &str, expected_in_science_notation: &str) {
742 let lhs = StandardForm::try_from(lhs).expect(FALIURE_MSG);
743 let rhs = StandardForm::try_from(rhs).expect(FALIURE_MSG);
744
745 assert_eq!(
746 (lhs + rhs).to_scientific_notation(),
747 StandardForm::try_from(expected_in_science_notation)
748 .expect(FALIURE_MSG)
749 .to_scientific_notation()
750 )
751 }
752
753 #[test_case("3.0e2", "2.0e2", "1.00e+2"; "subtraction_simple")]
754 #[test_case("5.0e3", "2.0e3", "3.00e+3"; "subtraction_large_numbers")]
755 #[test_case("2.0e-2", "1.0e-2", "1.00e-2"; "subtraction_small_numbers")]
756 #[test_case("1.0e6", "1.0e5", "9.00e+5"; "subtraction_large_difference")]
757 #[test_case("7.0e2", "3.0e2", "4.00e+2"; "subtraction_with_carry")]
758 #[test_case("1.23e2", "-2.46e2", "3.69e+2"; "subtraction_negative_term")]
759 #[test_case("5.0e-3", "1.0e-3", "4.00e-3"; "subtraction_small_difference")]
760 #[test_case("1.0e2", "9.0e1", "1.00e+1"; "subtraction_near_equal")]
761 #[test_case("-1.0e3", "-1.0e2", "-9.00e+2"; "subtraction_negative_numbers")]
762 #[test_case("1.0e1", "5.0e0", "5.00e+0"; "subtraction_half_value")]
763 fn sub_standardform(lhs: &str, rhs: &str, expected_in_science_notation: &str) {
764 let lhs = StandardForm::try_from(lhs).expect(FALIURE_MSG);
765 let rhs = StandardForm::try_from(rhs).expect(FALIURE_MSG);
766
767 assert_eq!(
768 (lhs - rhs).to_scientific_notation(),
769 StandardForm::try_from(expected_in_science_notation)
770 .expect(FALIURE_MSG)
771 .to_scientific_notation()
772 )
773 }
774
775 #[test_case("1.0e2", "2.0e2", "5.00e-1"; "division_simple")]
776 #[test_case("5.0e3", "2.0e3", "2.50e+0"; "division_large_numbers")]
777 #[test_case("2.0e-2", "1.0e-2", "2.00e+0"; "division_small_numbers")]
778 #[test_case("1.0e6", "1.0e3", "1.00e+3"; "division_large_by_large")]
779 #[test_case("9.0e2", "3.0e2", "3.00e+0"; "division_exact_division")]
780 #[test_case("7.0e5", "1.0e3", "7.00e+2"; "division_no_rounding")]
781 #[test_case("8.0e-4", "2.0e-2", "4.00e-2"; "division_small_by_small")]
782 #[test_case("5.0e2", "5.0e1", "1.00e+1"; "division_by_tenth")]
783 #[test_case("1.0e1", "2.0e1", "5.00e-1"; "division_half")]
784 #[test_case("1.0e-1", "5.0e-1", "2.00e-1"; "division_small_numbers_with_remainder")]
785 fn div_standardform(lhs: &str, rhs: &str, expected_in_science_notation: &str) {
786 let lhs = StandardForm::try_from(lhs).expect(FALIURE_MSG);
787 let rhs = StandardForm::try_from(rhs).expect(FALIURE_MSG);
788
789 assert_eq!(
790 (lhs / rhs).to_scientific_notation(),
791 StandardForm::try_from(expected_in_science_notation)
792 .expect(FALIURE_MSG)
793 .to_scientific_notation()
794 )
795 }
796
797 #[test_case("1.0e2", "2.0e2", "2.00e+4"; "multiplication_simple")]
798 #[test_case("5.0e3", "2.0e3", "1.00e+7"; "multiplication_large_numbers")]
799 #[test_case("2.0e-2", "1.0e-2", "2.00e-4"; "multiplication_small_numbers")]
800 #[test_case("1.0e6", "1.0e-3", "1.00e+3"; "multiplication_large_by_small")]
801 #[test_case("9.0e2", "3.0e2", "2.70e+5"; "multiplication_no_rounding")]
802 #[test_case("7.0e5", "1.0e3", "7.00e+8"; "multiplication_large_by_large")]
803 #[test_case("8.0e-4", "2.0e-2", "1.60e-5"; "multiplication_small_by_small")]
804 #[test_case("5.0e2", "5.0e1", "2.50e+4"; "multiplication_by_tenth")]
805 #[test_case("1.0e1", "2.0e1", "2.00e+2"; "multiplication_basic")]
806 #[test_case("1.0e-1", "5.0e-1", "5.00e-2"; "multiplication_small_numbers2")]
807 fn mul_standardform(lhs: &str, rhs: &str, expected_in_science_notation: &str) {
808 let lhs = StandardForm::try_from(lhs).expect(FALIURE_MSG);
809 let rhs = StandardForm::try_from(rhs).expect(FALIURE_MSG);
810
811 assert_eq!(
812 (lhs * rhs).to_scientific_notation(),
813 StandardForm::try_from(expected_in_science_notation)
814 .expect(FALIURE_MSG)
815 .to_scientific_notation()
816 )
817 }
818
819 #[test_case("5.0e2", "1.0e2", "0.00e+0"; "remainder_simple_whole")]
821 #[test_case("5.5e2", "1.0e2", "5.00e+1"; "remainder_simple_fraction")]
822 #[test_case("1.0e5", "3.0e4", "1.00e+4"; "remainder_large_numbers")]
823 #[test_case("1.0e2", "3.0e1", "1.00e+1"; "remainder_large_by_smaller")]
824 #[test_case("7.0e5", "4.0e5", "3.00e+5"; "remainder_no_rounding")]
825 #[test_case("1.2e-1", "5.0e-2", "2.00e-2"; "remainder_small_numbers")]
826 #[test_case("9.9e1", "2.0e1", "1.90e+1"; "remainder_with_fraction")]
827 #[test_case("5.0e3", "1.5e3", "5.00e+2"; "remainder_fraction_result")]
828 #[test_case("4.5e4", "1.0e4", "5.00e+3"; "remainder_exact_half")]
829 #[test_case("2.3e-1", "1.1e-1", "1.00e-2"; "remainder_small_fraction")]
830 fn rem_standardform(lhs: &str, rhs: &str, expected_in_science_notation: &str) {
831 let lhs = StandardForm::try_from(lhs).expect(FALIURE_MSG);
832 let rhs = StandardForm::try_from(rhs).expect(FALIURE_MSG);
833
834 assert_eq!(
835 (lhs % rhs).to_scientific_notation(),
836 StandardForm::try_from(expected_in_science_notation)
837 .expect(FALIURE_MSG)
838 .to_scientific_notation()
839 )
840 }
841}