Continue work on separating complex types
This commit is contained in:
parent
c47287b4e6
commit
dab0333b31
@ -8,25 +8,25 @@ use std::fmt;
|
|||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Number {
|
pub struct Number {
|
||||||
pub value: f64,
|
pub value: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Number {
|
impl PartialEq for Number {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
if self.value.is_nan() && other.value.is_nan()
|
if self.value.is_nan() && other.value.is_nan()
|
||||||
|| self.value.is_infinite() && other.value.is_infinite()
|
|| self.value.is_infinite() && other.value.is_infinite()
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else if self.value.is_nan()
|
} else if self.value.is_nan()
|
||||||
|| self.value.is_infinite()
|
|| self.value.is_infinite()
|
||||||
|| other.value.is_infinite()
|
|| other.value.is_infinite()
|
||||||
|| other.value.is_nan()
|
|| other.value.is_nan()
|
||||||
{
|
{
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
(self.value - other.value).abs() >= f64::EPSILON
|
(self.value - other.value).abs() >= f64::EPSILON
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
@ -34,400 +34,418 @@ impl PartialEq for Number {
|
|||||||
// pub value: Vec<Number>,
|
// pub value: Vec<Number>,
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Entry {
|
pub enum Entry {
|
||||||
Number(Number),
|
Number(Number),
|
||||||
// Vector(Vec<Number>),
|
// Vector(Vec<Number>),
|
||||||
// Matrix(Vec<Vec<Number>>),
|
// Matrix(Vec<Vec<Number>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CalculatorEntry for Entry {
|
impl CalculatorEntry for Entry {
|
||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(number) => number.format_entry(display_mode),
|
Self::Number(number) => number.format_entry(display_mode),
|
||||||
// Self::Vector(vector) => vector.add(),
|
// Self::Vector(vector) => vector.add(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
fn is_valid(&self) -> bool {
|
||||||
fn is_valid(&self) -> bool {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.is_valid(),
|
||||||
Self::Number(number) => number.is_valid(),
|
// Self::Vector(vector) => vector.add(),
|
||||||
// Self::Vector(vector) => vector.add(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn add(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn add(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.add(arg),
|
||||||
Self::Number(number) => number.add(arg),
|
// Self::Vector(vector) => vector.add(),
|
||||||
// Self::Vector(vector) => vector.add(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn sub(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn sub(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.sub(arg),
|
||||||
Self::Number(number) => number.sub(arg),
|
// Self::Vector(vector) => vector.sub(),
|
||||||
// Self::Vector(vector) => vector.sub(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn mul(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn mul(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.mul(arg),
|
||||||
Self::Number(number) => number.mul(arg),
|
// Self::Vector(vector) => vector.mul(),
|
||||||
// Self::Vector(vector) => vector.mul(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn div(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn div(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.div(arg),
|
||||||
Self::Number(number) => number.div(arg),
|
// Self::Vector(vector) => vector.div(),
|
||||||
// Self::Vector(vector) => vector.div(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn int_divide(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn int_divide(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.int_divide(arg),
|
||||||
Self::Number(number) => number.int_divide(arg),
|
// Self::Vector(vector) => vector.int_divide(),
|
||||||
// Self::Vector(vector) => vector.int_divide(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn negate(&self) -> CalculatorResult<Self> {
|
||||||
fn negate(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.negate(),
|
||||||
Self::Number(number) => number.negate(),
|
// Self::Vector(vector) => vector.negate(),
|
||||||
// Self::Vector(vector) => vector.negate(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn abs(&self) -> CalculatorResult<Self> {
|
||||||
fn abs(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.abs(),
|
||||||
Self::Number(number) => number.abs(),
|
// Self::Vector(vector) => vector.abs(),
|
||||||
// Self::Vector(vector) => vector.abs(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn inverse(&self) -> CalculatorResult<Self> {
|
||||||
fn inverse(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.inverse(),
|
||||||
Self::Number(number) => number.inverse(),
|
// Self::Vector(vector) => vector.inverse(),
|
||||||
// Self::Vector(vector) => vector.inverse(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn modulo(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn modulo(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.modulo(arg),
|
||||||
Self::Number(number) => number.modulo(arg),
|
// Self::Vector(vector) => vector.modulo(),
|
||||||
// Self::Vector(vector) => vector.modulo(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.sin(angle_mode),
|
||||||
Self::Number(number) => number.sin(angle_mode),
|
// Self::Vector(vector) => vector.sin(),
|
||||||
// Self::Vector(vector) => vector.sin(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.cos(angle_mode),
|
||||||
Self::Number(number) => number.cos(angle_mode),
|
// Self::Vector(vector) => vector.cos(),
|
||||||
// Self::Vector(vector) => vector.cos(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.tan(angle_mode),
|
||||||
Self::Number(number) => number.tan(angle_mode),
|
// Self::Vector(vector) => vector.tan(),
|
||||||
// Self::Vector(vector) => vector.tan(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.asin(angle_mode),
|
||||||
Self::Number(number) => number.asin(angle_mode),
|
// Self::Vector(vector) => vector.asin(),
|
||||||
// Self::Vector(vector) => vector.asin(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.acos(angle_mode),
|
||||||
Self::Number(number) => number.acos(angle_mode),
|
// Self::Vector(vector) => vector.acos(),
|
||||||
// Self::Vector(vector) => vector.acos(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.atan(angle_mode),
|
||||||
Self::Number(number) => number.atan(angle_mode),
|
// Self::Vector(vector) => vector.atan(),
|
||||||
// Self::Vector(vector) => vector.atan(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn sqrt(&self) -> CalculatorResult<Self> {
|
||||||
fn sqrt(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.sqrt(),
|
||||||
Self::Number(number) => number.sqrt(),
|
// Self::Vector(vector) => vector.sqrt(),
|
||||||
// Self::Vector(vector) => vector.sqrt(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn log(&self) -> CalculatorResult<Self> {
|
||||||
fn log(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.log(),
|
||||||
Self::Number(number) => number.log(),
|
// Self::Vector(vector) => vector.log(),
|
||||||
// Self::Vector(vector) => vector.log(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn ln(&self) -> CalculatorResult<Self> {
|
||||||
fn ln(&self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.ln(),
|
||||||
Self::Number(number) => number.ln(),
|
// Self::Vector(vector) => vector.ln(),
|
||||||
// Self::Vector(vector) => vector.ln(),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn pow(&self, arg: Self) -> CalculatorResult<Self> {
|
||||||
fn pow(&self, arg: Self) -> CalculatorResult<Self> {
|
match self {
|
||||||
match self {
|
Self::Number(number) => number.pow(arg),
|
||||||
Self::Number(number) => number.pow(arg),
|
// Self::Vector(vector) => vector.pow(),
|
||||||
// Self::Vector(vector) => vector.pow(),
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CalculatorEntry for Number {
|
impl CalculatorEntry for Number {
|
||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||||
match display_mode {
|
match display_mode {
|
||||||
CalculatorDisplayMode::Default => format!("{}", self.value),
|
CalculatorDisplayMode::Default => format!("{}", self.value),
|
||||||
CalculatorDisplayMode::Separated { separator } => separated(self.value, *separator),
|
CalculatorDisplayMode::Separated { separator } => {
|
||||||
CalculatorDisplayMode::Scientific { precision } => scientific(self.value, *precision),
|
separated(self.value, *separator)
|
||||||
CalculatorDisplayMode::Engineering { precision } => engineering(self.value, *precision),
|
}
|
||||||
CalculatorDisplayMode::Fixed { precision } => {
|
CalculatorDisplayMode::Scientific { precision } => {
|
||||||
format!("{:0>.precision$}", self.value, precision = 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 {
|
||||||
fn is_valid(&self) -> bool {
|
!self.value.is_nan() && !self.value.is_infinite()
|
||||||
!self.value.is_nan() && !self.value.is_infinite()
|
|
||||||
}
|
|
||||||
fn add(&self, arg: Entry) -> CalculatorResult<Entry> {
|
|
||||||
match arg {
|
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
|
||||||
value: value + self.value,
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
fn add(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
|
match arg {
|
||||||
match arg {
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
value: value + self.value,
|
||||||
value: value - self.value,
|
})),
|
||||||
})),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
|
match arg {
|
||||||
match arg {
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
value: value - self.value,
|
||||||
value: value * self.value,
|
})),
|
||||||
})),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
|
match arg {
|
||||||
match arg {
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
value: value * self.value,
|
||||||
value: value / self.value,
|
})),
|
||||||
})),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
|
match arg {
|
||||||
match arg {
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
value: value / self.value,
|
||||||
value: value.div_euclid(self.value),
|
})),
|
||||||
})),
|
}
|
||||||
}
|
}
|
||||||
}
|
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
fn negate(&self) -> CalculatorResult<Entry> {
|
match arg {
|
||||||
Ok(Entry::Number(Number { value: -self.value }))
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
}
|
value: value.div_euclid(self.value),
|
||||||
fn abs(&self) -> CalculatorResult<Entry> {
|
})),
|
||||||
Ok(Entry::Number(Number {
|
}
|
||||||
value: self.value.abs(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
fn inverse(&self) -> CalculatorResult<Entry> {
|
|
||||||
Ok(Entry::Number(Number {
|
|
||||||
value: self.value.recip(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> {
|
|
||||||
match arg {
|
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
|
||||||
value: value % self.value,
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
fn negate(&self) -> CalculatorResult<Entry> {
|
||||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
Ok(Entry::Number(Number { value: -self.value }))
|
||||||
Ok(Entry::Number(Number {
|
}
|
||||||
value: match angle_mode {
|
fn abs(&self) -> CalculatorResult<Entry> {
|
||||||
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
|
Ok(Entry::Number(Number {
|
||||||
CalculatorAngleMode::Radians => self.value.sin(),
|
value: self.value.abs(),
|
||||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).sin(),
|
}))
|
||||||
},
|
}
|
||||||
}))
|
fn inverse(&self) -> CalculatorResult<Entry> {
|
||||||
}
|
Ok(Entry::Number(Number {
|
||||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
value: self.value.recip(),
|
||||||
Ok(Entry::Number(Number {
|
}))
|
||||||
value: match angle_mode {
|
}
|
||||||
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
|
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
CalculatorAngleMode::Radians => self.value.cos(),
|
match arg {
|
||||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).cos(),
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
},
|
value: value % self.value,
|
||||||
}))
|
})),
|
||||||
}
|
}
|
||||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
}
|
||||||
Ok(Entry::Number(Number {
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
value: match angle_mode {
|
Ok(Entry::Number(Number {
|
||||||
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
|
value: match angle_mode {
|
||||||
CalculatorAngleMode::Radians => self.value.tan(),
|
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
|
||||||
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).tan(),
|
CalculatorAngleMode::Radians => self.value.sin(),
|
||||||
},
|
CalculatorAngleMode::Grads => {
|
||||||
}))
|
(self.value * std::f64::consts::PI / 200.0).sin()
|
||||||
}
|
}
|
||||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
},
|
||||||
Ok(Entry::Number(Number {
|
}))
|
||||||
value: match angle_mode {
|
}
|
||||||
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
CalculatorAngleMode::Radians => self.value.asin(),
|
Ok(Entry::Number(Number {
|
||||||
CalculatorAngleMode::Grads => self.value.asin() * std::f64::consts::PI / 200.0,
|
value: match angle_mode {
|
||||||
},
|
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
|
||||||
}))
|
CalculatorAngleMode::Radians => self.value.cos(),
|
||||||
}
|
CalculatorAngleMode::Grads => {
|
||||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
(self.value * std::f64::consts::PI / 200.0).cos()
|
||||||
Ok(Entry::Number(Number {
|
}
|
||||||
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 tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
},
|
Ok(Entry::Number(Number {
|
||||||
}))
|
value: match angle_mode {
|
||||||
}
|
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
|
||||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
CalculatorAngleMode::Radians => self.value.tan(),
|
||||||
Ok(Entry::Number(Number {
|
CalculatorAngleMode::Grads => {
|
||||||
value: match angle_mode {
|
(self.value * std::f64::consts::PI / 200.0).tan()
|
||||||
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
|
}
|
||||||
CalculatorAngleMode::Radians => self.value.atan(),
|
},
|
||||||
CalculatorAngleMode::Grads => self.value.atan() * std::f64::consts::PI / 200.0,
|
}))
|
||||||
},
|
}
|
||||||
}))
|
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
}
|
Ok(Entry::Number(Number {
|
||||||
fn sqrt(&self) -> CalculatorResult<Entry> {
|
value: match angle_mode {
|
||||||
Ok(Entry::Number(Number {
|
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
|
||||||
value: self.value.sqrt(),
|
CalculatorAngleMode::Radians => self.value.asin(),
|
||||||
}))
|
CalculatorAngleMode::Grads => {
|
||||||
}
|
self.value.asin() * std::f64::consts::PI / 200.0
|
||||||
fn log(&self) -> CalculatorResult<Entry> {
|
}
|
||||||
Ok(Entry::Number(Number {
|
},
|
||||||
value: self.value.log10(),
|
}))
|
||||||
}))
|
}
|
||||||
}
|
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
fn ln(&self) -> CalculatorResult<Entry> {
|
Ok(Entry::Number(Number {
|
||||||
Ok(Entry::Number(Number {
|
value: match angle_mode {
|
||||||
value: self.value.ln(),
|
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
|
||||||
}))
|
CalculatorAngleMode::Radians => self.value.acos(),
|
||||||
}
|
CalculatorAngleMode::Grads => {
|
||||||
fn pow(&self, arg: Entry) -> CalculatorResult<Entry> {
|
self.value.acos() * std::f64::consts::PI / 200.0
|
||||||
match arg {
|
}
|
||||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
},
|
||||||
value: value.powf(self.value),
|
}))
|
||||||
})),
|
}
|
||||||
|
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||||
|
Ok(Entry::Number(Number {
|
||||||
|
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(Number {
|
||||||
|
value: self.value.sqrt(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn log(&self) -> CalculatorResult<Entry> {
|
||||||
|
Ok(Entry::Number(Number {
|
||||||
|
value: self.value.log10(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn ln(&self) -> CalculatorResult<Entry> {
|
||||||
|
Ok(Entry::Number(Number {
|
||||||
|
value: self.value.ln(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
fn pow(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||||
|
match arg {
|
||||||
|
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||||
|
value: value.powf(self.value),
|
||||||
|
})),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CalculatorEntry {
|
pub trait CalculatorEntry {
|
||||||
// Misc
|
// Misc
|
||||||
fn is_valid(&self) -> bool;
|
fn is_valid(&self) -> bool;
|
||||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
||||||
// Mathematical operations
|
// Mathematical operations
|
||||||
fn add(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn add(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn sub(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn sub(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn mul(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn div(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn negate(&self) -> CalculatorResult<Entry>;
|
fn negate(&self) -> CalculatorResult<Entry>;
|
||||||
fn abs(&self) -> CalculatorResult<Entry>;
|
fn abs(&self) -> CalculatorResult<Entry>;
|
||||||
fn inverse(&self) -> CalculatorResult<Entry>;
|
fn inverse(&self) -> CalculatorResult<Entry>;
|
||||||
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
|
||||||
fn sqrt(&self) -> CalculatorResult<Entry>;
|
fn sqrt(&self) -> CalculatorResult<Entry>;
|
||||||
fn log(&self) -> CalculatorResult<Entry>;
|
fn log(&self) -> CalculatorResult<Entry>;
|
||||||
fn ln(&self) -> CalculatorResult<Entry>;
|
fn ln(&self) -> CalculatorResult<Entry>;
|
||||||
fn pow(&self, arg: Entry) -> CalculatorResult<Entry>;
|
fn pow(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Entry {
|
impl fmt::Display for Entry {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Number(Number { value }) => write!(f, "{}", value),
|
Self::Number(Number { value }) => write!(f, "{}", value),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://stackoverflow.com/a/65266882
|
// Based on https://stackoverflow.com/a/65266882
|
||||||
fn scientific(f: f64, precision: usize) -> String {
|
fn scientific(f: f64, precision: usize) -> String {
|
||||||
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
||||||
let exp = ret.split_off(ret.find('E').unwrap_or(0));
|
let exp = ret.split_off(ret.find('E').unwrap_or(0));
|
||||||
let (exp_sign, exp) = exp
|
let (exp_sign, exp) = exp
|
||||||
.strip_prefix("E-")
|
.strip_prefix("E-")
|
||||||
.map_or_else(|| ('+', &exp[1..]), |stripped| ('-', stripped));
|
.map_or_else(|| ('+', &exp[1..]), |stripped| ('-', stripped));
|
||||||
|
|
||||||
let sign = if ret.starts_with('-') { "" } else { " " };
|
let sign = if ret.starts_with('-') { "" } else { " " };
|
||||||
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
|
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn engineering(f: f64, precision: usize) -> String {
|
fn engineering(f: f64, precision: usize) -> String {
|
||||||
// Format the string so the first digit is always in the first column, and remove '.'. Requested precision + 2 to account for using 1, 2, or 3 digits for the whole portion of the string
|
// Format the string so the first digit is always in the first column, and remove '.'. Requested precision + 2 to account for using 1, 2, or 3 digits for the whole portion of the string
|
||||||
// 1,000 => 1000E3
|
// 1,000 => 1000E3
|
||||||
let all = format!(" {:.precision$E}", f, precision = precision)
|
let all = format!(" {:.precision$E}", f, precision = precision)
|
||||||
// Remove . since it can be moved
|
// Remove . since it can be moved
|
||||||
.replacen(".", "", 1)
|
.replacen(".", "", 1)
|
||||||
// Add 00E before E here so the length is enough for slicing below
|
// Add 00E before E here so the length is enough for slicing below
|
||||||
.replacen("E", "00E", 1);
|
.replacen("E", "00E", 1);
|
||||||
// Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E
|
// Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E
|
||||||
// 1000E3 => (1000, E3)
|
// 1000E3 => (1000, E3)
|
||||||
let (num_str, exp_str) = all.split_at(all.find('E').unwrap());
|
let (num_str, exp_str) = all.split_at(all.find('E').unwrap());
|
||||||
// Extract the exponent as an isize. This should always be true because Entry max will be ~400
|
// Extract the exponent as an isize. This should always be true because Entry max will be ~400
|
||||||
// E3 => 3 as isize
|
// E3 => 3 as isize
|
||||||
let exp = exp_str[1..].parse::<isize>().unwrap();
|
let exp = exp_str[1..].parse::<isize>().unwrap();
|
||||||
// Sign of the exponent. If string representation starts with E-, then negative
|
// Sign of the exponent. If string representation starts with E-, then negative
|
||||||
let display_exp_sign = if exp_str.strip_prefix("E-").is_some() {
|
let display_exp_sign = if exp_str.strip_prefix("E-").is_some() {
|
||||||
'-'
|
'-'
|
||||||
} else {
|
} else {
|
||||||
'+'
|
'+'
|
||||||
};
|
};
|
||||||
|
|
||||||
// The exponent to display. Always a multiple of 3 in engineering mode. Always positive because sign is added with display_exp_sign above
|
// The exponent to display. Always a multiple of 3 in engineering mode. Always positive because sign is added with display_exp_sign above
|
||||||
// 100 => 0, 1000 => 3, .1 => 3 (but will show as -3)
|
// 100 => 0, 1000 => 3, .1 => 3 (but will show as -3)
|
||||||
let display_exp = (exp.div_euclid(3) * 3).abs();
|
let display_exp = (exp.div_euclid(3) * 3).abs();
|
||||||
// Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility
|
// Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility
|
||||||
let num_whole_digits = exp.rem_euclid(3) as usize + 1;
|
let num_whole_digits = exp.rem_euclid(3) as usize + 1;
|
||||||
|
|
||||||
// If this is a negative number, strip off the added space, otherwise keep the space (and next digit)
|
// If this is a negative number, strip off the added space, otherwise keep the space (and next digit)
|
||||||
let num_str = if num_str.strip_prefix(" -").is_some() {
|
let num_str = if num_str.strip_prefix(" -").is_some() {
|
||||||
&num_str[1..]
|
&num_str[1..]
|
||||||
} else {
|
} else {
|
||||||
num_str
|
num_str
|
||||||
};
|
};
|
||||||
|
|
||||||
// Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit)
|
// Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit)
|
||||||
// Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10
|
// Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10
|
||||||
let whole = &num_str[0..=num_whole_digits];
|
let whole = &num_str[0..=num_whole_digits];
|
||||||
// Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2
|
// Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2
|
||||||
let decimal = &num_str[(num_whole_digits + 1)..=(precision + num_whole_digits)];
|
let decimal = &num_str[(num_whole_digits + 1)..=(precision + num_whole_digits)];
|
||||||
// Right align whole portion, always have decimal point
|
// Right align whole portion, always have decimal point
|
||||||
format!(
|
format!(
|
||||||
"{: >4}.{} E{}{:0>pad$}",
|
"{: >4}.{} E{}{:0>pad$}",
|
||||||
// display_sign,
|
// display_sign,
|
||||||
whole,
|
whole,
|
||||||
decimal,
|
decimal,
|
||||||
display_exp_sign,
|
display_exp_sign,
|
||||||
display_exp,
|
display_exp,
|
||||||
pad = 2
|
pad = 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn separated(f: f64, sep: char) -> String {
|
fn separated(f: f64, sep: char) -> String {
|
||||||
let mut ret = f.to_string();
|
let mut ret = f.to_string();
|
||||||
let start = if ret.starts_with('-') { 1 } else { 0 };
|
let start = if ret.starts_with('-') { 1 } else { 0 };
|
||||||
let end = ret.find('.').unwrap_or_else(|| ret.len());
|
let end = ret.find('.').unwrap_or_else(|| ret.len());
|
||||||
for i in 0..((end - start - 1).div_euclid(3)) {
|
for i in 0..((end - start - 1).div_euclid(3)) {
|
||||||
ret.insert(end - (i + 1) * 3, sep);
|
ret.insert(end - (i + 1) * 3, sep);
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user