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 std::collections::{HashSet, VecDeque};
|
||||||
use types::{
|
use types::{
|
||||||
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
|
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
|
||||||
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters,
|
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
|
||||||
CalculatorState, RegisterState,
|
RegisterState,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The maximum precision allowed for the calculator
|
/// The maximum precision allowed for the calculator
|
||||||
@ -283,13 +283,11 @@ impl Calculator {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
'r' => {
|
'r' => {
|
||||||
self.state =
|
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
|
||||||
CalculatorState::WaitingForRegister(RegisterState::Load);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
'R' => {
|
'R' => {
|
||||||
self.state =
|
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
|
||||||
CalculatorState::WaitingForRegister(RegisterState::Save);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
'`' => {
|
'`' => {
|
||||||
@ -348,11 +346,7 @@ impl Calculator {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn register_input(
|
fn register_input(&mut self, register_state: RegisterState, c: char) -> CalculatorResult<()> {
|
||||||
&mut self,
|
|
||||||
register_state: RegisterState,
|
|
||||||
c: char,
|
|
||||||
) -> CalculatorResult<()> {
|
|
||||||
match register_state {
|
match register_state {
|
||||||
RegisterState::Save => {
|
RegisterState::Save => {
|
||||||
let f = self.pop()?;
|
let f = self.pop()?;
|
||||||
@ -379,14 +373,8 @@ impl Calculator {
|
|||||||
'r' => self.angle_mode = CalculatorAngleMode::Radians,
|
'r' => self.angle_mode = CalculatorAngleMode::Radians,
|
||||||
'g' => self.angle_mode = CalculatorAngleMode::Grads,
|
'g' => self.angle_mode = CalculatorAngleMode::Grads,
|
||||||
'_' => self.display_mode = CalculatorDisplayMode::Default,
|
'_' => self.display_mode = CalculatorDisplayMode::Default,
|
||||||
',' => {
|
',' => self.display_mode = CalculatorDisplayMode::Separated { separator: ',' },
|
||||||
self.display_mode =
|
' ' => self.display_mode = CalculatorDisplayMode::Separated { separator: ' ' },
|
||||||
CalculatorDisplayMode::Separated { separator: ',' }
|
|
||||||
}
|
|
||||||
' ' => {
|
|
||||||
self.display_mode =
|
|
||||||
CalculatorDisplayMode::Separated { separator: ' ' }
|
|
||||||
}
|
|
||||||
's' => {
|
's' => {
|
||||||
self.display_mode = CalculatorDisplayMode::Scientific {
|
self.display_mode = CalculatorDisplayMode::Scientific {
|
||||||
precision: DEFAULT_PRECISION,
|
precision: DEFAULT_PRECISION,
|
||||||
@ -517,7 +505,7 @@ impl Calculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Pops a usize
|
/// 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 entry = self.peek(0)?;
|
||||||
let f = match entry {
|
let f = match entry {
|
||||||
Entry::Number(Number { value }) => value,
|
Entry::Number(Number { value }) => value,
|
||||||
@ -530,26 +518,11 @@ impl Calculator {
|
|||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
let u = f as usize;
|
let u = f as usize;
|
||||||
|
|
||||||
self.direct_state_change(CalculatorStateChange {
|
Ok((u, entry))
|
||||||
pop: OpArgs::Unary(entry),
|
|
||||||
push: OpArgs::None,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(u)
|
|
||||||
}
|
}
|
||||||
/// Pops a precision instead of an Entry. Precisions are of type usize
|
/// Pops a precision instead of an Entry. Precisions are of type usize
|
||||||
pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
|
pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
|
||||||
let entry = self.peek(0)?;
|
let (u, entry) = self.peek_usize()?;
|
||||||
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;
|
|
||||||
|
|
||||||
if u > MAX_PRECISION {
|
if u > MAX_PRECISION {
|
||||||
return Err(CalculatorError::PrecisionTooHigh);
|
return Err(CalculatorError::PrecisionTooHigh);
|
||||||
@ -563,16 +536,14 @@ impl Calculator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
|
||||||
let count = self.pop_usize()?;
|
let (count, count_entry) = self.peek_usize()?;
|
||||||
let (entries, values): (Vec<Entry>, Vec<Number>) = (0..count)
|
let (mut entries, values): (VecDeque<Entry>, Vec<Number>) = (1..=count)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let e = self.peek(i)?;
|
let e = self.peek(i)?;
|
||||||
match e {
|
match e {
|
||||||
// TODO: For now, vectors only contain numbers
|
// TODO: For now, vectors only contain numbers
|
||||||
Entry::Number(number) => Ok((e, number)),
|
Entry::Number(number) => Ok((e, number)),
|
||||||
Entry::Vector(_vector) => {
|
Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch),
|
||||||
Err(CalculatorError::TypeMismatch)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
|
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
|
||||||
@ -583,8 +554,9 @@ impl Calculator {
|
|||||||
values,
|
values,
|
||||||
direction: true,
|
direction: true,
|
||||||
});
|
});
|
||||||
|
entries.push_front(count_entry);
|
||||||
Ok(CalculatorStateChange {
|
Ok(CalculatorStateChange {
|
||||||
pop: OpArgs::Variable(entries),
|
pop: OpArgs::Variable(Vec::from(entries)),
|
||||||
push: OpArgs::Unary(entry),
|
push: OpArgs::Unary(entry),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -610,15 +582,15 @@ impl Calculator {
|
|||||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
|
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
|
||||||
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
|
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
|
||||||
}
|
}
|
||||||
CalculatorOperation::ArithmeticOperation(
|
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => {
|
||||||
ArithmeticOperation::IntegerDivide,
|
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?)))
|
||||||
) => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))),
|
}
|
||||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
|
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
|
||||||
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
|
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
|
||||||
}
|
}
|
||||||
CalculatorOperation::ArithmeticOperation(
|
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => {
|
||||||
ArithmeticOperation::AbsoluteValue,
|
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
|
||||||
) => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))),
|
}
|
||||||
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
|
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
|
||||||
self.unary_op(|a| Ok(OpArgs::Unary(a.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)?)))
|
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?)))
|
||||||
}
|
}
|
||||||
CalculatorOperation::BuildVector => self.build_vector(),
|
CalculatorOperation::BuildVector => self.build_vector(),
|
||||||
CalculatorOperation::Dup => {
|
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))),
|
||||||
self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a])))
|
|
||||||
}
|
|
||||||
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
|
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
|
||||||
CalculatorOperation::Swap => {
|
CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))),
|
||||||
self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a])))
|
|
||||||
}
|
|
||||||
CalculatorOperation::Undo => return self.history_op(false),
|
CalculatorOperation::Undo => return self.history_op(false),
|
||||||
CalculatorOperation::Redo => return self.history_op(true),
|
CalculatorOperation::Redo => return self.history_op(true),
|
||||||
// Macros are a no-op operator; need to insert for undo/redo
|
// Macros are a no-op operator; need to insert for undo/redo
|
||||||
@ -699,11 +667,7 @@ impl Calculator {
|
|||||||
}
|
}
|
||||||
.last()
|
.last()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
CalculatorError::EmptyHistory(String::from(if forward {
|
CalculatorError::EmptyHistory(String::from(if forward { "redo" } else { "undo" }))
|
||||||
"redo"
|
|
||||||
} else {
|
|
||||||
"undo"
|
|
||||||
}))
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let target_history_mode = if forward {
|
let target_history_mode = if forward {
|
||||||
@ -826,7 +790,7 @@ impl Calculator {
|
|||||||
self.stack.push_front(a.clone()); // TODO: Remove the clones
|
self.stack.push_front(a.clone()); // TODO: Remove the clones
|
||||||
}
|
}
|
||||||
OpArgs::Variable(entries) => {
|
OpArgs::Variable(entries) => {
|
||||||
for e in entries {
|
for e in entries.iter().rev() {
|
||||||
self.stack.push_front(e.clone());
|
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 {
|
impl CalculatorEntry for Vector {
|
||||||
// Misc
|
// Misc
|
||||||
fn to_editable_string(&self) -> CalculatorResult<String> {
|
fn to_editable_string(&self) -> CalculatorResult<String> {
|
||||||
@ -531,10 +288,7 @@ impl CalculatorEntry for Vector {
|
|||||||
Err(CalculatorError::TypeMismatch)
|
Err(CalculatorError::TypeMismatch)
|
||||||
}
|
}
|
||||||
fn is_valid(&self) -> bool {
|
fn is_valid(&self) -> bool {
|
||||||
self.values
|
self.values.iter().all(|number| number.is_valid())
|
||||||
.iter()
|
|
||||||
.find(|number| !number.is_valid())
|
|
||||||
.is_none()
|
|
||||||
}
|
}
|
||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
format!(
|
format!(
|
||||||
@ -543,7 +297,7 @@ impl CalculatorEntry for Vector {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|number| number.format_entry(display_mode))
|
.map(|number| number.format_entry(display_mode))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("; ")
|
.join(if self.direction { "; " } else { " " })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Mathematical operations
|
// Mathematical operations
|
||||||
@ -551,10 +305,19 @@ impl CalculatorEntry for Vector {
|
|||||||
self.iterated_unary(Number::negate)
|
self.iterated_unary(Number::negate)
|
||||||
}
|
}
|
||||||
fn abs(&self) -> CalculatorResult<Entry> {
|
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> {
|
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> {
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
self.iterated_unary(|n| n.sin(angle_mode))
|
self.iterated_unary(|n| n.sin(angle_mode))
|
||||||
@ -698,11 +461,10 @@ impl Vector {
|
|||||||
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
|
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
|
||||||
) -> CalculatorResult<Entry> {
|
) -> CalculatorResult<Entry> {
|
||||||
if self.values.len() != v2.values.len() {
|
if self.values.len() != v2.values.len() {
|
||||||
return Err(CalculatorError::ArithmeticError);
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
}
|
}
|
||||||
if self.direction != v2.direction {
|
if self.direction != v2.direction {
|
||||||
// TODO: Return a different error
|
return Err(CalculatorError::DimensionMismatch);
|
||||||
return Err(CalculatorError::ArithmeticError);
|
|
||||||
}
|
}
|
||||||
Ok(Entry::Vector(Self {
|
Ok(Entry::Vector(Self {
|
||||||
values: 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
|
pub trait CalculatorEntry
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
@ -800,7 +804,7 @@ impl fmt::Display for Entry {
|
|||||||
|
|
||||||
impl fmt::Display for Number {
|
impl fmt::Display for Number {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}", self)
|
write!(f, "{}", self.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ pub enum CalculatorError {
|
|||||||
NotEnoughStackEntries,
|
NotEnoughStackEntries,
|
||||||
/// Requested type does not match target type
|
/// Requested type does not match target type
|
||||||
TypeMismatch,
|
TypeMismatch,
|
||||||
|
/// Dimensions must match
|
||||||
|
DimensionMismatch,
|
||||||
/// Thrown when an undo or redo cannot be performed
|
/// Thrown when an undo or redo cannot be performed
|
||||||
CorruptStateChange(String),
|
CorruptStateChange(String),
|
||||||
/// Cannot undo or redo
|
/// Cannot undo or redo
|
||||||
@ -47,6 +49,7 @@ impl fmt::Display for CalculatorError {
|
|||||||
Self::ArithmeticError => write!(f, "Arithmetic Error"),
|
Self::ArithmeticError => write!(f, "Arithmetic Error"),
|
||||||
Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
|
Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
|
||||||
Self::TypeMismatch => write!(f, "Type mismatch"),
|
Self::TypeMismatch => write!(f, "Type mismatch"),
|
||||||
|
Self::DimensionMismatch => write!(f, "Dimension mismatch"),
|
||||||
Self::CorruptStateChange(msg) => {
|
Self::CorruptStateChange(msg) => {
|
||||||
write!(f, "Corrupt state change: {}", msg)
|
write!(f, "Corrupt state change: {}", msg)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user