Add ArithmeticOperation

This commit is contained in:
Austen Adler 2021-05-31 15:37:55 -04:00
parent 39e3c83abc
commit d84f2f7076
3 changed files with 223 additions and 111 deletions

View File

@ -7,7 +7,7 @@ use crate::calc::entries::CalculatorEntry;
use confy::{load, store};
use entries::{Entry, Number};
use errors::{CalculatorError, CalculatorResult};
use operations::{CalculatorOperation, CalculatorStateChange, MacroState, OpArgs};
use operations::{ArithmeticOperation,CalculatorOperation, CalculatorStateChange, MacroState, OpArgs};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
@ -214,29 +214,29 @@ impl Calculator {
_ => Err(CalculatorError::ParseError),
}
}
'+' => self.op(CalculatorOperation::Add),
'-' => self.op(CalculatorOperation::Subtract),
'*' => self.op(CalculatorOperation::Multiply),
'/' => self.op(CalculatorOperation::Divide),
'n' => self.op(CalculatorOperation::Negate),
'|' => self.op(CalculatorOperation::AbsoluteValue),
'i' => self.op(CalculatorOperation::Inverse),
'%' => self.op(CalculatorOperation::Modulo),
'+' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Add)),
'-' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Subtract)),
'*' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Multiply)),
'/' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide)),
'n' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate)),
'|' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue)),
'i' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse)),
'%' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Modulo)),
'?' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide)),
's' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sin)),
'c' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Cos)),
't' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Tan)),
'S' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ASin)),
'C' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ACos)),
'T' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ATan)),
'v' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sqrt)),
'^' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow)),
'l' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Log)),
'L' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Ln)),
// Special
'\\' => self.op(CalculatorOperation::Drop),
'?' => self.op(CalculatorOperation::IntegerDivide),
' ' => self.op(CalculatorOperation::Dup),
'>' => self.op(CalculatorOperation::Swap),
's' => self.op(CalculatorOperation::Sin),
'c' => self.op(CalculatorOperation::Cos),
't' => self.op(CalculatorOperation::Tan),
'S' => self.op(CalculatorOperation::ASin),
'C' => self.op(CalculatorOperation::ACos),
'T' => self.op(CalculatorOperation::ATan),
'v' => self.op(CalculatorOperation::Sqrt),
'^' => self.op(CalculatorOperation::Pow),
'l' => self.op(CalculatorOperation::Log),
'L' => self.op(CalculatorOperation::Ln),
// Special
'u' => self.op(CalculatorOperation::Undo),
'U' => self.op(CalculatorOperation::Redo),
// State modifiers
@ -478,7 +478,7 @@ impl Calculator {
let entry = self.peek(0)?;
let f = match entry {
Entry::Number(Number { value }) => value,
// Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
};
// Ensure this can be cast to a usize
if !f.is_finite() || f.is_sign_negative() {
@ -507,63 +507,63 @@ impl Calculator {
}
}
let state_change = match op {
CalculatorOperation::Add => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Add) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(a)?)))
}
CalculatorOperation::Subtract => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Subtract) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.sub(a)?)))
}
CalculatorOperation::Multiply => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Multiply) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.mul(a)?)))
}
CalculatorOperation::Divide => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(a)?)))
}
CalculatorOperation::IntegerDivide => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(a)?)))
}
CalculatorOperation::Negate => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
}
CalculatorOperation::AbsoluteValue => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
}
CalculatorOperation::Inverse => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?)))
}
CalculatorOperation::Modulo => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Modulo) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.modulo(a)?)))
}
CalculatorOperation::Sin => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sin) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.sin(angle_mode)?)))
}
CalculatorOperation::Cos => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Cos) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.cos(angle_mode)?)))
}
CalculatorOperation::Tan => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Tan) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.tan(angle_mode)?)))
}
CalculatorOperation::ASin => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ASin) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.asin(angle_mode)?)))
}
CalculatorOperation::ACos => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ACos) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.acos(angle_mode)?)))
}
CalculatorOperation::ATan => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ATan) => {
let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.atan(angle_mode)?)))
}
CalculatorOperation::Sqrt => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sqrt) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.sqrt()?)))
}
CalculatorOperation::Log => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))),
CalculatorOperation::Ln => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))),
CalculatorOperation::Pow => {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Log) => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Ln) => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(a)?)))
}
CalculatorOperation::Dup => {
@ -741,7 +741,6 @@ impl Calculator {
&mut self,
op: impl FnOnce(Entry) -> CalculatorResult<OpArgs>,
) -> CalculatorResult<CalculatorStateChange> {
// TODO: Use peek instead of stack.get()
let arg = self.peek(0)?;
Ok(CalculatorStateChange {
pop: OpArgs::Unary(arg.clone()),

View File

@ -1,5 +1,6 @@
// use super::operations::CalculatorStateChange;
use super::errors::CalculatorResult;
// TODO: This file kina blows. Tons of repetition. Do not know how to fix yet though
use super::errors::{CalculatorError, CalculatorResult};
use super::types::CalculatorAngleMode;
use crate::calc::CalculatorDisplayMode;
use serde::{Deserialize, Serialize};
@ -11,6 +12,15 @@ pub struct Number {
pub value: f64,
}
impl Number {
fn binary_op(arg: &Entry, op: impl Fn(&Number) -> Number) -> CalculatorResult<Entry> {
match arg {
Entry::Number(number) => Ok(Entry::Number(op(number))),
Entry::Vector(vector) => Ok(vector.map_into(op)),
}
}
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
if self.value.is_nan() && other.value.is_nan()
@ -29,17 +39,52 @@ impl PartialEq for Number {
}
}
// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
// pub struct Vector {
// pub value: Vec<Number>,
// }
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct Vector {
pub direction: bool,
pub values: Vec<Number>,
}
impl Vector {
fn binary_op(
&self,
arg: &Entry,
op: impl Fn((&Number, &Number)) -> Number,
) -> CalculatorResult<Entry> {
match arg {
// Entry::Number(number) => Ok(Entry::Number(op(number))),
Entry::Number(number) => Ok(self.map_into(|t| op((t, number)))),
Entry::Vector(vector) => {
if self.values.len() != vector.values.len() {
return Err(CalculatorError::ArithmeticError);
}
Ok(Entry::Vector(Vector {
values: self
.values
.iter()
.zip(vector.values.iter())
.map(op)
.collect(),
..*self
}))
}
}
}
pub fn map_into(&self, op: impl Fn(&Number) -> Number) -> Entry {
Entry::Vector(Vector {
values: (self.values.iter().map(op).collect()),
..*self
})
}
}
// TODO: Remove the copy trait
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum Entry {
Number(Number),
// Vector(Vec<Number>),
Vector(Vector),
// Matrix(Vec<Vec<Number>>),
}
@ -47,127 +92,127 @@ impl CalculatorEntry for Entry {
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match self {
Self::Number(number) => number.format_entry(display_mode),
// Self::Vector(vector) => vector.add(),
Self::Vector(vector) => vector.format_entry(display_mode),
}
}
fn is_valid(&self) -> bool {
match self {
Self::Number(number) => number.is_valid(),
// Self::Vector(vector) => vector.add(),
Self::Vector(vector) => vector.is_valid(),
}
}
fn add(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.add(arg),
// Self::Vector(vector) => vector.add(),
Self::Vector(vector) => vector.add(arg),
}
}
fn sub(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sub(arg),
// Self::Vector(vector) => vector.sub(),
Self::Vector(vector) => vector.sub(arg),
}
}
fn mul(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.mul(arg),
// Self::Vector(vector) => vector.mul(),
Self::Vector(vector) => vector.mul(arg),
}
}
fn div(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.div(arg),
// Self::Vector(vector) => vector.div(),
Self::Vector(vector) => vector.div(arg),
}
}
fn int_divide(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.int_divide(arg),
// Self::Vector(vector) => vector.int_divide(),
Self::Vector(vector) => vector.int_divide(arg),
}
}
fn negate(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.negate(),
// Self::Vector(vector) => vector.negate(),
Self::Vector(vector) => vector.negate(),
}
}
fn abs(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.abs(),
// Self::Vector(vector) => vector.abs(),
Self::Vector(vector) => vector.abs(),
}
}
fn inverse(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.inverse(),
// Self::Vector(vector) => vector.inverse(),
Self::Vector(vector) => vector.inverse(),
}
}
fn modulo(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.modulo(arg),
// Self::Vector(vector) => vector.modulo(),
Self::Vector(vector) => vector.modulo(arg),
}
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sin(angle_mode),
// Self::Vector(vector) => vector.sin(),
Self::Vector(vector) => vector.sin(angle_mode),
}
}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.cos(angle_mode),
// Self::Vector(vector) => vector.cos(),
Self::Vector(vector) => vector.cos(angle_mode),
}
}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.tan(angle_mode),
// Self::Vector(vector) => vector.tan(),
Self::Vector(vector) => vector.tan(angle_mode),
}
}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.asin(angle_mode),
// Self::Vector(vector) => vector.asin(),
Self::Vector(vector) => vector.asin(angle_mode),
}
}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.acos(angle_mode),
// Self::Vector(vector) => vector.acos(),
Self::Vector(vector) => vector.acos(angle_mode),
}
}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.atan(angle_mode),
// Self::Vector(vector) => vector.atan(),
Self::Vector(vector) => vector.atan(angle_mode),
}
}
fn sqrt(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sqrt(),
// Self::Vector(vector) => vector.sqrt(),
Self::Vector(vector) => vector.sqrt(),
}
}
fn log(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.log(),
// Self::Vector(vector) => vector.log(),
Self::Vector(vector) => vector.log(),
}
}
fn ln(&self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.ln(),
// Self::Vector(vector) => vector.ln(),
Self::Vector(vector) => vector.ln(),
}
}
fn pow(&self, arg: Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.pow(arg),
// Self::Vector(vector) => vector.pow(),
Self::Vector(vector) => vector.pow(arg),
}
}
}
@ -194,39 +239,29 @@ impl CalculatorEntry for Number {
!self.value.is_nan() && !self.value.is_infinite()
}
fn add(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value + self.value,
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value + self.value,
})
}
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value - self.value,
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value - self.value,
})
}
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value * self.value,
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value * self.value,
})
}
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value / self.value,
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value / self.value,
})
}
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value.div_euclid(self.value),
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value.div_euclid(self.value),
})
}
fn negate(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { value: -self.value }))
@ -242,11 +277,9 @@ impl CalculatorEntry for Number {
}))
}
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value % self.value,
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value % self.value,
})
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
@ -330,11 +363,88 @@ impl CalculatorEntry for Number {
}))
}
fn pow(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value.powf(self.value),
})),
}
Number::binary_op(&arg, |b| Self {
value: b.value.powf(self.value),
})
}
}
impl CalculatorEntry for Vector {
// Misc
fn is_valid(&self) -> bool {
!self.values
.iter()
.find(|number| !number.is_valid())
.is_some()
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
format!(
"[{}]",
self.values
.iter()
.map(|number| number.format_entry(display_mode))
.collect::<Vec<String>>()
.join("; ")
)
}
// Mathematical operations
fn add(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value + a.value,
})
}
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value - a.value,
})
}
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value * a.value,
})
}
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value / a.value,
})
}
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value.div_euclid(a.value),
})
}
fn negate(&self) -> CalculatorResult<Entry> {
Ok(self.map_into(|n| Number { value: -n.value }))
}
fn abs(&self) -> CalculatorResult<Entry> {
Ok(self.map_into(|n| Number {
value: n.value.abs(),
}))
}
fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Vector {
direction: !self.direction,
..*self
}))
}
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value % a.value,
})
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn sqrt(&self) -> CalculatorResult<Entry> {}
fn log(&self) -> CalculatorResult<Entry> {}
fn ln(&self) -> CalculatorResult<Entry> {}
fn pow(&self, arg: Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value.powf(a.value),
})
}
}

View File

@ -1,8 +1,8 @@
use super::entries::Entry;
use serde::{Deserialize, Serialize};
/// Operations that can be sent to the calculator such as +, -, or undo
#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub enum CalculatorOperation {
pub enum ArithmeticOperation {
Add,
Subtract,
Multiply,
@ -12,7 +12,6 @@ pub enum CalculatorOperation {
Inverse,
Modulo,
IntegerDivide,
//Remainder,
Sin,
Cos,
Tan,
@ -20,12 +19,16 @@ pub enum CalculatorOperation {
ACos,
ATan,
Sqrt,
Undo,
Redo,
Pow,
// Factorial,
Log,
Ln,
}
/// Operations that can be sent to the calculator such as +, -, or undo
#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub enum CalculatorOperation {
ArithmeticOperation(ArithmeticOperation),
Undo,
Redo,
Drop,
Dup,
Swap,