mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-11-07 08:24:33 +01:00
Add engineering mode
This commit is contained in:
parent
22ccb03ec9
commit
90b6bed227
@ -1,6 +1,7 @@
|
||||
mod output;
|
||||
mod repl;
|
||||
|
||||
use kalk::kalk_value::ScientificNotationFormat;
|
||||
use kalk::parser;
|
||||
use seahorse::{App, Context, Flag, FlagType};
|
||||
use std::env;
|
||||
@ -24,6 +25,10 @@ fn main() {
|
||||
.description("Specify number precision")
|
||||
.alias("p"),
|
||||
)
|
||||
.flag(
|
||||
Flag::new("eng", FlagType::Bool)
|
||||
.description("Engineering mode")
|
||||
)
|
||||
.flag(
|
||||
Flag::new("angle-unit", FlagType::String)
|
||||
.description("Unit used for angles, either rad or deg. This can also be specified using an environment variable with the name 'ANGLE_UNIT'.")
|
||||
@ -58,6 +63,12 @@ fn default_action(context: &Context) {
|
||||
let precision = context
|
||||
.int_flag("precision")
|
||||
.unwrap_or(output::DEFAULT_PRECISION as isize) as u32;
|
||||
let format = if context.bool_flag("eng") {
|
||||
ScientificNotationFormat::Engineering
|
||||
} else {
|
||||
ScientificNotationFormat::Normal
|
||||
};
|
||||
|
||||
if let Ok(max_recursion_depth) = context.int_flag("max-recursion-depth") {
|
||||
parser_context = parser_context.set_max_recursion_depth(max_recursion_depth as u32);
|
||||
}
|
||||
@ -72,7 +83,7 @@ fn default_action(context: &Context) {
|
||||
|
||||
if context.args.is_empty() {
|
||||
// REPL
|
||||
repl::start(&mut parser_context, precision);
|
||||
repl::start(&mut parser_context, precision, format);
|
||||
} else {
|
||||
// Direct output
|
||||
output::eval(
|
||||
@ -80,6 +91,7 @@ fn default_action(context: &Context) {
|
||||
&context.args.join(" "),
|
||||
precision,
|
||||
10u8,
|
||||
format,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use ansi_term::Colour::Red;
|
||||
use kalk::parser;
|
||||
use kalk::{kalk_value::ScientificNotationFormat, parser};
|
||||
|
||||
pub(crate) const DEFAULT_PRECISION: u32 = 63;
|
||||
|
||||
pub fn eval(parser: &mut parser::Context, input: &str, precision: u32, base: u8) {
|
||||
pub fn eval(parser: &mut parser::Context, input: &str, precision: u32, base: u8, format: ScientificNotationFormat) {
|
||||
match parser::eval(parser, input, precision) {
|
||||
Ok(Some(mut result)) => {
|
||||
if !result.set_radix(base) {
|
||||
@ -13,7 +13,7 @@ pub fn eval(parser: &mut parser::Context, input: &str, precision: u32, base: u8)
|
||||
}
|
||||
|
||||
if precision == DEFAULT_PRECISION {
|
||||
println!("{}", result.to_string_pretty());
|
||||
println!("{}", result.to_string_pretty_format(format));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::output;
|
||||
use ansi_term::Colour::{self, Cyan};
|
||||
use kalk::kalk_value::ScientificNotationFormat;
|
||||
use kalk::parser;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Captures;
|
||||
@ -24,7 +25,7 @@ struct Context {
|
||||
base: u8,
|
||||
}
|
||||
|
||||
pub fn start(parser: &mut parser::Context, precision: u32) {
|
||||
pub fn start(parser: &mut parser::Context, precision: u32, format: ScientificNotationFormat) {
|
||||
let mut editor = Editor::<RLHelper>::new();
|
||||
editor.set_helper(Some(RLHelper {
|
||||
highlighter: LineHighlighter {},
|
||||
@ -66,7 +67,7 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
|
||||
match readline {
|
||||
Ok(input) => {
|
||||
editor.add_history_entry(input.as_str());
|
||||
eval_repl(&mut repl, parser, &input, precision);
|
||||
eval_repl(&mut repl, parser, &input, precision, format);
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => break,
|
||||
_ => break,
|
||||
@ -78,7 +79,7 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_repl(repl: &mut self::Context, parser: &mut parser::Context, input: &str, precision: u32) {
|
||||
fn eval_repl(repl: &mut self::Context, parser: &mut parser::Context, input: &str, precision: u32, format: ScientificNotationFormat) {
|
||||
if let Some(file_name) = input.strip_prefix("load ") {
|
||||
if let Some(file_path) = crate::get_input_file_by_name(file_name) {
|
||||
crate::load_input_file(&file_path, precision, parser);
|
||||
@ -109,7 +110,7 @@ fn eval_repl(repl: &mut self::Context, parser: &mut parser::Context, input: &str
|
||||
"clear" => print!("\x1B[2J"),
|
||||
"exit" => process::exit(0),
|
||||
"help" => print_cli_help(),
|
||||
_ => output::eval(parser, input, precision, repl.base),
|
||||
_ => output::eval(parser, input, precision, repl.base, format),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use crate::kalk_value::{ComplexNumberType, KalkValue, ScientificNotation};
|
||||
use crate::kalk_value::{ComplexNumberType, KalkValue, ScientificNotation, ScientificNotationFormat};
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct CalculationResult {
|
||||
@ -36,15 +36,15 @@ impl CalculationResult {
|
||||
self.value.to_string_big()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = toPrettyString)]
|
||||
pub fn to_string_pretty(&self) -> String {
|
||||
#[wasm_bindgen(js_name = toPrettyStringWithFormat)]
|
||||
pub fn to_string_pretty_format(&self, format: ScientificNotationFormat) -> String {
|
||||
let value = if self.radix == 10 {
|
||||
self.value.to_string_pretty_radix(10)
|
||||
self.value.to_string_pretty_radix(10, format)
|
||||
} else {
|
||||
format!(
|
||||
"{}\n{}",
|
||||
self.value.to_string_pretty_radix(10),
|
||||
self.value.to_string_pretty_radix(self.radix),
|
||||
self.value.to_string_pretty_radix(10, format),
|
||||
self.value.to_string_pretty_radix(self.radix, format),
|
||||
)
|
||||
};
|
||||
|
||||
@ -55,6 +55,11 @@ impl CalculationResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = toPrettyString)]
|
||||
pub fn to_string_pretty(&self) -> String {
|
||||
self.to_string_pretty_format(ScientificNotationFormat::Normal)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = getValue)]
|
||||
pub fn to_f64(&self) -> f64 {
|
||||
self.value.to_f64()
|
||||
|
@ -2,7 +2,7 @@
|
||||
pub mod with_rug;
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
use rug::Float;
|
||||
use rug::{Float, ops::Pow};
|
||||
#[cfg(feature = "rug")]
|
||||
pub use with_rug::*;
|
||||
|
||||
@ -108,7 +108,6 @@ macro_rules! as_number_or_zero {
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone)]
|
||||
pub struct ScientificNotation {
|
||||
pub negative: bool,
|
||||
pub value: f64,
|
||||
pub exponent: i32,
|
||||
pub imaginary: bool,
|
||||
@ -121,17 +120,42 @@ pub enum ComplexNumberType {
|
||||
Imaginary,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ScientificNotationFormat {
|
||||
Normal,
|
||||
Engineering,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl ScientificNotation {
|
||||
#[wasm_bindgen(js_name = toString)]
|
||||
pub fn to_js_string(&self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
|
||||
pub fn to_string_format(&self, format: ScientificNotationFormat) -> String {
|
||||
match format {
|
||||
ScientificNotationFormat::Normal => self.to_string(),
|
||||
ScientificNotationFormat::Engineering => self.to_string_eng(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_string_eng(&self) -> String {
|
||||
let exponent = self.exponent - 1;
|
||||
let modulo = exponent % 3;
|
||||
let value = self.value * 10_f64.powi(modulo);
|
||||
|
||||
ScientificNotation {
|
||||
value,
|
||||
exponent: exponent - modulo + 1,
|
||||
imaginary: self.imaginary,
|
||||
}.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ScientificNotation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let sign = if self.negative { "-" } else { "" };
|
||||
let digits_and_mul = if self.value == 1f64 {
|
||||
String::new()
|
||||
} else {
|
||||
@ -140,11 +164,10 @@ impl std::fmt::Display for ScientificNotation {
|
||||
|
||||
write!(
|
||||
f,
|
||||
"{}{}10^{} {}",
|
||||
sign,
|
||||
"{}10^{}{}",
|
||||
digits_and_mul,
|
||||
self.exponent - 1,
|
||||
if self.imaginary { "i" } else { "" }
|
||||
if self.imaginary { " i" } else { "" }
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -288,7 +311,7 @@ impl KalkValue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_pretty_radix(&self, radix: u8) -> String {
|
||||
pub fn to_string_pretty_radix(&self, radix: u8, format: ScientificNotationFormat) -> String {
|
||||
let (real, imaginary, unit) = match self {
|
||||
KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
|
||||
_ => return self.to_string(),
|
||||
@ -308,21 +331,31 @@ impl KalkValue {
|
||||
let mut new_real = real.clone();
|
||||
let mut new_imaginary = imaginary.clone();
|
||||
let mut has_scientific_notation = false;
|
||||
let result_str = if (-6..8).contains(&sci_notation_real.exponent) || real == &0f64 {
|
||||
let is_engineering_mode = matches!(format, ScientificNotationFormat::Engineering);
|
||||
let result_str = if is_engineering_mode {
|
||||
has_scientific_notation = true;
|
||||
|
||||
sci_notation_real.to_string_format(ScientificNotationFormat::Engineering)
|
||||
} else if (-6..8).contains(&sci_notation_real.exponent) || real == &0f64 {
|
||||
self.to_string_real(radix)
|
||||
} else if sci_notation_real.exponent <= -14 {
|
||||
new_real = float!(0);
|
||||
|
||||
String::from("0")
|
||||
} else if radix == 10 {
|
||||
has_scientific_notation = true;
|
||||
|
||||
sci_notation_real.to_string().trim().to_string()
|
||||
sci_notation_real.to_string_format(format)
|
||||
} else {
|
||||
return String::new();
|
||||
};
|
||||
|
||||
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
|
||||
let result_str_imaginary = if (-6..8).contains(&sci_notation_imaginary.exponent)
|
||||
let result_str_imaginary = if is_engineering_mode {
|
||||
has_scientific_notation = true;
|
||||
|
||||
sci_notation_imaginary.to_string_format(ScientificNotationFormat::Engineering)
|
||||
} else if (-6..8).contains(&sci_notation_imaginary.exponent)
|
||||
|| imaginary == &0f64
|
||||
|| imaginary == &1f64
|
||||
{
|
||||
@ -333,7 +366,7 @@ impl KalkValue {
|
||||
} else if radix == 10 {
|
||||
has_scientific_notation = true;
|
||||
|
||||
sci_notation_imaginary.to_string().trim().to_string()
|
||||
sci_notation_imaginary.to_string_format(format)
|
||||
} else {
|
||||
return String::new();
|
||||
};
|
||||
@ -368,15 +401,15 @@ impl KalkValue {
|
||||
if estimate != output && radix == 10 {
|
||||
output.push_str(&format!(" ≈ {}", estimate));
|
||||
}
|
||||
} else if has_scientific_notation {
|
||||
} else if has_scientific_notation && !is_engineering_mode {
|
||||
output.insert_str(0, &format!("{} ≈ ", self));
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
pub fn to_string_pretty(&self) -> String {
|
||||
self.to_string_pretty_radix(10)
|
||||
pub fn to_string_pretty(&self, format: ScientificNotationFormat) -> String {
|
||||
self.to_string_pretty_radix(10, format)
|
||||
}
|
||||
|
||||
pub fn to_string_with_unit(&self) -> String {
|
||||
@ -516,7 +549,6 @@ impl KalkValue {
|
||||
let exponent = value.abs().log10().floor() as i32 + 1;
|
||||
|
||||
ScientificNotation {
|
||||
negative: value < 0f64,
|
||||
value: value / (10f64.powf(exponent as f64 - 1f64) as f64),
|
||||
// I... am not sure what else to do...
|
||||
exponent,
|
||||
@ -1309,7 +1341,6 @@ fn pow(x: f64, y: f64) -> f64 {
|
||||
|
||||
#[cfg(feature = "rug")]
|
||||
fn pow(x: Float, y: Float) -> Float {
|
||||
use rug::ops::Pow;
|
||||
x.pow(y)
|
||||
}
|
||||
|
||||
@ -1377,9 +1408,11 @@ impl From<i32> for KalkValue {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::kalk_value::{spaced, KalkValue};
|
||||
use crate::kalk_value::{spaced, KalkValue, ScientificNotationFormat};
|
||||
use crate::test_helpers::cmp;
|
||||
|
||||
use super::ScientificNotation;
|
||||
|
||||
#[test]
|
||||
fn test_spaced() {
|
||||
assert_eq!(spaced("1"), String::from("1"));
|
||||
@ -1543,8 +1576,30 @@ mod tests {
|
||||
(float!(3.00000000004), float!(0.0), "3"),
|
||||
];
|
||||
for (real, imaginary, output) in in_out {
|
||||
let result = KalkValue::Number(real, imaginary, None).to_string_pretty();
|
||||
let result = KalkValue::Number(real, imaginary, None).to_string_pretty(ScientificNotationFormat::Normal);
|
||||
assert_eq!(output, result);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eng_mode() {
|
||||
let in_out = vec![
|
||||
(1.23, 0, "1.23×10^0"),
|
||||
(1.23, 1, "12.3×10^0"),
|
||||
(1.23, 2, "123×10^0"),
|
||||
(1.23, 3, "1.23×10^3"),
|
||||
(1.23, 4, "12.3×10^3"),
|
||||
(1.23, 5, "123×10^3"),
|
||||
(1.23, 6, "1.23×10^6"),
|
||||
];
|
||||
for (value, exponent, output) in in_out {
|
||||
let sci = ScientificNotation {
|
||||
value,
|
||||
exponent: exponent + 1,
|
||||
imaginary: false,
|
||||
};
|
||||
|
||||
assert_eq!(sci.to_string_format(ScientificNotationFormat::Engineering), output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user