Continue work on separating complex types

This commit is contained in:
Austen Adler 2021-05-30 23:02:32 -04:00
parent c47287b4e6
commit dab0333b31

View File

@ -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
}