diff --git a/core/src/error.rs b/core/src/error.rs index 009ee590..236997a4 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -32,7 +32,6 @@ pub(crate) enum FendError { ExpectedARationalNumber, CannotConvertToInteger, ComplexToInteger, - NumberWithUnitToInt, InexactNumberToInt, ExpectedANumber, ExpectedABool(&'static str), @@ -74,16 +73,13 @@ pub(crate) enum FendError { ExpectedAString, ExpectedARealNumber, ConversionRhsNumerical, - FactorialUnitless, ModuloForPositiveInts, - ExpUnitless, IncompatibleConversion { from: String, to: String, from_base: String, to_base: String, }, - ModuloUnitless, RootsOfNegativeNumbers, NonIntegerNegRoots, CannotConvertValueTo(&'static str), @@ -104,13 +100,8 @@ impl fmt::Display for FendError { match self { Self::Interrupted => write!(f, "interrupted"), Self::ParseError(e) => write!(f, "{e}"), - Self::FactorialUnitless => { - write!(f, "factorial is only supported for unitless numbers") - } Self::DeserializationError => write!(f, "failed to deserialize object"), - Self::ModuloUnitless => write!(f, "modulo is only supported for unitless numbers"), Self::FactorialComplex => write!(f, "factorial is not supported for complex numbers"), - Self::ExpUnitless => write!(f, "exponentiation is only supported for unitless numbers"), Self::IoError(_) => write!(f, "I/O error"), Self::InvalidBasePrefix => write!( f, @@ -191,7 +182,6 @@ impl fmt::Display for FendError { Self::ExpectedARationalNumber => write!(f, "expected a rational number"), Self::CannotConvertToInteger => write!(f, "number cannot be converted to an integer"), Self::ComplexToInteger => write!(f, "cannot convert complex number to integer"), - Self::NumberWithUnitToInt => write!(f, "cannot convert number with unit to integer"), Self::InexactNumberToInt => write!(f, "cannot convert inexact number to integer"), Self::ExpectedANumber => write!(f, "expected a number"), Self::InvalidDiceSyntax => write!(f, "invalid dice syntax, try e.g. `4d6`"), diff --git a/core/src/num/unit.rs b/core/src/num/unit.rs index 5c4de166..41f8e264 100644 --- a/core/src/num/unit.rs +++ b/core/src/num/unit.rs @@ -83,10 +83,7 @@ impl Value { } pub(crate) fn try_as_usize(self, int: &I) -> FResult { - if !self.is_unitless(int)? { - return Err(FendError::NumberWithUnitToInt); - } - self.try_as_usize_unit(int) + self.into_unitless_complex(int)?.try_as_usize(int) } pub(crate) fn try_as_usize_unit(self, int: &I) -> FResult { @@ -160,16 +157,13 @@ impl Value { } pub(crate) fn factorial(self, int: &I) -> FResult { - if !self.is_unitless(int)? { - return Err(FendError::FactorialUnitless); - } Ok(Self { - value: Dist::from(self.value.one_point()?.factorial(int)?), - unit: self.unit, + unit: Unit::unitless(), exact: self.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, + value: Dist::from(self.into_unitless_complex(int)?.factorial(int)?), }) } @@ -280,74 +274,59 @@ impl Value { } fn modulo(self, rhs: Self, int: &I) -> FResult { - if !self.is_unitless(int)? || !rhs.is_unitless(int)? { - return Err(FendError::ModuloUnitless); - } Ok(Self { - value: Dist::from( - self.value - .one_point()? - .modulo(rhs.value.one_point()?, int)?, - ), - unit: self.unit, + unit: Unit::unitless(), exact: self.exact && rhs.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, + value: Dist::from( + self.into_unitless_complex(int)? + .modulo(rhs.into_unitless_complex(int)?, int)?, + ), }) } fn bitwise(self, rhs: Self, op: BitwiseBop, int: &I) -> FResult { - if !self.is_unitless(int)? || !rhs.is_unitless(int)? { - return Err(FendError::ExpectedAUnitlessNumber); - } Ok(Self { - value: Dist::from( - self.value - .one_point()? - .bitwise(rhs.value.one_point()?, op, int)?, - ), - unit: self.unit, + unit: Unit::unitless(), exact: self.exact && rhs.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, + value: Dist::from(self.into_unitless_complex(int)?.bitwise( + rhs.into_unitless_complex(int)?, + op, + int, + )?), }) } pub(crate) fn combination(self, rhs: Self, int: &I) -> FResult { - if !self.is_unitless(int)? || !rhs.is_unitless(int)? { - return Err(FendError::ExpectedAUnitlessNumber); - } Ok(Self { - value: Dist::from( - self.value - .one_point()? - .combination(rhs.value.one_point()?, int)?, - ), - unit: self.unit, + unit: Unit::unitless(), exact: self.exact && rhs.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, + value: Dist::from( + self.into_unitless_complex(int)? + .combination(rhs.into_unitless_complex(int)?, int)?, + ), }) } pub(crate) fn permutation(self, rhs: Self, int: &I) -> FResult { - if !self.is_unitless(int)? || !rhs.is_unitless(int)? { - return Err(FendError::ExpectedAUnitlessNumber); - } Ok(Self { - value: Dist::from( - self.value - .one_point()? - .permutation(rhs.value.one_point()?, int)?, - ), - unit: self.unit, + unit: Unit::unitless(), exact: self.exact && rhs.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, + value: Dist::from( + self.into_unitless_complex(int)? + .permutation(rhs.into_unitless_complex(int)?, int)?, + ), }) } @@ -393,14 +372,13 @@ impl Value { } pub(crate) fn pow(self, rhs: Self, int: &I) -> FResult { - if !rhs.is_unitless(int)? { - return Err(FendError::ExpUnitless); - } + let rhs_exact = rhs.exact; + let rhs = rhs.into_unitless_complex(int)?; let mut new_components = vec![]; let mut exact_res = true; for unit_exp in self.unit.components { let exponent = Exact::new(unit_exp.exponent, self.exact) - .mul(&Exact::new(rhs.value.clone().one_point()?, rhs.exact), int)?; + .mul(&Exact::new(rhs.clone(), rhs_exact), int)?; exact_res = exact_res && exponent.exact; new_components.push(UnitExponent { unit: unit_exp.unit, @@ -410,11 +388,11 @@ impl Value { let new_unit = Unit { components: new_components, }; - let value = self.value.one_point()?.pow(rhs.value.one_point()?, int)?; + let value = self.value.one_point()?.pow(rhs, int)?; Ok(Self { value: value.value.into(), unit: new_unit, - exact: self.exact && rhs.exact && exact_res && value.exact, + exact: self.exact && rhs_exact && exact_res && value.exact, base: self.base, format: self.format, simplifiable: self.simplifiable, @@ -489,6 +467,14 @@ impl Value { self.convert_to(Self::unitless(), int) } + fn into_unitless_complex(mut self, int: &I) -> FResult { + self = self.remove_unit_scaling(int)?; + if !self.is_unitless(int)? { + return Err(FendError::ExpectedAUnitlessNumber); + } + self.value.one_point() + } + fn apply_fn_exact( mut self, f: impl FnOnce(Complex, &I) -> FResult>, diff --git a/core/tests/integration_tests.rs b/core/tests/integration_tests.rs index ed063790..91237ffa 100644 --- a/core/tests/integration_tests.rs +++ b/core/tests/integration_tests.rs @@ -5972,3 +5972,9 @@ fn modulo_percent() { test_eval("5%4", "1"); test_eval("(104857566-103811072+1) % (1024*1024/512)", "2015"); } + +#[test] +fn modulo_unitless() { + test_eval("5 mod (4k)", "5"); + test_eval("(4k)^2", "16000000"); +}