mirror of
https://github.com/PaddiM8/kalker.git
synced 2024-12-04 21:51:20 +01:00
Add engineering mode
This commit is contained in:
parent
22ccb03ec9
commit
90b6bed227
@ -1,6 +1,7 @@
|
|||||||
mod output;
|
mod output;
|
||||||
mod repl;
|
mod repl;
|
||||||
|
|
||||||
|
use kalk::kalk_value::ScientificNotationFormat;
|
||||||
use kalk::parser;
|
use kalk::parser;
|
||||||
use seahorse::{App, Context, Flag, FlagType};
|
use seahorse::{App, Context, Flag, FlagType};
|
||||||
use std::env;
|
use std::env;
|
||||||
@ -24,6 +25,10 @@ fn main() {
|
|||||||
.description("Specify number precision")
|
.description("Specify number precision")
|
||||||
.alias("p"),
|
.alias("p"),
|
||||||
)
|
)
|
||||||
|
.flag(
|
||||||
|
Flag::new("eng", FlagType::Bool)
|
||||||
|
.description("Engineering mode")
|
||||||
|
)
|
||||||
.flag(
|
.flag(
|
||||||
Flag::new("angle-unit", FlagType::String)
|
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'.")
|
.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
|
let precision = context
|
||||||
.int_flag("precision")
|
.int_flag("precision")
|
||||||
.unwrap_or(output::DEFAULT_PRECISION as isize) as u32;
|
.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") {
|
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);
|
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() {
|
if context.args.is_empty() {
|
||||||
// REPL
|
// REPL
|
||||||
repl::start(&mut parser_context, precision);
|
repl::start(&mut parser_context, precision, format);
|
||||||
} else {
|
} else {
|
||||||
// Direct output
|
// Direct output
|
||||||
output::eval(
|
output::eval(
|
||||||
@ -80,6 +91,7 @@ fn default_action(context: &Context) {
|
|||||||
&context.args.join(" "),
|
&context.args.join(" "),
|
||||||
precision,
|
precision,
|
||||||
10u8,
|
10u8,
|
||||||
|
format,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use ansi_term::Colour::Red;
|
use ansi_term::Colour::Red;
|
||||||
use kalk::parser;
|
use kalk::{kalk_value::ScientificNotationFormat, parser};
|
||||||
|
|
||||||
pub(crate) const DEFAULT_PRECISION: u32 = 63;
|
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) {
|
match parser::eval(parser, input, precision) {
|
||||||
Ok(Some(mut result)) => {
|
Ok(Some(mut result)) => {
|
||||||
if !result.set_radix(base) {
|
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 {
|
if precision == DEFAULT_PRECISION {
|
||||||
println!("{}", result.to_string_pretty());
|
println!("{}", result.to_string_pretty_format(format));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::output;
|
use crate::output;
|
||||||
use ansi_term::Colour::{self, Cyan};
|
use ansi_term::Colour::{self, Cyan};
|
||||||
|
use kalk::kalk_value::ScientificNotationFormat;
|
||||||
use kalk::parser;
|
use kalk::parser;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Captures;
|
use regex::Captures;
|
||||||
@ -24,7 +25,7 @@ struct Context {
|
|||||||
base: u8,
|
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();
|
let mut editor = Editor::<RLHelper>::new();
|
||||||
editor.set_helper(Some(RLHelper {
|
editor.set_helper(Some(RLHelper {
|
||||||
highlighter: LineHighlighter {},
|
highlighter: LineHighlighter {},
|
||||||
@ -66,7 +67,7 @@ pub fn start(parser: &mut parser::Context, precision: u32) {
|
|||||||
match readline {
|
match readline {
|
||||||
Ok(input) => {
|
Ok(input) => {
|
||||||
editor.add_history_entry(input.as_str());
|
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,
|
Err(ReadlineError::Interrupted) => break,
|
||||||
_ => 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_name) = input.strip_prefix("load ") {
|
||||||
if let Some(file_path) = crate::get_input_file_by_name(file_name) {
|
if let Some(file_path) = crate::get_input_file_by_name(file_name) {
|
||||||
crate::load_input_file(&file_path, precision, parser);
|
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"),
|
"clear" => print!("\x1B[2J"),
|
||||||
"exit" => process::exit(0),
|
"exit" => process::exit(0),
|
||||||
"help" => print_cli_help(),
|
"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 wasm_bindgen::prelude::wasm_bindgen;
|
||||||
|
|
||||||
use crate::kalk_value::{ComplexNumberType, KalkValue, ScientificNotation};
|
use crate::kalk_value::{ComplexNumberType, KalkValue, ScientificNotation, ScientificNotationFormat};
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct CalculationResult {
|
pub struct CalculationResult {
|
||||||
@ -36,15 +36,15 @@ impl CalculationResult {
|
|||||||
self.value.to_string_big()
|
self.value.to_string_big()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = toPrettyString)]
|
#[wasm_bindgen(js_name = toPrettyStringWithFormat)]
|
||||||
pub fn to_string_pretty(&self) -> String {
|
pub fn to_string_pretty_format(&self, format: ScientificNotationFormat) -> String {
|
||||||
let value = if self.radix == 10 {
|
let value = if self.radix == 10 {
|
||||||
self.value.to_string_pretty_radix(10)
|
self.value.to_string_pretty_radix(10, format)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{}\n{}",
|
"{}\n{}",
|
||||||
self.value.to_string_pretty_radix(10),
|
self.value.to_string_pretty_radix(10, format),
|
||||||
self.value.to_string_pretty_radix(self.radix),
|
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)]
|
#[wasm_bindgen(js_name = getValue)]
|
||||||
pub fn to_f64(&self) -> f64 {
|
pub fn to_f64(&self) -> f64 {
|
||||||
self.value.to_f64()
|
self.value.to_f64()
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
pub mod with_rug;
|
pub mod with_rug;
|
||||||
|
|
||||||
#[cfg(feature = "rug")]
|
#[cfg(feature = "rug")]
|
||||||
use rug::Float;
|
use rug::{Float, ops::Pow};
|
||||||
#[cfg(feature = "rug")]
|
#[cfg(feature = "rug")]
|
||||||
pub use with_rug::*;
|
pub use with_rug::*;
|
||||||
|
|
||||||
@ -108,7 +108,6 @@ macro_rules! as_number_or_zero {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ScientificNotation {
|
pub struct ScientificNotation {
|
||||||
pub negative: bool,
|
|
||||||
pub value: f64,
|
pub value: f64,
|
||||||
pub exponent: i32,
|
pub exponent: i32,
|
||||||
pub imaginary: bool,
|
pub imaginary: bool,
|
||||||
@ -121,17 +120,42 @@ pub enum ComplexNumberType {
|
|||||||
Imaginary,
|
Imaginary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ScientificNotationFormat {
|
||||||
|
Normal,
|
||||||
|
Engineering,
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl ScientificNotation {
|
impl ScientificNotation {
|
||||||
#[wasm_bindgen(js_name = toString)]
|
#[wasm_bindgen(js_name = toString)]
|
||||||
pub fn to_js_string(&self) -> String {
|
pub fn to_js_string(&self) -> String {
|
||||||
self.to_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 {
|
impl std::fmt::Display for ScientificNotation {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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 {
|
let digits_and_mul = if self.value == 1f64 {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
@ -140,11 +164,10 @@ impl std::fmt::Display for ScientificNotation {
|
|||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}10^{} {}",
|
"{}10^{}{}",
|
||||||
sign,
|
|
||||||
digits_and_mul,
|
digits_and_mul,
|
||||||
self.exponent - 1,
|
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 {
|
let (real, imaginary, unit) = match self {
|
||||||
KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
|
KalkValue::Number(real, imaginary, unit) => (real, imaginary, unit),
|
||||||
_ => return self.to_string(),
|
_ => return self.to_string(),
|
||||||
@ -308,21 +331,31 @@ impl KalkValue {
|
|||||||
let mut new_real = real.clone();
|
let mut new_real = real.clone();
|
||||||
let mut new_imaginary = imaginary.clone();
|
let mut new_imaginary = imaginary.clone();
|
||||||
let mut has_scientific_notation = false;
|
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)
|
self.to_string_real(radix)
|
||||||
} else if sci_notation_real.exponent <= -14 {
|
} else if sci_notation_real.exponent <= -14 {
|
||||||
new_real = float!(0);
|
new_real = float!(0);
|
||||||
|
|
||||||
String::from("0")
|
String::from("0")
|
||||||
} else if radix == 10 {
|
} else if radix == 10 {
|
||||||
has_scientific_notation = true;
|
has_scientific_notation = true;
|
||||||
|
|
||||||
sci_notation_real.to_string().trim().to_string()
|
sci_notation_real.to_string_format(format)
|
||||||
} else {
|
} else {
|
||||||
return String::new();
|
return String::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
let sci_notation_imaginary = self.to_scientific_notation(ComplexNumberType::Imaginary);
|
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 == &0f64
|
||||||
|| imaginary == &1f64
|
|| imaginary == &1f64
|
||||||
{
|
{
|
||||||
@ -333,7 +366,7 @@ impl KalkValue {
|
|||||||
} else if radix == 10 {
|
} else if radix == 10 {
|
||||||
has_scientific_notation = true;
|
has_scientific_notation = true;
|
||||||
|
|
||||||
sci_notation_imaginary.to_string().trim().to_string()
|
sci_notation_imaginary.to_string_format(format)
|
||||||
} else {
|
} else {
|
||||||
return String::new();
|
return String::new();
|
||||||
};
|
};
|
||||||
@ -368,15 +401,15 @@ impl KalkValue {
|
|||||||
if estimate != output && radix == 10 {
|
if estimate != output && radix == 10 {
|
||||||
output.push_str(&format!(" ≈ {}", estimate));
|
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.insert_str(0, &format!("{} ≈ ", self));
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_pretty(&self) -> String {
|
pub fn to_string_pretty(&self, format: ScientificNotationFormat) -> String {
|
||||||
self.to_string_pretty_radix(10)
|
self.to_string_pretty_radix(10, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_with_unit(&self) -> String {
|
pub fn to_string_with_unit(&self) -> String {
|
||||||
@ -516,7 +549,6 @@ impl KalkValue {
|
|||||||
let exponent = value.abs().log10().floor() as i32 + 1;
|
let exponent = value.abs().log10().floor() as i32 + 1;
|
||||||
|
|
||||||
ScientificNotation {
|
ScientificNotation {
|
||||||
negative: value < 0f64,
|
|
||||||
value: value / (10f64.powf(exponent as f64 - 1f64) as f64),
|
value: value / (10f64.powf(exponent as f64 - 1f64) as f64),
|
||||||
// I... am not sure what else to do...
|
// I... am not sure what else to do...
|
||||||
exponent,
|
exponent,
|
||||||
@ -1309,7 +1341,6 @@ fn pow(x: f64, y: f64) -> f64 {
|
|||||||
|
|
||||||
#[cfg(feature = "rug")]
|
#[cfg(feature = "rug")]
|
||||||
fn pow(x: Float, y: Float) -> Float {
|
fn pow(x: Float, y: Float) -> Float {
|
||||||
use rug::ops::Pow;
|
|
||||||
x.pow(y)
|
x.pow(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1377,9 +1408,11 @@ impl From<i32> for KalkValue {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::kalk_value::{spaced, KalkValue};
|
use crate::kalk_value::{spaced, KalkValue, ScientificNotationFormat};
|
||||||
use crate::test_helpers::cmp;
|
use crate::test_helpers::cmp;
|
||||||
|
|
||||||
|
use super::ScientificNotation;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_spaced() {
|
fn test_spaced() {
|
||||||
assert_eq!(spaced("1"), String::from("1"));
|
assert_eq!(spaced("1"), String::from("1"));
|
||||||
@ -1543,8 +1576,30 @@ mod tests {
|
|||||||
(float!(3.00000000004), float!(0.0), "3"),
|
(float!(3.00000000004), float!(0.0), "3"),
|
||||||
];
|
];
|
||||||
for (real, imaginary, output) in in_out {
|
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);
|
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