Skip to content

Commit

Permalink
Add engineering mode
Browse files Browse the repository at this point in the history
  • Loading branch information
PaddiM8 committed Mar 23, 2024
1 parent 22ccb03 commit 90b6bed
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 32 deletions.
14 changes: 13 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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'.")
Expand Down Expand Up @@ -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);
}
Expand All @@ -72,14 +83,15 @@ 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(
&mut parser_context,
&context.args.join(" "),
precision,
10u8,
format,
);
}
}
Expand Down
6 changes: 3 additions & 3 deletions cli/src/output.rs
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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;
}
Expand Down
9 changes: 5 additions & 4 deletions cli/src/repl.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {},
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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),
}
}

Expand Down
17 changes: 11 additions & 6 deletions kalk/src/calculation_result.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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),
)
};

Expand All @@ -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()
Expand Down
91 changes: 73 additions & 18 deletions kalk/src/kalk_value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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 { "" }
)
}
}
Expand Down Expand Up @@ -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(),
Expand All @@ -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
{
Expand All @@ -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();
};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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"));
Expand Down Expand Up @@ -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);
}
}
}

0 comments on commit 90b6bed

Please sign in to comment.