Get vectors working
This commit is contained in:
parent
53891274f1
commit
0405d25998
86
src/calc.rs
86
src/calc.rs
@ -16,8 +16,8 @@ use std::collections::{BTreeMap, HashMap};
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use types::{
|
||||
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
|
||||
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters,
|
||||
CalculatorState, RegisterState,
|
||||
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
|
||||
RegisterState,
|
||||
};
|
||||
|
||||
/// The maximum precision allowed for the calculator
|
||||
@ -283,13 +283,11 @@ impl Calculator {
|
||||
Ok(())
|
||||
}
|
||||
'r' => {
|
||||
self.state =
|
||||
CalculatorState::WaitingForRegister(RegisterState::Load);
|
||||
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
|
||||
Ok(())
|
||||
}
|
||||
'R' => {
|
||||
self.state =
|
||||
CalculatorState::WaitingForRegister(RegisterState::Save);
|
||||
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
|
||||
Ok(())
|
||||
}
|
||||
'`' => {
|
||||
@ -348,11 +346,7 @@ impl Calculator {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn register_input(
|
||||
&mut self,
|
||||
register_state: RegisterState,
|
||||
c: char,
|
||||
) -> CalculatorResult<()> {
|
||||
fn register_input(&mut self, register_state: RegisterState, c: char) -> CalculatorResult<()> {
|
||||
match register_state {
|
||||
RegisterState::Save => {
|
||||
let f = self.pop()?;
|
||||
@ -379,14 +373,8 @@ impl Calculator {
|
||||
'r' => self.angle_mode = CalculatorAngleMode::Radians,
|
||||
'g' => self.angle_mode = CalculatorAngleMode::Grads,
|
||||
'_' => self.display_mode = CalculatorDisplayMode::Default,
|
||||
',' => {
|
||||
self.display_mode =
|
||||
CalculatorDisplayMode::Separated { separator: ',' }
|
||||
}
|
||||
' ' => {
|
||||
self.display_mode =
|
||||
CalculatorDisplayMode::Separated { separator: ' ' }
|
||||
}
|
||||
',' => self.display_mode = CalculatorDisplayMode::Separated { separator: ',' },
|
||||
' ' => self.display_mode = CalculatorDisplayMode::Separated { separator: ' ' },
|
||||
's' => {
|
||||
self.display_mode = CalculatorDisplayMode::Scientific {
|
||||
precision: DEFAULT_PRECISION,
|
||||
@ -517,7 +505,7 @@ impl Calculator {
|
||||
}
|
||||
}
|
||||
/// Pops a usize
|
||||
pub fn pop_usize(&mut self) -> CalculatorResult<usize> {
|
||||
pub fn peek_usize(&mut self) -> CalculatorResult<(usize, Entry)> {
|
||||
let entry = self.peek(0)?;
|
||||
let f = match entry {
|
||||
Entry::Number(Number { value }) => value,
|
||||
@ -530,26 +518,11 @@ impl Calculator {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
let u = f as usize;
|
||||
|
||||
self.direct_state_change(CalculatorStateChange {
|
||||
pop: OpArgs::Unary(entry),
|
||||
push: OpArgs::None,
|
||||
})?;
|
||||
|
||||
Ok(u)
|
||||
Ok((u, entry))
|
||||
}
|
||||
/// Pops a precision instead of an Entry. Precisions are of type usize
|
||||
pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
|
||||
let entry = self.peek(0)?;
|
||||
let f = match entry {
|
||||
Entry::Number(Number { value }) => value,
|
||||
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
|
||||
};
|
||||
// Ensure this can be cast to a usize
|
||||
if !f.is_finite() || f.is_sign_negative() {
|
||||
return Err(CalculatorError::ArithmeticError);
|
||||
}
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
let u = f as usize;
|
||||
let (u, entry) = self.peek_usize()?;
|
||||
|
||||
if u > MAX_PRECISION {
|
||||
return Err(CalculatorError::PrecisionTooHigh);
|
||||
@ -563,16 +536,14 @@ impl Calculator {
|
||||
}
|
||||
|
||||
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
||||
let count = self.pop_usize()?;
|
||||
let (entries, values): (Vec<Entry>, Vec<Number>) = (0..count)
|
||||
let (count, count_entry) = self.peek_usize()?;
|
||||
let (mut entries, values): (VecDeque<Entry>, Vec<Number>) = (1..=count)
|
||||
.map(|i| {
|
||||
let e = self.peek(i)?;
|
||||
match e {
|
||||
// TODO: For now, vectors only contain numbers
|
||||
Entry::Number(number) => Ok((e, number)),
|
||||
Entry::Vector(_vector) => {
|
||||
Err(CalculatorError::TypeMismatch)
|
||||
}
|
||||
Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch),
|
||||
}
|
||||
})
|
||||
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
|
||||
@ -583,8 +554,9 @@ impl Calculator {
|
||||
values,
|
||||
direction: true,
|
||||
});
|
||||
entries.push_front(count_entry);
|
||||
Ok(CalculatorStateChange {
|
||||
pop: OpArgs::Variable(entries),
|
||||
pop: OpArgs::Variable(Vec::from(entries)),
|
||||
push: OpArgs::Unary(entry),
|
||||
})
|
||||
}
|
||||
@ -610,15 +582,15 @@ impl Calculator {
|
||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
|
||||
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
|
||||
}
|
||||
CalculatorOperation::ArithmeticOperation(
|
||||
ArithmeticOperation::IntegerDivide,
|
||||
) => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))),
|
||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => {
|
||||
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?)))
|
||||
}
|
||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
|
||||
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
|
||||
}
|
||||
CalculatorOperation::ArithmeticOperation(
|
||||
ArithmeticOperation::AbsoluteValue,
|
||||
) => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))),
|
||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => {
|
||||
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
|
||||
}
|
||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
|
||||
self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?)))
|
||||
}
|
||||
@ -662,13 +634,9 @@ impl Calculator {
|
||||
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?)))
|
||||
}
|
||||
CalculatorOperation::BuildVector => self.build_vector(),
|
||||
CalculatorOperation::Dup => {
|
||||
self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a])))
|
||||
}
|
||||
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))),
|
||||
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
|
||||
CalculatorOperation::Swap => {
|
||||
self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a])))
|
||||
}
|
||||
CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))),
|
||||
CalculatorOperation::Undo => return self.history_op(false),
|
||||
CalculatorOperation::Redo => return self.history_op(true),
|
||||
// Macros are a no-op operator; need to insert for undo/redo
|
||||
@ -699,11 +667,7 @@ impl Calculator {
|
||||
}
|
||||
.last()
|
||||
.ok_or_else(|| {
|
||||
CalculatorError::EmptyHistory(String::from(if forward {
|
||||
"redo"
|
||||
} else {
|
||||
"undo"
|
||||
}))
|
||||
CalculatorError::EmptyHistory(String::from(if forward { "redo" } else { "undo" }))
|
||||
})?;
|
||||
|
||||
let target_history_mode = if forward {
|
||||
@ -826,7 +790,7 @@ impl Calculator {
|
||||
self.stack.push_front(a.clone()); // TODO: Remove the clones
|
||||
}
|
||||
OpArgs::Variable(entries) => {
|
||||
for e in entries {
|
||||
for e in entries.iter().rev() {
|
||||
self.stack.push_front(e.clone());
|
||||
}
|
||||
}
|
||||
|
@ -281,249 +281,6 @@ impl CalculatorEntry for Entry {
|
||||
}
|
||||
}
|
||||
|
||||
impl CalculatorEntry for Number {
|
||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||
Ok(format!("{}", self.value))
|
||||
}
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||
match display_mode {
|
||||
CalculatorDisplayMode::Default => format!("{}", self.value),
|
||||
CalculatorDisplayMode::Separated { separator } => {
|
||||
separated(self.value, *separator)
|
||||
}
|
||||
CalculatorDisplayMode::Scientific { precision } => {
|
||||
scientific(self.value, *precision)
|
||||
}
|
||||
CalculatorDisplayMode::Engineering { precision } => {
|
||||
engineering(self.value, *precision)
|
||||
}
|
||||
CalculatorDisplayMode::Fixed { precision } => {
|
||||
format!("{:0>.precision$}", self.value, precision = precision)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn is_valid(&self) -> bool {
|
||||
!self.value.is_nan() && !self.value.is_infinite()
|
||||
}
|
||||
fn negate(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self { value: -self.value }))
|
||||
}
|
||||
fn abs(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.abs(),
|
||||
}))
|
||||
}
|
||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.recip(),
|
||||
}))
|
||||
}
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
|
||||
CalculatorAngleMode::Radians => self.value.sin(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
(self.value * std::f64::consts::PI / 200.0).sin()
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
|
||||
CalculatorAngleMode::Radians => self.value.cos(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
(self.value * std::f64::consts::PI / 200.0).cos()
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
|
||||
CalculatorAngleMode::Radians => self.value.tan(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
(self.value * std::f64::consts::PI / 200.0).tan()
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.asin(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
self.value.asin() * std::f64::consts::PI / 200.0
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.acos(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
self.value.acos() * std::f64::consts::PI / 200.0
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.atan(),
|
||||
CalculatorAngleMode::Grads => {
|
||||
self.value.atan() * std::f64::consts::PI / 200.0
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn sqrt(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.sqrt(),
|
||||
}))
|
||||
}
|
||||
fn log(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.log10(),
|
||||
}))
|
||||
}
|
||||
fn ln(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.ln(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.add_vec(vector),
|
||||
Entry::Number(number) => self.add_num(number),
|
||||
}
|
||||
}
|
||||
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.sub_vec(vector),
|
||||
Entry::Number(number) => self.sub_num(number),
|
||||
}
|
||||
}
|
||||
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.mul_vec(vector),
|
||||
Entry::Number(number) => self.mul_num(number),
|
||||
}
|
||||
}
|
||||
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.div_vec(vector),
|
||||
Entry::Number(number) => self.div_num(number),
|
||||
}
|
||||
}
|
||||
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.int_divide_vec(vector),
|
||||
Entry::Number(number) => self.int_divide_num(number),
|
||||
}
|
||||
}
|
||||
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.modulo_vec(vector),
|
||||
Entry::Number(number) => self.modulo_num(number),
|
||||
}
|
||||
}
|
||||
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.pow_vec(vector),
|
||||
Entry::Number(number) => self.pow_num(number),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::add_num)
|
||||
}
|
||||
fn sub_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::sub_num)
|
||||
}
|
||||
fn mul_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::mul_num)
|
||||
}
|
||||
fn div_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::div_num)
|
||||
}
|
||||
fn int_divide_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::int_divide_num)
|
||||
}
|
||||
fn modulo_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::modulo_num)
|
||||
}
|
||||
fn pow_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::pow_num)
|
||||
}
|
||||
|
||||
fn add_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value + self.value,
|
||||
}))
|
||||
}
|
||||
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value - self.value,
|
||||
}))
|
||||
}
|
||||
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value * self.value,
|
||||
}))
|
||||
}
|
||||
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value / self.value,
|
||||
}))
|
||||
}
|
||||
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value.div_euclid(self.value),
|
||||
}))
|
||||
}
|
||||
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value % self.value,
|
||||
}))
|
||||
}
|
||||
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: arg.value.powf(self.value),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Number {
|
||||
fn iterated_binary(
|
||||
self,
|
||||
vector: &Vector,
|
||||
op: impl Fn(&Self, &Self) -> CalculatorResult<Entry>,
|
||||
) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Vector(Vector {
|
||||
values: vector
|
||||
.values
|
||||
.iter()
|
||||
.map(|n| op(&self, n))
|
||||
.map(|e| match e {
|
||||
// Only numbers are valid in a vector
|
||||
Ok(Entry::Number(number)) => Ok(number),
|
||||
_ => Err(CalculatorError::ArithmeticError),
|
||||
})
|
||||
.collect::<CalculatorResult<Vec<Self>>>()?,
|
||||
direction: vector.direction,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl CalculatorEntry for Vector {
|
||||
// Misc
|
||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||
@ -531,10 +288,7 @@ impl CalculatorEntry for Vector {
|
||||
Err(CalculatorError::TypeMismatch)
|
||||
}
|
||||
fn is_valid(&self) -> bool {
|
||||
self.values
|
||||
.iter()
|
||||
.find(|number| !number.is_valid())
|
||||
.is_none()
|
||||
self.values.iter().all(|number| number.is_valid())
|
||||
}
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||
format!(
|
||||
@ -543,7 +297,7 @@ impl CalculatorEntry for Vector {
|
||||
.iter()
|
||||
.map(|number| number.format_entry(display_mode))
|
||||
.collect::<Vec<String>>()
|
||||
.join("; ")
|
||||
.join(if self.direction { "; " } else { " " })
|
||||
)
|
||||
}
|
||||
// Mathematical operations
|
||||
@ -551,10 +305,19 @@ impl CalculatorEntry for Vector {
|
||||
self.iterated_unary(Number::negate)
|
||||
}
|
||||
fn abs(&self) -> CalculatorResult<Entry> {
|
||||
self.iterated_unary(Number::abs)
|
||||
let value: Entry = self
|
||||
.values
|
||||
.iter()
|
||||
.try_fold(Entry::Number(Number::ZERO), |acc, n2| {
|
||||
acc.add(&n2.pow_num(&Number { value: 2.0_f64 })?)
|
||||
})?;
|
||||
Ok(value.sqrt()?)
|
||||
}
|
||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||
self.iterated_unary(Number::inverse)
|
||||
Ok(Entry::Vector(Vector {
|
||||
values: self.values.clone(),
|
||||
direction: !self.direction,
|
||||
}))
|
||||
}
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
self.iterated_unary(|n| n.sin(angle_mode))
|
||||
@ -698,11 +461,10 @@ impl Vector {
|
||||
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
|
||||
) -> CalculatorResult<Entry> {
|
||||
if self.values.len() != v2.values.len() {
|
||||
return Err(CalculatorError::ArithmeticError);
|
||||
return Err(CalculatorError::DimensionMismatch);
|
||||
}
|
||||
if self.direction != v2.direction {
|
||||
// TODO: Return a different error
|
||||
return Err(CalculatorError::ArithmeticError);
|
||||
return Err(CalculatorError::DimensionMismatch);
|
||||
}
|
||||
Ok(Entry::Vector(Self {
|
||||
values: self
|
||||
@ -740,6 +502,248 @@ impl Vector {
|
||||
}
|
||||
}
|
||||
|
||||
impl CalculatorEntry for Number {
|
||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||
Ok(format!("{}", self.value))
|
||||
}
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||
match display_mode {
|
||||
CalculatorDisplayMode::Default => format!("{}", self.value),
|
||||
CalculatorDisplayMode::Separated { separator } => separated(self.value, *separator),
|
||||
CalculatorDisplayMode::Scientific { precision } => scientific(self.value, *precision),
|
||||
CalculatorDisplayMode::Engineering { precision } => engineering(self.value, *precision),
|
||||
CalculatorDisplayMode::Fixed { precision } => {
|
||||
format!("{:0>.precision$}", self.value, precision = precision)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn is_valid(&self) -> bool {
|
||||
!self.value.is_nan() && !self.value.is_infinite()
|
||||
}
|
||||
fn negate(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self { value: -self.value }))
|
||||
}
|
||||
fn abs(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.abs(),
|
||||
}))
|
||||
}
|
||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.recip(),
|
||||
}))
|
||||
}
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
|
||||
CalculatorAngleMode::Radians => self.value.sin(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).sin(),
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
|
||||
CalculatorAngleMode::Radians => self.value.cos(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).cos(),
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
|
||||
CalculatorAngleMode::Radians => self.value.tan(),
|
||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).tan(),
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.asin(),
|
||||
CalculatorAngleMode::Grads => self.value.asin() * std::f64::consts::PI / 200.0,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.acos(),
|
||||
CalculatorAngleMode::Grads => self.value.acos() * std::f64::consts::PI / 200.0,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: match angle_mode {
|
||||
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
|
||||
CalculatorAngleMode::Radians => self.value.atan(),
|
||||
CalculatorAngleMode::Grads => self.value.atan() * std::f64::consts::PI / 200.0,
|
||||
},
|
||||
}))
|
||||
}
|
||||
fn sqrt(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.sqrt(),
|
||||
}))
|
||||
}
|
||||
fn log(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.log10(),
|
||||
}))
|
||||
}
|
||||
fn ln(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Self {
|
||||
value: self.value.ln(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.add_vec(vector),
|
||||
Entry::Number(number) => self.add_num(number),
|
||||
}
|
||||
}
|
||||
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.sub_vec(vector),
|
||||
Entry::Number(number) => self.sub_num(number),
|
||||
}
|
||||
}
|
||||
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.mul_vec(vector),
|
||||
Entry::Number(number) => self.mul_num(number),
|
||||
}
|
||||
}
|
||||
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.div_vec(vector),
|
||||
Entry::Number(number) => self.div_num(number),
|
||||
}
|
||||
}
|
||||
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.int_divide_vec(vector),
|
||||
Entry::Number(number) => self.int_divide_num(number),
|
||||
}
|
||||
}
|
||||
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.modulo_vec(vector),
|
||||
Entry::Number(number) => self.modulo_num(number),
|
||||
}
|
||||
}
|
||||
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Vector(vector) => self.pow_vec(vector),
|
||||
Entry::Number(number) => self.pow_num(number),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::add_num)
|
||||
}
|
||||
fn sub_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::sub_num)
|
||||
}
|
||||
fn mul_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::mul_num)
|
||||
}
|
||||
fn div_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::div_num)
|
||||
}
|
||||
fn int_divide_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::int_divide_num)
|
||||
}
|
||||
fn modulo_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::modulo_num)
|
||||
}
|
||||
fn pow_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
|
||||
self.iterated_binary(arg, Self::pow_num)
|
||||
}
|
||||
|
||||
fn add_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value + arg.value,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value - arg.value,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value * arg.value,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value / arg.value,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value.div_euclid(arg.value),
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value % arg.value,
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry> {
|
||||
Self {
|
||||
value: self.value.powf(arg.value),
|
||||
}
|
||||
.validate()
|
||||
}
|
||||
}
|
||||
|
||||
impl Number {
|
||||
pub const ZERO: Self = Self { value: 0.0_f64 };
|
||||
|
||||
fn validate(&self) -> CalculatorResult<Entry> {
|
||||
if self.is_valid() {
|
||||
Ok(Entry::Number(*self))
|
||||
} else {
|
||||
Err(CalculatorError::ArithmeticError)
|
||||
}
|
||||
}
|
||||
|
||||
fn iterated_binary(
|
||||
self,
|
||||
vector: &Vector,
|
||||
op: impl Fn(&Self, &Self) -> CalculatorResult<Entry>,
|
||||
) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Vector(Vector {
|
||||
values: vector
|
||||
.values
|
||||
.iter()
|
||||
.map(|n| op(&self, n))
|
||||
.map(|e| match e {
|
||||
// Only numbers are valid in a vector
|
||||
Ok(Entry::Number(number)) => Ok(number),
|
||||
_ => Err(CalculatorError::ArithmeticError),
|
||||
})
|
||||
.collect::<CalculatorResult<Vec<Self>>>()?,
|
||||
direction: vector.direction,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CalculatorEntry
|
||||
where
|
||||
Self: Sized,
|
||||
@ -800,7 +804,7 @@ impl fmt::Display for Entry {
|
||||
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@ pub enum CalculatorError {
|
||||
NotEnoughStackEntries,
|
||||
/// Requested type does not match target type
|
||||
TypeMismatch,
|
||||
/// Dimensions must match
|
||||
DimensionMismatch,
|
||||
/// Thrown when an undo or redo cannot be performed
|
||||
CorruptStateChange(String),
|
||||
/// Cannot undo or redo
|
||||
@ -47,6 +49,7 @@ impl fmt::Display for CalculatorError {
|
||||
Self::ArithmeticError => write!(f, "Arithmetic Error"),
|
||||
Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
|
||||
Self::TypeMismatch => write!(f, "Type mismatch"),
|
||||
Self::DimensionMismatch => write!(f, "Dimension mismatch"),
|
||||
Self::CorruptStateChange(msg) => {
|
||||
write!(f, "Corrupt state change: {}", msg)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user