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)]
|
||||
pub struct Number {
|
||||
pub value: f64,
|
||||
pub value: f64,
|
||||
}
|
||||
|
||||
impl PartialEq for Number {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.value.is_nan() && other.value.is_nan()
|
||||
|| self.value.is_infinite() && other.value.is_infinite()
|
||||
{
|
||||
true
|
||||
} else if self.value.is_nan()
|
||||
|| self.value.is_infinite()
|
||||
|| other.value.is_infinite()
|
||||
|| other.value.is_nan()
|
||||
{
|
||||
false
|
||||
} else {
|
||||
(self.value - other.value).abs() >= f64::EPSILON
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if self.value.is_nan() && other.value.is_nan()
|
||||
|| self.value.is_infinite() && other.value.is_infinite()
|
||||
{
|
||||
true
|
||||
} else if self.value.is_nan()
|
||||
|| self.value.is_infinite()
|
||||
|| other.value.is_infinite()
|
||||
|| other.value.is_nan()
|
||||
{
|
||||
false
|
||||
} else {
|
||||
(self.value - other.value).abs() >= f64::EPSILON
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
@ -34,400 +34,418 @@ impl PartialEq for Number {
|
||||
// pub value: Vec<Number>,
|
||||
// }
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Entry {
|
||||
Number(Number),
|
||||
// Vector(Vec<Number>),
|
||||
// Matrix(Vec<Vec<Number>>),
|
||||
Number(Number),
|
||||
// Vector(Vec<Number>),
|
||||
// Matrix(Vec<Vec<Number>>),
|
||||
}
|
||||
|
||||
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(),
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
|
||||
match self {
|
||||
Self::Number(number) => number.format_entry(display_mode),
|
||||
// Self::Vector(vector) => vector.add(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn is_valid(&self) -> bool {
|
||||
match self {
|
||||
Self::Number(number) => number.is_valid(),
|
||||
// Self::Vector(vector) => vector.add(),
|
||||
fn is_valid(&self) -> bool {
|
||||
match self {
|
||||
Self::Number(number) => number.is_valid(),
|
||||
// Self::Vector(vector) => vector.add(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn add(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.add(arg),
|
||||
// Self::Vector(vector) => vector.add(),
|
||||
fn add(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.add(arg),
|
||||
// Self::Vector(vector) => vector.add(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn sub(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sub(arg),
|
||||
// Self::Vector(vector) => vector.sub(),
|
||||
fn sub(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sub(arg),
|
||||
// Self::Vector(vector) => vector.sub(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn mul(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.mul(arg),
|
||||
// Self::Vector(vector) => vector.mul(),
|
||||
fn mul(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.mul(arg),
|
||||
// Self::Vector(vector) => vector.mul(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn div(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.div(arg),
|
||||
// Self::Vector(vector) => vector.div(),
|
||||
fn div(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.div(arg),
|
||||
// Self::Vector(vector) => vector.div(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn int_divide(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.int_divide(arg),
|
||||
// Self::Vector(vector) => vector.int_divide(),
|
||||
fn int_divide(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.int_divide(arg),
|
||||
// Self::Vector(vector) => vector.int_divide(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn negate(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.negate(),
|
||||
// Self::Vector(vector) => vector.negate(),
|
||||
fn negate(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.negate(),
|
||||
// Self::Vector(vector) => vector.negate(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn abs(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.abs(),
|
||||
// Self::Vector(vector) => vector.abs(),
|
||||
fn abs(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.abs(),
|
||||
// Self::Vector(vector) => vector.abs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn inverse(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.inverse(),
|
||||
// Self::Vector(vector) => vector.inverse(),
|
||||
fn inverse(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.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(),
|
||||
fn modulo(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.modulo(arg),
|
||||
// Self::Vector(vector) => vector.modulo(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sin(angle_mode),
|
||||
// Self::Vector(vector) => vector.sin(),
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sin(angle_mode),
|
||||
// Self::Vector(vector) => vector.sin(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.cos(angle_mode),
|
||||
// Self::Vector(vector) => vector.cos(),
|
||||
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.cos(angle_mode),
|
||||
// Self::Vector(vector) => vector.cos(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.tan(angle_mode),
|
||||
// Self::Vector(vector) => vector.tan(),
|
||||
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.tan(angle_mode),
|
||||
// Self::Vector(vector) => vector.tan(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.asin(angle_mode),
|
||||
// Self::Vector(vector) => vector.asin(),
|
||||
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.asin(angle_mode),
|
||||
// Self::Vector(vector) => vector.asin(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.acos(angle_mode),
|
||||
// Self::Vector(vector) => vector.acos(),
|
||||
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.acos(angle_mode),
|
||||
// Self::Vector(vector) => vector.acos(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.atan(angle_mode),
|
||||
// Self::Vector(vector) => vector.atan(),
|
||||
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.atan(angle_mode),
|
||||
// Self::Vector(vector) => vector.atan(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn sqrt(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sqrt(),
|
||||
// Self::Vector(vector) => vector.sqrt(),
|
||||
fn sqrt(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.sqrt(),
|
||||
// Self::Vector(vector) => vector.sqrt(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn log(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.log(),
|
||||
// Self::Vector(vector) => vector.log(),
|
||||
fn log(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.log(),
|
||||
// Self::Vector(vector) => vector.log(),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn ln(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.ln(),
|
||||
// Self::Vector(vector) => vector.ln(),
|
||||
fn ln(&self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.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(),
|
||||
fn pow(&self, arg: Self) -> CalculatorResult<Self> {
|
||||
match self {
|
||||
Self::Number(number) => number.pow(arg),
|
||||
// Self::Vector(vector) => vector.pow(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CalculatorEntry for Number {
|
||||
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 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 add(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value + self.value,
|
||||
})),
|
||||
fn is_valid(&self) -> bool {
|
||||
!self.value.is_nan() && !self.value.is_infinite()
|
||||
}
|
||||
}
|
||||
fn sub(&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> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value + self.value,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value * self.value,
|
||||
})),
|
||||
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value - self.value,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value / self.value,
|
||||
})),
|
||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value * self.value,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value.div_euclid(self.value),
|
||||
})),
|
||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value / self.value,
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn negate(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Number { value: -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 int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
|
||||
match arg {
|
||||
Entry::Number(Number { value }) => Ok(Entry::Number(Number {
|
||||
value: value.div_euclid(self.value),
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Number {
|
||||
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(Number {
|
||||
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(Number {
|
||||
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(Number {
|
||||
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(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 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),
|
||||
})),
|
||||
fn negate(&self) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Number { value: -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 sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
|
||||
Ok(Entry::Number(Number {
|
||||
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(Number {
|
||||
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(Number {
|
||||
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(Number {
|
||||
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(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 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 {
|
||||
// Misc
|
||||
fn is_valid(&self) -> bool;
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
||||
// Mathematical operations
|
||||
fn add(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn sub(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn negate(&self) -> CalculatorResult<Entry>;
|
||||
fn abs(&self) -> CalculatorResult<Entry>;
|
||||
fn inverse(&self) -> CalculatorResult<Entry>;
|
||||
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
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>;
|
||||
// Misc
|
||||
fn is_valid(&self) -> bool;
|
||||
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
|
||||
// Mathematical operations
|
||||
fn add(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn sub(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn mul(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn div(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
fn negate(&self) -> CalculatorResult<Entry>;
|
||||
fn abs(&self) -> CalculatorResult<Entry>;
|
||||
fn inverse(&self) -> CalculatorResult<Entry>;
|
||||
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry>;
|
||||
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>;
|
||||
}
|
||||
|
||||
impl fmt::Display for Entry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Number(Number { value }) => write!(f, "{}", value),
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Number(Number { value }) => write!(f, "{}", value),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on https://stackoverflow.com/a/65266882
|
||||
fn scientific(f: f64, precision: usize) -> String {
|
||||
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
||||
let exp = ret.split_off(ret.find('E').unwrap_or(0));
|
||||
let (exp_sign, exp) = exp
|
||||
.strip_prefix("E-")
|
||||
.map_or_else(|| ('+', &exp[1..]), |stripped| ('-', stripped));
|
||||
let mut ret = format!("{:.precision$E}", f, precision = precision);
|
||||
let exp = ret.split_off(ret.find('E').unwrap_or(0));
|
||||
let (exp_sign, exp) = exp
|
||||
.strip_prefix("E-")
|
||||
.map_or_else(|| ('+', &exp[1..]), |stripped| ('-', stripped));
|
||||
|
||||
let sign = if ret.starts_with('-') { "" } else { " " };
|
||||
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
|
||||
let sign = if ret.starts_with('-') { "" } else { " " };
|
||||
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
|
||||
}
|
||||
|
||||
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
|
||||
// 1,000 => 1000E3
|
||||
let all = format!(" {:.precision$E}", f, precision = precision)
|
||||
// Remove . since it can be moved
|
||||
.replacen(".", "", 1)
|
||||
// Add 00E before E here so the length is enough for slicing below
|
||||
.replacen("E", "00E", 1);
|
||||
// Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E
|
||||
// 1000E3 => (1000, E3)
|
||||
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
|
||||
// E3 => 3 as isize
|
||||
let exp = exp_str[1..].parse::<isize>().unwrap();
|
||||
// Sign of the exponent. If string representation starts with E-, then negative
|
||||
let display_exp_sign = if exp_str.strip_prefix("E-").is_some() {
|
||||
'-'
|
||||
} else {
|
||||
'+'
|
||||
};
|
||||
// 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
|
||||
let all = format!(" {:.precision$E}", f, precision = precision)
|
||||
// Remove . since it can be moved
|
||||
.replacen(".", "", 1)
|
||||
// Add 00E before E here so the length is enough for slicing below
|
||||
.replacen("E", "00E", 1);
|
||||
// Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E
|
||||
// 1000E3 => (1000, E3)
|
||||
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
|
||||
// E3 => 3 as isize
|
||||
let exp = exp_str[1..].parse::<isize>().unwrap();
|
||||
// Sign of the exponent. If string representation starts with E-, then negative
|
||||
let display_exp_sign = if exp_str.strip_prefix("E-").is_some() {
|
||||
'-'
|
||||
} else {
|
||||
'+'
|
||||
};
|
||||
|
||||
// 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)
|
||||
let display_exp = (exp.div_euclid(3) * 3).abs();
|
||||
// Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility
|
||||
let num_whole_digits = exp.rem_euclid(3) as usize + 1;
|
||||
// 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)
|
||||
let display_exp = (exp.div_euclid(3) * 3).abs();
|
||||
// Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility
|
||||
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)
|
||||
let num_str = if num_str.strip_prefix(" -").is_some() {
|
||||
&num_str[1..]
|
||||
} else {
|
||||
num_str
|
||||
};
|
||||
// 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() {
|
||||
&num_str[1..]
|
||||
} else {
|
||||
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)
|
||||
// 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];
|
||||
// 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)];
|
||||
// Right align whole portion, always have decimal point
|
||||
format!(
|
||||
"{: >4}.{} E{}{:0>pad$}",
|
||||
// display_sign,
|
||||
whole,
|
||||
decimal,
|
||||
display_exp_sign,
|
||||
display_exp,
|
||||
pad = 2
|
||||
)
|
||||
// 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
|
||||
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
|
||||
let decimal = &num_str[(num_whole_digits + 1)..=(precision + num_whole_digits)];
|
||||
// Right align whole portion, always have decimal point
|
||||
format!(
|
||||
"{: >4}.{} E{}{:0>pad$}",
|
||||
// display_sign,
|
||||
whole,
|
||||
decimal,
|
||||
display_exp_sign,
|
||||
display_exp,
|
||||
pad = 2
|
||||
)
|
||||
}
|
||||
|
||||
fn separated(f: f64, sep: char) -> String {
|
||||
let mut ret = f.to_string();
|
||||
let start = if ret.starts_with('-') { 1 } else { 0 };
|
||||
let end = ret.find('.').unwrap_or_else(|| ret.len());
|
||||
for i in 0..((end - start - 1).div_euclid(3)) {
|
||||
ret.insert(end - (i + 1) * 3, sep);
|
||||
}
|
||||
ret
|
||||
let mut ret = f.to_string();
|
||||
let start = if ret.starts_with('-') { 1 } else { 0 };
|
||||
let end = ret.find('.').unwrap_or_else(|| ret.len());
|
||||
for i in 0..((end - start - 1).div_euclid(3)) {
|
||||
ret.insert(end - (i + 1) * 3, sep);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user