mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-31 08:59:15 +01:00
Implemented complex variants of prelude functions
This commit is contained in:
parent
1c914bc77f
commit
fa4e853982
@ -177,10 +177,7 @@ fn eval_unary_expr(
|
|||||||
match op {
|
match op {
|
||||||
TokenKind::Minus => Ok(num.mul(context, KalkNum::from(-1f64))),
|
TokenKind::Minus => Ok(num.mul(context, KalkNum::from(-1f64))),
|
||||||
TokenKind::Percent => Ok(num.mul(context, KalkNum::from(0.01f64))),
|
TokenKind::Percent => Ok(num.mul(context, KalkNum::from(0.01f64))),
|
||||||
TokenKind::Exclamation => Ok(KalkNum::new(
|
TokenKind::Exclamation => Ok(prelude::special_funcs::factorial(num)),
|
||||||
prelude::special_funcs::factorial(num.value),
|
|
||||||
unit,
|
|
||||||
)),
|
|
||||||
_ => Err(CalcError::InvalidOperator),
|
_ => Err(CalcError::InvalidOperator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,11 +273,13 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
1 => {
|
1 => {
|
||||||
let x = eval_expr(context, &expressions[0], "")?;
|
let x = eval_expr(context, &expressions[0], "")?;
|
||||||
|
|
||||||
|
// Turn eg. sqrt(-1) into i
|
||||||
if x.value < 0f64 && (identifier.full_name == "sqrt" || identifier.full_name == "√") {
|
if x.value < 0f64 && (identifier.full_name == "sqrt" || identifier.full_name == "√") {
|
||||||
|
let abs_value = x.mul(context, KalkNum::from(-1f64));
|
||||||
let (sqrt, unit) = prelude::call_unary_func(
|
let (sqrt, unit) = prelude::call_unary_func(
|
||||||
context,
|
context,
|
||||||
&identifier.full_name,
|
&identifier.full_name,
|
||||||
x.value * (-1f64),
|
abs_value,
|
||||||
&context.angle_unit.clone(),
|
&context.angle_unit.clone(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -288,7 +287,7 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
return Ok(KalkNum::new_with_imaginary(
|
return Ok(KalkNum::new_with_imaginary(
|
||||||
KalkNum::default().value,
|
KalkNum::default().value,
|
||||||
&unit,
|
&unit,
|
||||||
sqrt,
|
sqrt.value,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,14 +297,14 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
prelude::call_unary_func(
|
prelude::call_unary_func(
|
||||||
context,
|
context,
|
||||||
&identifier.full_name,
|
&identifier.full_name,
|
||||||
x.value,
|
x,
|
||||||
&context.angle_unit.clone(),
|
&context.angle_unit.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
let x = eval_expr(context, &expressions[0], "")?.value;
|
let x = eval_expr(context, &expressions[0], "")?;
|
||||||
let y = eval_expr(context, &expressions[1], "")?.value;
|
let y = eval_expr(context, &expressions[1], "")?;
|
||||||
prelude::call_binary_func(
|
prelude::call_binary_func(
|
||||||
context,
|
context,
|
||||||
&identifier.full_name,
|
&identifier.full_name,
|
||||||
@ -317,11 +316,8 @@ pub(crate) fn eval_fn_call_expr(
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((result, func_unit)) = prelude_func {
|
if let Some((result, _)) = prelude_func {
|
||||||
return Ok(KalkNum::new(
|
return Ok(result);
|
||||||
result,
|
|
||||||
if unit.len() > 0 { unit } else { &func_unit },
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special functions
|
// Special functions
|
||||||
@ -455,7 +451,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cmp(x: KalkNum, y: f64) -> bool {
|
fn cmp(x: KalkNum, y: f64) -> bool {
|
||||||
println!("{} = {}", x.to_f64(), y);
|
|
||||||
(x.to_f64() - y).abs() < 0.0001
|
(x.to_f64() - y).abs() < 0.0001
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ lazy_static! {
|
|||||||
pub static ref INVERSE_UNARY_FUNCS: HashMap<&'static str, &'static str> = {
|
pub static ref INVERSE_UNARY_FUNCS: HashMap<&'static str, &'static str> = {
|
||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
m.insert("cos", "acos");
|
m.insert("cos", "acos");
|
||||||
m.insert("cosec", "acosec");
|
m.insert("csc", "acsc");
|
||||||
m.insert("cosech", "cosech");
|
m.insert("csch", "csch");
|
||||||
m.insert("cosh", "acosh");
|
m.insert("cosh", "acosh");
|
||||||
m.insert("cot", "acot");
|
m.insert("cot", "acot");
|
||||||
m.insert("coth", "acoth");
|
m.insert("coth", "acoth");
|
||||||
@ -24,8 +24,8 @@ lazy_static! {
|
|||||||
m.insert("tanh", "atanh");
|
m.insert("tanh", "atanh");
|
||||||
|
|
||||||
m.insert("acos", "cos");
|
m.insert("acos", "cos");
|
||||||
m.insert("acosec", "cosec");
|
m.insert("acsc", "csc");
|
||||||
m.insert("acosech", "cosech");
|
m.insert("acsch", "csch");
|
||||||
m.insert("acosh", "cosh");
|
m.insert("acosh", "cosh");
|
||||||
m.insert("acot", "cot");
|
m.insert("acot", "cot");
|
||||||
m.insert("acoth", "coth");
|
m.insert("acoth", "coth");
|
||||||
|
@ -92,6 +92,10 @@ impl ScientificNotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KalkNum {
|
impl KalkNum {
|
||||||
|
pub fn has_imaginary(&self) -> bool {
|
||||||
|
self.imaginary_value != 0f64
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_scientific_notation(
|
pub fn to_scientific_notation(
|
||||||
&self,
|
&self,
|
||||||
complex_number_type: ComplexNumberType,
|
complex_number_type: ComplexNumberType,
|
||||||
@ -128,7 +132,7 @@ impl KalkNum {
|
|||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
let as_str = trim_number_string(&self.to_f64().to_string());
|
let as_str = trim_number_string(&self.to_f64().to_string());
|
||||||
|
|
||||||
if self.imaginary_value != 0f64 {
|
if self.has_imaginary() {
|
||||||
let imaginary_as_str = trim_number_string(&self.imaginary_to_f64().to_string());
|
let imaginary_as_str = trim_number_string(&self.imaginary_to_f64().to_string());
|
||||||
let sign = if self.imaginary_value < 0f64 {
|
let sign = if self.imaginary_value < 0f64 {
|
||||||
"-"
|
"-"
|
||||||
@ -143,7 +147,7 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string_big(&self) -> String {
|
pub fn to_string_big(&self) -> String {
|
||||||
if self.imaginary_value == 0f64 {
|
if !self.has_imaginary() {
|
||||||
self.value.to_string()
|
self.value.to_string()
|
||||||
} else {
|
} else {
|
||||||
let sign = if self.imaginary_value < 0f64 {
|
let sign = if self.imaginary_value < 0f64 {
|
||||||
@ -196,7 +200,7 @@ impl KalkNum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut output = result_str;
|
let mut output = result_str;
|
||||||
if self.imaginary_value != 0f64 {
|
if self.has_imaginary() {
|
||||||
// If the real value is 0, and there is an imaginary one,
|
// If the real value is 0, and there is an imaginary one,
|
||||||
// clear the output so that the real value is not shown.
|
// clear the output so that the real value is not shown.
|
||||||
if output == "0" {
|
if output == "0" {
|
||||||
@ -264,51 +268,22 @@ impl KalkNum {
|
|||||||
|
|
||||||
pub(crate) fn add(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn add(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
KalkNum::new_with_imaginary(
|
self.add_without_unit(right)
|
||||||
self.value + right.value,
|
|
||||||
&right.unit,
|
|
||||||
self.imaginary_value + right.imaginary_value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn sub(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
KalkNum::new_with_imaginary(
|
self.sub_without_unit(right)
|
||||||
self.value - right.value,
|
|
||||||
&right.unit,
|
|
||||||
self.imaginary_value - right.imaginary_value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mul(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn mul(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
// (a + bi)(c + di) = ac + adi + bci + bdi²
|
self.mul_without_unit(right)
|
||||||
KalkNum::new_with_imaginary(
|
|
||||||
self.value.clone() * right.value.clone()
|
|
||||||
- self.imaginary_value.clone() * right.imaginary_value.clone(),
|
|
||||||
&right.unit,
|
|
||||||
self.value * right.imaginary_value + self.imaginary_value * right.value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn div(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn div(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs.clone());
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs.clone());
|
||||||
|
self.div_without_unit(right)
|
||||||
// Avoid unecessary calculations
|
|
||||||
if self.imaginary_value == 0f64 && right.imaginary_value == 0f64 {
|
|
||||||
KalkNum::new(self.value / right.value, &right.unit)
|
|
||||||
} else {
|
|
||||||
// Multiply both the numerator and denominator
|
|
||||||
// with the conjugate of the denominator, and divide.
|
|
||||||
let conjugate = rhs.get_conjugate();
|
|
||||||
let numerator = self.clone().mul(context, conjugate.clone());
|
|
||||||
let denominator = rhs.clone().mul(context, conjugate);
|
|
||||||
KalkNum::new_with_imaginary(
|
|
||||||
numerator.value / denominator.value.clone(),
|
|
||||||
&right.unit,
|
|
||||||
numerator.imaginary_value / denominator.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rem(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn rem(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
@ -316,6 +291,50 @@ impl KalkNum {
|
|||||||
KalkNum::new(self.value % right.value, &right.unit)
|
KalkNum::new(self.value % right.value, &right.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
self.value + rhs.value,
|
||||||
|
&rhs.unit,
|
||||||
|
self.imaginary_value + rhs.imaginary_value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sub_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
self.value - rhs.value,
|
||||||
|
&rhs.unit,
|
||||||
|
self.imaginary_value - rhs.imaginary_value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn mul_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
// (a + bi)(c + di) = ac + adi + bci + bdi²
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
self.value.clone() * rhs.value.clone()
|
||||||
|
- self.imaginary_value.clone() * rhs.imaginary_value.clone(),
|
||||||
|
&rhs.unit,
|
||||||
|
self.value * rhs.imaginary_value + self.imaginary_value * rhs.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn div_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
// Avoid unecessary calculations
|
||||||
|
if self.imaginary_value == 0f64 && rhs.imaginary_value == 0f64 {
|
||||||
|
KalkNum::new(self.value / rhs.value, &rhs.unit)
|
||||||
|
} else {
|
||||||
|
// Multiply both the numerator and denominator
|
||||||
|
// with the conjugate of the denominator, and divide.
|
||||||
|
let conjugate = rhs.get_conjugate();
|
||||||
|
let numerator = self.clone().mul_without_unit(conjugate.clone());
|
||||||
|
let denominator = rhs.clone().mul_without_unit(conjugate);
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
numerator.value / denominator.value.clone(),
|
||||||
|
&rhs.unit,
|
||||||
|
numerator.imaginary_value / denominator.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_conjugate(&self) -> KalkNum {
|
pub fn get_conjugate(&self) -> KalkNum {
|
||||||
KalkNum::new_with_imaginary(
|
KalkNum::new_with_imaginary(
|
||||||
self.value.clone(),
|
self.value.clone(),
|
||||||
|
@ -27,6 +27,14 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_imaginary(value: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
value: 0f64,
|
||||||
|
unit: String::new(),
|
||||||
|
imaginary_value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = getValue)]
|
#[wasm_bindgen(js_name = getValue)]
|
||||||
pub fn to_f64(&self) -> f64 {
|
pub fn to_f64(&self) -> f64 {
|
||||||
self.value
|
self.value
|
||||||
@ -86,7 +94,28 @@ impl KalkNum {
|
|||||||
|
|
||||||
pub(crate) fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
KalkNum::new(self.value.powf(right.value), &right.unit)
|
self.pow_without_unit(right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pow_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
if self.has_imaginary() || rhs.has_imaginary() {
|
||||||
|
let a = self.value.clone();
|
||||||
|
let b = self.imaginary_value.clone();
|
||||||
|
let c = rhs.value;
|
||||||
|
let d = rhs.imaginary_value;
|
||||||
|
let arg = crate::prelude::funcs::arg(self).value;
|
||||||
|
let raised = a.clone() * a + b.clone() * b;
|
||||||
|
let exp = raised.clone().powf(c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
|
||||||
|
let polar = c * arg + d / 2f64 * raised.ln();
|
||||||
|
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
polar.clone().cos() * exp.clone(),
|
||||||
|
&rhs.unit,
|
||||||
|
polar.sin() * exp,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(self.value.powf(rhs.value), &rhs.unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,14 @@ impl KalkNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_imaginary(value: Float) -> Self {
|
||||||
|
Self {
|
||||||
|
value: Float::with_val(63, 0),
|
||||||
|
unit: String::new(),
|
||||||
|
imaginary_value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_f64(&self) -> f64 {
|
pub fn to_f64(&self) -> f64 {
|
||||||
self.value.to_f64_round(rug::float::Round::Nearest)
|
self.value.to_f64_round(rug::float::Round::Nearest)
|
||||||
}
|
}
|
||||||
@ -49,7 +57,28 @@ impl KalkNum {
|
|||||||
|
|
||||||
pub(crate) fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
pub(crate) fn pow(self, context: &mut crate::interpreter::Context, rhs: KalkNum) -> KalkNum {
|
||||||
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
let right = calculate_unit(context, &self, rhs.clone()).unwrap_or(rhs);
|
||||||
KalkNum::new(self.value.pow(right.value), &right.unit)
|
self.pow_without_unit(right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn pow_without_unit(self, rhs: KalkNum) -> KalkNum {
|
||||||
|
if self.has_imaginary() || rhs.has_imaginary() {
|
||||||
|
let a = self.value.clone();
|
||||||
|
let b = self.imaginary_value.clone();
|
||||||
|
let c = rhs.value;
|
||||||
|
let d = rhs.imaginary_value;
|
||||||
|
let arg = crate::prelude::funcs::arg(self).value;
|
||||||
|
let raised = a.clone() * a + b.clone() * b;
|
||||||
|
let exp = raised.clone().pow(c.clone() / 2f64) * (-d.clone() * arg.clone()).exp();
|
||||||
|
let polar = c * arg + d / 2f64 * raised.ln();
|
||||||
|
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
polar.clone().cos() * exp.clone(),
|
||||||
|
&rhs.unit,
|
||||||
|
polar.sin() * exp,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(self.value.pow(rhs.value), &rhs.unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,26 @@
|
|||||||
|
use crate::kalk_num::KalkNum;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use FuncType::*;
|
use FuncType::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "rug")]
|
||||||
|
pub mod with_rug;
|
||||||
|
#[cfg(feature = "rug")]
|
||||||
|
pub use with_rug::funcs::*;
|
||||||
|
#[cfg(feature = "rug")]
|
||||||
|
pub use with_rug::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "rug"))]
|
||||||
|
pub mod regular;
|
||||||
|
#[cfg(not(feature = "rug"))]
|
||||||
|
pub use regular::funcs::*;
|
||||||
|
#[cfg(not(feature = "rug"))]
|
||||||
|
pub use regular::*;
|
||||||
|
|
||||||
|
use crate::ast::Expr;
|
||||||
|
use crate::interpreter;
|
||||||
|
pub use funcs::*;
|
||||||
|
|
||||||
// `i` is added in the symbol_table module, since for some reason it didn't work here.
|
// `i` is added in the symbol_table module, since for some reason it didn't work here.
|
||||||
pub const INIT: &'static str = "unit deg = (rad*180)/pi";
|
pub const INIT: &'static str = "unit deg = (rad*180)/pi";
|
||||||
|
|
||||||
@ -41,8 +60,8 @@ lazy_static! {
|
|||||||
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
|
pub static ref UNARY_FUNCS: HashMap<&'static str, (UnaryFuncInfo, &'static str)> = {
|
||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
m.insert("cos", (UnaryFuncInfo(cos, Trig), ""));
|
m.insert("cos", (UnaryFuncInfo(cos, Trig), ""));
|
||||||
m.insert("cosec", (UnaryFuncInfo(cosec, Trig), ""));
|
m.insert("csc", (UnaryFuncInfo(csc, Trig), ""));
|
||||||
m.insert("cosech", (UnaryFuncInfo(cosech, Trig), ""));
|
m.insert("csch", (UnaryFuncInfo(csch, Trig), ""));
|
||||||
m.insert("cosh", (UnaryFuncInfo(cosh, Trig), ""));
|
m.insert("cosh", (UnaryFuncInfo(cosh, Trig), ""));
|
||||||
m.insert("cot", (UnaryFuncInfo(cot, Trig), ""));
|
m.insert("cot", (UnaryFuncInfo(cot, Trig), ""));
|
||||||
m.insert("coth", (UnaryFuncInfo(coth, Trig), ""));
|
m.insert("coth", (UnaryFuncInfo(coth, Trig), ""));
|
||||||
@ -54,8 +73,8 @@ lazy_static! {
|
|||||||
m.insert("tanh", (UnaryFuncInfo(tanh, Trig), ""));
|
m.insert("tanh", (UnaryFuncInfo(tanh, Trig), ""));
|
||||||
|
|
||||||
m.insert("acos", (UnaryFuncInfo(acos, InverseTrig), "rad"));
|
m.insert("acos", (UnaryFuncInfo(acos, InverseTrig), "rad"));
|
||||||
m.insert("acosec", (UnaryFuncInfo(acosec, InverseTrig), "rad"));
|
m.insert("acsc", (UnaryFuncInfo(acsc, InverseTrig), "rad"));
|
||||||
m.insert("acosech", (UnaryFuncInfo(acosech, InverseTrig), "rad"));
|
m.insert("acsch", (UnaryFuncInfo(acsch, InverseTrig), "rad"));
|
||||||
m.insert("acosh", (UnaryFuncInfo(acosh, InverseTrig), "rad"));
|
m.insert("acosh", (UnaryFuncInfo(acosh, InverseTrig), "rad"));
|
||||||
m.insert("acot", (UnaryFuncInfo(acot, InverseTrig), "rad"));
|
m.insert("acot", (UnaryFuncInfo(acot, InverseTrig), "rad"));
|
||||||
m.insert("acoth", (UnaryFuncInfo(acoth, InverseTrig), "rad"));
|
m.insert("acoth", (UnaryFuncInfo(acoth, InverseTrig), "rad"));
|
||||||
@ -66,6 +85,7 @@ lazy_static! {
|
|||||||
m.insert("atan", (UnaryFuncInfo(atan, InverseTrig), "rad"));
|
m.insert("atan", (UnaryFuncInfo(atan, InverseTrig), "rad"));
|
||||||
m.insert("atanh", (UnaryFuncInfo(atanh, InverseTrig), "rad"));
|
m.insert("atanh", (UnaryFuncInfo(atanh, InverseTrig), "rad"));
|
||||||
|
|
||||||
|
m.insert("arg", (UnaryFuncInfo(arg, Other), ""));
|
||||||
m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
|
m.insert("abs", (UnaryFuncInfo(abs, Other), ""));
|
||||||
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
|
m.insert("cbrt", (UnaryFuncInfo(cbrt, Other), ""));
|
||||||
m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
|
m.insert("ceil", (UnaryFuncInfo(ceil, Other), ""));
|
||||||
@ -86,7 +106,7 @@ lazy_static! {
|
|||||||
let mut m = HashMap::new();
|
let mut m = HashMap::new();
|
||||||
m.insert("max", (BinaryFuncInfo(max, Other), ""));
|
m.insert("max", (BinaryFuncInfo(max, Other), ""));
|
||||||
m.insert("min", (BinaryFuncInfo(min, Other), ""));
|
m.insert("min", (BinaryFuncInfo(min, Other), ""));
|
||||||
m.insert("hyp", (BinaryFuncInfo(hyp, Other), ""));
|
m.insert("hypot", (BinaryFuncInfo(hypot, Other), ""));
|
||||||
m.insert("log", (BinaryFuncInfo(logx, Other), ""));
|
m.insert("log", (BinaryFuncInfo(logx, Other), ""));
|
||||||
m.insert("root", (BinaryFuncInfo(nth_root, Other), ""));
|
m.insert("root", (BinaryFuncInfo(nth_root, Other), ""));
|
||||||
m
|
m
|
||||||
@ -99,16 +119,496 @@ enum FuncType {
|
|||||||
Other,
|
Other,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rug")]
|
// Unary functions
|
||||||
pub mod with_rug;
|
pub struct UnaryFuncInfo(fn(KalkNum) -> KalkNum, FuncType);
|
||||||
#[cfg(feature = "rug")]
|
|
||||||
pub use with_rug::funcs::*;
|
|
||||||
#[cfg(feature = "rug")]
|
|
||||||
pub use with_rug::*;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "rug"))]
|
pub struct BinaryFuncInfo(fn(KalkNum, KalkNum) -> KalkNum, FuncType);
|
||||||
pub mod regular;
|
|
||||||
#[cfg(not(feature = "rug"))]
|
impl UnaryFuncInfo {
|
||||||
pub use regular::funcs::*;
|
fn call(&self, context: &mut interpreter::Context, x: KalkNum, angle_unit: &str) -> KalkNum {
|
||||||
#[cfg(not(feature = "rug"))]
|
let func = self.0;
|
||||||
pub use regular::*;
|
match self.1 {
|
||||||
|
FuncType::Trig => func(from_angle_unit(context, x, angle_unit)),
|
||||||
|
FuncType::InverseTrig => to_angle_unit(context, func(x), angle_unit),
|
||||||
|
FuncType::Other => func(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BinaryFuncInfo {
|
||||||
|
fn call(
|
||||||
|
&self,
|
||||||
|
context: &mut interpreter::Context,
|
||||||
|
x: KalkNum,
|
||||||
|
y: KalkNum,
|
||||||
|
angle_unit: &str,
|
||||||
|
) -> KalkNum {
|
||||||
|
let func = self.0;
|
||||||
|
match self.1 {
|
||||||
|
FuncType::Trig => func(
|
||||||
|
from_angle_unit(context, x, angle_unit),
|
||||||
|
from_angle_unit(context, y, angle_unit),
|
||||||
|
),
|
||||||
|
FuncType::InverseTrig => to_angle_unit(context, func(x, y), angle_unit),
|
||||||
|
FuncType::Other => func(x, y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_prelude_func(identifier: &str) -> bool {
|
||||||
|
identifier == "sum"
|
||||||
|
|| identifier == "Σ"
|
||||||
|
|| identifier == "integrate"
|
||||||
|
|| identifier == "∫"
|
||||||
|
|| UNARY_FUNCS.contains_key(identifier)
|
||||||
|
|| BINARY_FUNCS.contains_key(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_unary_func(
|
||||||
|
context: &mut interpreter::Context,
|
||||||
|
name: &str,
|
||||||
|
x: KalkNum,
|
||||||
|
angle_unit: &str,
|
||||||
|
) -> Option<(KalkNum, String)> {
|
||||||
|
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
|
||||||
|
Some((
|
||||||
|
func_info.call(context, x, &angle_unit),
|
||||||
|
func_unit.to_string(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_binary_func(
|
||||||
|
context: &mut interpreter::Context,
|
||||||
|
name: &str,
|
||||||
|
x: KalkNum,
|
||||||
|
y: KalkNum,
|
||||||
|
angle_unit: &str,
|
||||||
|
) -> Option<(KalkNum, String)> {
|
||||||
|
if let Some((func_info, func_unit)) = BINARY_FUNCS.get(name) {
|
||||||
|
Some((
|
||||||
|
func_info.call(context, x, y, angle_unit),
|
||||||
|
func_unit.to_string(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_angle_unit(context: &mut interpreter::Context, x: KalkNum, angle_unit: &str) -> KalkNum {
|
||||||
|
match angle_unit {
|
||||||
|
"rad" => x,
|
||||||
|
_ => interpreter::convert_unit(context, &Expr::Literal(x.to_f64()), "rad", angle_unit)
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_angle_unit(context: &mut interpreter::Context, x: KalkNum, angle_unit: &str) -> KalkNum {
|
||||||
|
match angle_unit {
|
||||||
|
"rad" => x,
|
||||||
|
_ => interpreter::convert_unit(context, &Expr::Literal(x.to_f64()), angle_unit, "rad")
|
||||||
|
.unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod funcs {
|
||||||
|
#[cfg(not(feature = "rug"))]
|
||||||
|
pub use super::regular::funcs::*;
|
||||||
|
#[cfg(feature = "rug")]
|
||||||
|
pub use super::with_rug::funcs::*;
|
||||||
|
use crate::kalk_num::KalkNum;
|
||||||
|
|
||||||
|
pub fn abs(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// |z| = sqrt(a² + b²)
|
||||||
|
let a = x.value.clone() * x.value;
|
||||||
|
let b = x.imaginary_value.clone() * x.imaginary_value;
|
||||||
|
|
||||||
|
sqrt(KalkNum::new(a + b, &x.unit))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.abs(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acos(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// -i * ln(i * sqrt(1 - z²) + z)
|
||||||
|
let root =
|
||||||
|
sqrt(KalkNum::from(1f64).sub_without_unit(x.clone().mul_without_unit(x.clone())));
|
||||||
|
let iroot = multiply_with_i(root.clone());
|
||||||
|
let ln = ln(iroot.add_without_unit(x));
|
||||||
|
|
||||||
|
// -iz = -i(a + bi) = b - ai
|
||||||
|
KalkNum::new_with_imaginary(ln.imaginary_value, &ln.unit, -ln.value)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.acos(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acosh(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let sqrt1 = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone() + 1f64,
|
||||||
|
&x.unit,
|
||||||
|
x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
let sqrt2 = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone() - 1f64,
|
||||||
|
&x.unit,
|
||||||
|
x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
|
||||||
|
ln(x.add_without_unit(sqrt1.mul_without_unit(sqrt2)))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.acosh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acot(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// atan(1/z)
|
||||||
|
atan(KalkNum::from(1f64).div_without_unit(x))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).atan(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acoth(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// 1 / z
|
||||||
|
let inv_x = KalkNum::from(1f64).div_without_unit(x);
|
||||||
|
let ln1 = ln(KalkNum::new_with_imaginary(
|
||||||
|
1f64 + inv_x.value.clone(),
|
||||||
|
&inv_x.unit,
|
||||||
|
inv_x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
let ln2 = ln(KalkNum::new_with_imaginary(
|
||||||
|
1f64 - inv_x.value,
|
||||||
|
&inv_x.unit,
|
||||||
|
-inv_x.imaginary_value,
|
||||||
|
));
|
||||||
|
|
||||||
|
ln1.sub_without_unit(ln2)
|
||||||
|
.div_without_unit(KalkNum::from(2f64))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).atanh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acsc(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// asin(1/z)
|
||||||
|
asin(KalkNum::from(1f64).div_without_unit(x))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).asin(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn acsch(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let inv_x2 =
|
||||||
|
KalkNum::from(1f64).div_without_unit(x.clone().mul_without_unit(x.clone()));
|
||||||
|
let sqrt = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
1f64 + inv_x2.value,
|
||||||
|
&inv_x2.unit,
|
||||||
|
inv_x2.imaginary_value,
|
||||||
|
));
|
||||||
|
let inv_x = KalkNum::from(1f64).div_without_unit(x.clone());
|
||||||
|
|
||||||
|
ln(sqrt.add_without_unit(inv_x))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).asinh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asec(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// acos(1/z)
|
||||||
|
acos(KalkNum::from(1f64).div_without_unit(x))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).acos(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asech(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// 1/z
|
||||||
|
let inv_x = KalkNum::from(1f64).div_without_unit(x.clone());
|
||||||
|
// sqrt(1/z - 1)
|
||||||
|
let sqrt1 = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
inv_x.value.clone() - 1f64,
|
||||||
|
&inv_x.unit,
|
||||||
|
inv_x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
// sqrt(1/z + 1)
|
||||||
|
let sqrt2 = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
inv_x.value.clone() + 1f64,
|
||||||
|
&inv_x.unit,
|
||||||
|
inv_x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
|
||||||
|
// ln(1/z + sqrt(1/z - 1) * sqrt(1/z + 1))
|
||||||
|
ln(sqrt1.mul_without_unit(sqrt2).add_without_unit(inv_x))
|
||||||
|
} else {
|
||||||
|
KalkNum::new((1f64 / x.value).acosh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asin(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// i * ln(sqrt(1 - z²) - iz)
|
||||||
|
let root =
|
||||||
|
sqrt(KalkNum::from(1f64).sub_without_unit(x.clone().mul_without_unit(x.clone())));
|
||||||
|
let iz = multiply_with_i(x.clone());
|
||||||
|
let ln = ln(root.sub_without_unit(iz));
|
||||||
|
multiply_with_i(ln)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.asin(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asinh(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let x2 = x.clone().mul_without_unit(x.clone());
|
||||||
|
let sqrt = sqrt(KalkNum::new_with_imaginary(
|
||||||
|
x2.value + 1f64,
|
||||||
|
&x2.unit,
|
||||||
|
x2.imaginary_value,
|
||||||
|
));
|
||||||
|
|
||||||
|
ln(x.add_without_unit(sqrt))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.asinh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atan(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let iz = multiply_with_i(x);
|
||||||
|
// 1 + iz
|
||||||
|
let numerator = KalkNum::new_with_imaginary(
|
||||||
|
1f64 + iz.value.clone(),
|
||||||
|
&iz.unit,
|
||||||
|
iz.imaginary_value.clone(),
|
||||||
|
);
|
||||||
|
// 1 - iz
|
||||||
|
let denominator =
|
||||||
|
KalkNum::new_with_imaginary(1f64 - iz.value, &iz.unit, -iz.imaginary_value);
|
||||||
|
let ln = ln(numerator.div_without_unit(denominator));
|
||||||
|
|
||||||
|
// -0.5iz = -0.5i(a + bi) = b/2 - ai/2
|
||||||
|
multiply_with_i(ln).div_without_unit(KalkNum::from(-2f64))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.atan(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn atanh(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// 1/2 * log(z + 1) - 1/2 * log(-z + 1)
|
||||||
|
let log1 = ln(KalkNum::new_with_imaginary(
|
||||||
|
1f64 + x.value.clone(),
|
||||||
|
&x.unit,
|
||||||
|
x.imaginary_value.clone(),
|
||||||
|
));
|
||||||
|
let log2 = ln(KalkNum::new_with_imaginary(
|
||||||
|
1f64 - x.value,
|
||||||
|
&x.unit,
|
||||||
|
-x.imaginary_value,
|
||||||
|
));
|
||||||
|
|
||||||
|
log1.sub_without_unit(log2)
|
||||||
|
.div_without_unit(KalkNum::from(2f64))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.atanh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cbrt(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new(x.value.cbrt(), &x.unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ceil(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(x.value.ceil(), &x.unit, x.imaginary_value.ceil())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cos(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone().cos() * x.imaginary_value.clone().cosh(),
|
||||||
|
&x.unit,
|
||||||
|
-x.value.sin() * x.imaginary_value.sinh(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cosh(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone().cosh() * x.imaginary_value.clone().cos(),
|
||||||
|
&x.unit,
|
||||||
|
x.value.sinh() * x.imaginary_value.sin(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn csc(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::from(1f64).div_without_unit(sin(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn csch(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::from(1f64).div_without_unit(sinh(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cot(x: KalkNum) -> KalkNum {
|
||||||
|
let a = x.value * 2f64;
|
||||||
|
let b = x.imaginary_value * 2f64;
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
-a.clone().sin() / (a.clone().cos() - b.clone().cosh()),
|
||||||
|
&x.unit,
|
||||||
|
b.clone().sinh() / (a.cos() - b.cosh()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn coth(x: KalkNum) -> KalkNum {
|
||||||
|
let a = x.value * 2f64;
|
||||||
|
let b = x.imaginary_value * 2f64;
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
-a.clone().sinh() / (b.clone().cos() - a.clone().cosh()),
|
||||||
|
&x.unit,
|
||||||
|
b.clone().sin() / (b.cos() - a.cosh()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exp(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// e^a*cos(b) + ie^a*sin(b)
|
||||||
|
let exp_a = x.value.exp();
|
||||||
|
let b = x.imaginary_value;
|
||||||
|
KalkNum::new_with_imaginary(exp_a.clone() * b.clone().cos(), &x.unit, exp_a * b.sin())
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.exp(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn floor(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(x.value.floor(), &x.unit, x.imaginary_value.floor())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frac(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(x.value.fract(), &x.unit, x.imaginary_value.fract())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
// ln(z) / ln(10)
|
||||||
|
ln(x).div_without_unit(KalkNum::from(10f64.ln()))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.log10(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn logx(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() || y.has_imaginary() {
|
||||||
|
// ln(z) / ln(n)
|
||||||
|
ln(x).div_without_unit(ln(y))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.log10() / y.value.log10(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ln(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let r = abs(x.clone());
|
||||||
|
// ln|z| + i * arg z
|
||||||
|
ln(r).add_without_unit(multiply_with_i(arg(x)))
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.ln(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nth_root(x: KalkNum, n: KalkNum) -> KalkNum {
|
||||||
|
x.pow_without_unit(KalkNum::from(1f64).div_without_unit(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn round(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(x.value.round(), &x.unit, x.imaginary_value.round())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sec(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::from(1f64).div_without_unit(cos(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sech(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::from(1f64).div_without_unit(cosh(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sin(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone().sin() * x.imaginary_value.clone().cosh(),
|
||||||
|
&x.unit,
|
||||||
|
x.value.cos() * x.imaginary_value.sinh(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sinh(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
x.value.clone().sinh() * x.imaginary_value.clone().cos(),
|
||||||
|
&x.unit,
|
||||||
|
x.value.cosh() * x.imaginary_value.sin(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sqrt(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let abs = abs(x.clone());
|
||||||
|
let r = abs.value;
|
||||||
|
let a = x.value;
|
||||||
|
let b = x.imaginary_value;
|
||||||
|
|
||||||
|
// sqrt((|z| + a) / 2) + i * (b / |b|) * sqrt((|z| - a) / 2)
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
((r.clone() + a.clone()) / 2f64).sqrt(),
|
||||||
|
&abs.unit,
|
||||||
|
(b.clone() / b.abs()) * ((r - a) / 2f64).sqrt(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.sqrt(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tan(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let a = x.value * 2f64;
|
||||||
|
let b = x.imaginary_value * 2f64;
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
a.clone().sin() / (a.clone().cos() + b.clone().cosh()),
|
||||||
|
&x.unit,
|
||||||
|
b.clone().sinh() / (a.cos() + b.cosh()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.tan(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tanh(x: KalkNum) -> KalkNum {
|
||||||
|
if x.has_imaginary() {
|
||||||
|
let a = x.value * 2f64;
|
||||||
|
let b = x.imaginary_value * 2f64;
|
||||||
|
KalkNum::new_with_imaginary(
|
||||||
|
a.clone().sinh() / (a.clone().cosh() + b.clone().cos()),
|
||||||
|
&x.unit,
|
||||||
|
b.clone().sin() / (a.cosh() + b.cos()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.tanh(), &x.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trunc(x: KalkNum) -> KalkNum {
|
||||||
|
KalkNum::new_with_imaginary(x.value.trunc(), &x.unit, x.imaginary_value.trunc())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn multiply_with_i(z: KalkNum) -> KalkNum {
|
||||||
|
// iz = i(a + bi) = -b + ai
|
||||||
|
KalkNum::new_with_imaginary(-z.imaginary_value, &z.unit, z.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,211 +1,34 @@
|
|||||||
use super::*;
|
|
||||||
use crate::ast::Expr;
|
|
||||||
use crate::interpreter;
|
|
||||||
|
|
||||||
// Unary functions
|
|
||||||
pub struct UnaryFuncInfo(pub(super) fn(f64) -> f64, pub(super) FuncType);
|
|
||||||
|
|
||||||
pub struct BinaryFuncInfo(pub(super) fn(f64, f64) -> f64, pub(super) FuncType);
|
|
||||||
|
|
||||||
impl UnaryFuncInfo {
|
|
||||||
fn call(&self, context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
|
||||||
let func = self.0;
|
|
||||||
match self.1 {
|
|
||||||
FuncType::Trig => func(from_angle_unit(context, x, angle_unit)),
|
|
||||||
FuncType::InverseTrig => to_angle_unit(context, func(x), angle_unit),
|
|
||||||
FuncType::Other => func(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinaryFuncInfo {
|
|
||||||
fn call(&self, context: &mut interpreter::Context, x: f64, y: f64, angle_unit: &str) -> f64 {
|
|
||||||
let func = self.0;
|
|
||||||
match self.1 {
|
|
||||||
FuncType::Trig => func(
|
|
||||||
from_angle_unit(context, x, angle_unit),
|
|
||||||
from_angle_unit(context, y, angle_unit),
|
|
||||||
),
|
|
||||||
FuncType::InverseTrig => to_angle_unit(context, func(x, y), angle_unit),
|
|
||||||
FuncType::Other => func(x, y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_prelude_func(identifier: &str) -> bool {
|
|
||||||
identifier == "sum"
|
|
||||||
|| identifier == "Σ"
|
|
||||||
|| identifier == "integrate"
|
|
||||||
|| identifier == "∫"
|
|
||||||
|| UNARY_FUNCS.contains_key(identifier)
|
|
||||||
|| BINARY_FUNCS.contains_key(identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_unary_func(
|
|
||||||
context: &mut interpreter::Context,
|
|
||||||
name: &str,
|
|
||||||
x: f64,
|
|
||||||
angle_unit: &str,
|
|
||||||
) -> Option<(f64, String)> {
|
|
||||||
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
|
|
||||||
Some((
|
|
||||||
func_info.call(context, x, &angle_unit),
|
|
||||||
func_unit.to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_binary_func(
|
|
||||||
context: &mut interpreter::Context,
|
|
||||||
name: &str,
|
|
||||||
x: f64,
|
|
||||||
y: f64,
|
|
||||||
angle_unit: &str,
|
|
||||||
) -> Option<(f64, String)> {
|
|
||||||
if let Some((func_info, func_unit)) = BINARY_FUNCS.get(name) {
|
|
||||||
Some((
|
|
||||||
func_info.call(context, x, y, angle_unit),
|
|
||||||
func_unit.to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_angle_unit(context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
|
||||||
match angle_unit {
|
|
||||||
"rad" => x,
|
|
||||||
_ => {
|
|
||||||
interpreter::convert_unit(context, &Expr::Literal(x), "rad", angle_unit)
|
|
||||||
.unwrap()
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_angle_unit(context: &mut interpreter::Context, x: f64, angle_unit: &str) -> f64 {
|
|
||||||
match angle_unit {
|
|
||||||
"rad" => x,
|
|
||||||
_ => {
|
|
||||||
interpreter::convert_unit(context, &Expr::Literal(x), angle_unit, "rad")
|
|
||||||
.unwrap()
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod special_funcs {
|
pub mod special_funcs {
|
||||||
pub fn factorial(x: f64) -> f64 {
|
use crate::kalk_num::KalkNum;
|
||||||
super::funcs::gamma(x + 1f64)
|
|
||||||
|
pub fn factorial(x: KalkNum) -> KalkNum {
|
||||||
|
// Round it a bit, to prevent floating point errors.
|
||||||
|
KalkNum::new(
|
||||||
|
(super::funcs::precise_gamma(x.value + 1f64) * 10e6f64).round() / 10e6f64,
|
||||||
|
&x.unit,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod funcs {
|
pub(crate) mod funcs {
|
||||||
pub fn abs(x: f64) -> f64 {
|
use crate::kalk_num::KalkNum;
|
||||||
x.abs()
|
use crate::prelude::funcs::abs;
|
||||||
|
|
||||||
|
pub fn arg(x: KalkNum) -> KalkNum {
|
||||||
|
// i(ln|x| - ln(x))
|
||||||
|
KalkNum::new(x.imaginary_value.atan2(x.value), &x.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acos(x: f64) -> f64 {
|
pub fn gamma(x: KalkNum) -> KalkNum {
|
||||||
x.acos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acosh(x: f64) -> f64 {
|
|
||||||
x.acosh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acot(x: f64) -> f64 {
|
|
||||||
(1f64 / x).atan()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acoth(x: f64) -> f64 {
|
|
||||||
(1f64 / x).atanh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acosec(x: f64) -> f64 {
|
|
||||||
(1f64 / x).asin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acosech(x: f64) -> f64 {
|
|
||||||
(1f64 / x).asinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asec(x: f64) -> f64 {
|
|
||||||
(1f64 / x).acos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asech(x: f64) -> f64 {
|
|
||||||
(1f64 / x).acosh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asin(x: f64) -> f64 {
|
|
||||||
x.asin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asinh(x: f64) -> f64 {
|
|
||||||
x.asinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn atan(x: f64) -> f64 {
|
|
||||||
x.atan()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn atanh(x: f64) -> f64 {
|
|
||||||
x.atanh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cbrt(x: f64) -> f64 {
|
|
||||||
x.cbrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ceil(x: f64) -> f64 {
|
|
||||||
x.ceil()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cos(x: f64) -> f64 {
|
|
||||||
x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosh(x: f64) -> f64 {
|
|
||||||
x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosec(x: f64) -> f64 {
|
|
||||||
1f64 / x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosech(x: f64) -> f64 {
|
|
||||||
1f64 / x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cot(x: f64) -> f64 {
|
|
||||||
x.clone().cos() / x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn coth(x: f64) -> f64 {
|
|
||||||
x.clone().cosh() / x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exp(x: f64) -> f64 {
|
|
||||||
x.exp()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn floor(x: f64) -> f64 {
|
|
||||||
x.floor()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn frac(x: f64) -> f64 {
|
|
||||||
x.fract()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gamma(x: f64) -> f64 {
|
|
||||||
// Round it a bit, to prevent floating point errors.
|
// Round it a bit, to prevent floating point errors.
|
||||||
(precise_gamma(x) * 10e6f64).round() / 10e6f64
|
KalkNum::new(
|
||||||
|
(precise_gamma(x.value) * 10e6f64).round() / 10e6f64,
|
||||||
|
&x.unit,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matthias Eiholzer - https://gitlab.com/matthiaseiholzer/mathru/-/tree/master
|
// Matthias Eiholzer - https://gitlab.com/matthiaseiholzer/mathru/-/tree/master
|
||||||
fn precise_gamma(x: f64) -> f64 {
|
pub(super) fn precise_gamma(x: f64) -> f64 {
|
||||||
let pi = 3.1415926535897932384626433832795028841971693993751058209749445923f64;
|
let pi = 3.1415926535897932384626433832795028841971693993751058209749445923f64;
|
||||||
if x == 0f64 {
|
if x == 0f64 {
|
||||||
return f64::NAN;
|
return f64::NAN;
|
||||||
@ -227,67 +50,26 @@ pub(super) mod funcs {
|
|||||||
2f64.sqrt() * pi.sqrt() * t.powf(x - 0.5f64) * (-t).exp() * a
|
2f64.sqrt() * pi.sqrt() * t.powf(x - 0.5f64) * (-t).exp() * a
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hyp(x: f64, y: f64) -> f64 {
|
pub fn hypot(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
x.hypot(y)
|
if x.has_imaginary() || y.has_imaginary() {
|
||||||
|
let abs_x = abs(x);
|
||||||
|
let abs_y = abs(y);
|
||||||
|
crate::prelude::funcs::sqrt(
|
||||||
|
abs_x
|
||||||
|
.clone()
|
||||||
|
.mul_without_unit(abs_x)
|
||||||
|
.add_without_unit(abs_y.clone().mul_without_unit(abs_y)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.hypot(y.value), &x.unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(x: f64) -> f64 {
|
pub fn max(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
x.log10()
|
KalkNum::new(x.value.max(y.value), &x.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn logx(x: f64, y: f64) -> f64 {
|
pub fn min(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
x.log10() / y.log10()
|
KalkNum::new(x.value.min(y.value), &x.unit)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ln(x: f64) -> f64 {
|
|
||||||
x.ln()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max(x: f64, y: f64) -> f64 {
|
|
||||||
x.max(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min(x: f64, y: f64) -> f64 {
|
|
||||||
x.min(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn round(x: f64) -> f64 {
|
|
||||||
x.round()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sec(x: f64) -> f64 {
|
|
||||||
1f64 / x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sech(x: f64) -> f64 {
|
|
||||||
1f64 / x.cosh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sin(x: f64) -> f64 {
|
|
||||||
x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sinh(x: f64) -> f64 {
|
|
||||||
x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sqrt(x: f64) -> f64 {
|
|
||||||
x.sqrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nth_root(x: f64, n: f64) -> f64 {
|
|
||||||
x.powf(1f64 / n)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tan(x: f64) -> f64 {
|
|
||||||
x.tan()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tanh(x: f64) -> f64 {
|
|
||||||
x.tanh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trunc(x: f64) -> f64 {
|
|
||||||
x.trunc()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,291 +1,44 @@
|
|||||||
use super::*;
|
|
||||||
use crate::ast::Expr;
|
|
||||||
use crate::interpreter;
|
|
||||||
use rug::Float;
|
|
||||||
|
|
||||||
// Unary functions
|
|
||||||
pub struct UnaryFuncInfo(pub(super) fn(Float) -> Float, pub(super) FuncType);
|
|
||||||
|
|
||||||
pub struct BinaryFuncInfo(pub(super) fn(Float, Float) -> Float, pub(super) FuncType);
|
|
||||||
|
|
||||||
impl UnaryFuncInfo {
|
|
||||||
fn call(&self, context: &mut interpreter::Context, x: Float, angle_unit: &str) -> Float {
|
|
||||||
let func = self.0;
|
|
||||||
match self.1 {
|
|
||||||
FuncType::Trig => func(from_angle_unit(context, x, angle_unit)),
|
|
||||||
FuncType::InverseTrig => to_angle_unit(context, func(x), angle_unit),
|
|
||||||
FuncType::Other => func(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BinaryFuncInfo {
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
context: &mut interpreter::Context,
|
|
||||||
x: Float,
|
|
||||||
y: Float,
|
|
||||||
angle_unit: &str,
|
|
||||||
) -> Float {
|
|
||||||
let func = self.0;
|
|
||||||
match self.1 {
|
|
||||||
FuncType::Trig => func(
|
|
||||||
from_angle_unit(context, x, angle_unit),
|
|
||||||
from_angle_unit(context, y, angle_unit),
|
|
||||||
),
|
|
||||||
FuncType::InverseTrig => to_angle_unit(context, func(x, y), angle_unit),
|
|
||||||
FuncType::Other => func(x, y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_prelude_func(identifier: &str) -> bool {
|
|
||||||
identifier == "sum"
|
|
||||||
|| identifier == "Σ"
|
|
||||||
|| identifier == "integrate"
|
|
||||||
|| identifier == "∫"
|
|
||||||
|| UNARY_FUNCS.contains_key(identifier)
|
|
||||||
|| BINARY_FUNCS.contains_key(identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_unary_func(
|
|
||||||
context: &mut interpreter::Context,
|
|
||||||
name: &str,
|
|
||||||
x: Float,
|
|
||||||
angle_unit: &str,
|
|
||||||
) -> Option<(Float, String)> {
|
|
||||||
if let Some((func_info, func_unit)) = UNARY_FUNCS.get(name) {
|
|
||||||
Some((
|
|
||||||
func_info.call(context, x, &angle_unit),
|
|
||||||
func_unit.to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_binary_func(
|
|
||||||
context: &mut interpreter::Context,
|
|
||||||
name: &str,
|
|
||||||
x: Float,
|
|
||||||
y: Float,
|
|
||||||
angle_unit: &str,
|
|
||||||
) -> Option<(Float, String)> {
|
|
||||||
if let Some((func_info, func_unit)) = BINARY_FUNCS.get(name) {
|
|
||||||
Some((
|
|
||||||
func_info.call(context, x, y, angle_unit),
|
|
||||||
func_unit.to_string(),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_angle_unit(context: &mut interpreter::Context, x: Float, angle_unit: &str) -> Float {
|
|
||||||
match angle_unit {
|
|
||||||
"rad" => x,
|
|
||||||
_ => {
|
|
||||||
interpreter::convert_unit(
|
|
||||||
context,
|
|
||||||
&Expr::Literal(x.to_f64_round(rug::float::Round::Nearest)),
|
|
||||||
"rad",
|
|
||||||
angle_unit,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_angle_unit(context: &mut interpreter::Context, x: Float, angle_unit: &str) -> Float {
|
|
||||||
match angle_unit {
|
|
||||||
"rad" => x,
|
|
||||||
_ => {
|
|
||||||
interpreter::convert_unit(
|
|
||||||
context,
|
|
||||||
&Expr::Literal(x.to_f64_round(rug::float::Round::Nearest)),
|
|
||||||
angle_unit,
|
|
||||||
"rad",
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod special_funcs {
|
pub mod special_funcs {
|
||||||
use rug::Float;
|
use crate::prelude::KalkNum;
|
||||||
|
|
||||||
pub fn factorial(x: Float) -> Float {
|
pub fn factorial(x: KalkNum) -> KalkNum {
|
||||||
((x + 1) as Float).gamma()
|
KalkNum::new((x.value + 1f64).gamma(), &x.unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) mod funcs {
|
pub(crate) mod funcs {
|
||||||
use rug::ops::Pow;
|
use crate::kalk_num::KalkNum;
|
||||||
use rug::Float;
|
use crate::prelude::funcs::abs;
|
||||||
|
|
||||||
pub fn abs(x: Float) -> Float {
|
pub fn arg(x: KalkNum) -> KalkNum {
|
||||||
x.abs()
|
// i(ln|x| - ln(x))
|
||||||
|
KalkNum::new(x.imaginary_value.atan2(&x.value), &x.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acos(x: Float) -> Float {
|
pub fn gamma(x: KalkNum) -> KalkNum {
|
||||||
x.acos()
|
KalkNum::new(x.value.gamma(), &x.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acosh(x: Float) -> Float {
|
pub fn hypot(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
x.acosh()
|
if x.has_imaginary() || y.has_imaginary() {
|
||||||
|
let abs_x = abs(x);
|
||||||
|
let abs_y = abs(y);
|
||||||
|
crate::prelude::funcs::sqrt(
|
||||||
|
abs_x
|
||||||
|
.clone()
|
||||||
|
.mul_without_unit(abs_x)
|
||||||
|
.add_without_unit(abs_y.clone().mul_without_unit(abs_y)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
KalkNum::new(x.value.hypot(&y.value), &x.unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acot(x: Float) -> Float {
|
pub fn max(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
(1f64 / x).atan()
|
KalkNum::new(x.value.max(&y.value), &x.unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn acoth(x: Float) -> Float {
|
pub fn min(x: KalkNum, y: KalkNum) -> KalkNum {
|
||||||
(1f64 / x).atanh()
|
KalkNum::new(x.value.min(&y.value), &x.unit)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acosec(x: Float) -> Float {
|
|
||||||
(1f64 / x).asin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn acosech(x: Float) -> Float {
|
|
||||||
(1f64 / x).asinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asec(x: Float) -> Float {
|
|
||||||
(1f64 / x).acos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asech(x: Float) -> Float {
|
|
||||||
(1f64 / x).acosh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asin(x: Float) -> Float {
|
|
||||||
x.asin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn asinh(x: Float) -> Float {
|
|
||||||
x.asinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn atan(x: Float) -> Float {
|
|
||||||
x.atan()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn atanh(x: Float) -> Float {
|
|
||||||
x.atanh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cbrt(x: Float) -> Float {
|
|
||||||
x.cbrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ceil(x: Float) -> Float {
|
|
||||||
x.ceil()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cos(x: Float) -> Float {
|
|
||||||
x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosh(x: Float) -> Float {
|
|
||||||
x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosec(x: Float) -> Float {
|
|
||||||
1f64 / x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cosech(x: Float) -> Float {
|
|
||||||
1f64 / x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cot(x: Float) -> Float {
|
|
||||||
x.clone().cos() / x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn coth(x: Float) -> Float {
|
|
||||||
x.clone().cosh() / x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exp(x: Float) -> Float {
|
|
||||||
x.exp()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn floor(x: Float) -> Float {
|
|
||||||
x.floor()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn frac(x: Float) -> Float {
|
|
||||||
x.fract()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gamma(x: Float) -> Float {
|
|
||||||
x.gamma()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hyp(x: Float, y: Float) -> Float {
|
|
||||||
x.hypot(&y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn log(x: Float) -> Float {
|
|
||||||
x.log10()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn logx(x: Float, y: Float) -> Float {
|
|
||||||
x.log10() / y.log10()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ln(x: Float) -> Float {
|
|
||||||
x.ln()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn max(x: Float, y: Float) -> Float {
|
|
||||||
x.max(&y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn min(x: Float, y: Float) -> Float {
|
|
||||||
x.min(&y)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn round(x: Float) -> Float {
|
|
||||||
x.round()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sec(x: Float) -> Float {
|
|
||||||
1f64 / x.cos()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sech(x: Float) -> Float {
|
|
||||||
1f64 / x.cosh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sin(x: Float) -> Float {
|
|
||||||
x.sin()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sinh(x: Float) -> Float {
|
|
||||||
x.sinh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sqrt(x: Float) -> Float {
|
|
||||||
x.sqrt()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn nth_root(x: Float, n: Float) -> Float {
|
|
||||||
x.pow(Float::with_val(1, 1) / n)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tan(x: Float) -> Float {
|
|
||||||
x.tan()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tanh(x: Float) -> Float {
|
|
||||||
x.tanh()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trunc(x: Float) -> Float {
|
|
||||||
x.trunc()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,14 @@ They are used like this: name(arg1, arg2, etc.)
|
|||||||
Example: f(3) + 3 A(2, 3)
|
Example: f(3) + 3 A(2, 3)
|
||||||
|
|
||||||
Predefined functions
|
Predefined functions
|
||||||
sin, cos, tan, cot, cosec, sec
|
sin, cos, tan, cot, csc, sec
|
||||||
sinh, cosh, tanh, coth, cosech, sech
|
sinh, cosh, tanh, coth, csch, sech
|
||||||
asin, acos, atan, acot, acosec, asec
|
asin, acos, atan, acot, acsc, asec
|
||||||
asinh, acosh, atanh, acoth, acosech, asech
|
asinh, acosh, atanh, acoth, acsch, asech
|
||||||
abs, ceil or ⌈⌉, floor or ⌊⌋, frac, round, trunc
|
abs, ceil or ⌈⌉, floor or ⌊⌋, frac, round, trunc
|
||||||
sqrt or √, cbrt, exp, log, ln
|
sqrt or √, cbrt, exp, log, ln
|
||||||
gamma or Γ
|
gamma or Γ
|
||||||
asinh, acosh, atanh, acoth, acosech, asech
|
asinh, acosh, atanh, acoth, acsch, asech
|
||||||
min, max, hyp
|
min, max, hyp
|
||||||
log Eg. log(1000, 10) is the same as log10(1000)
|
log Eg. log(1000, 10) is the same as log10(1000)
|
||||||
root Eg. root(16, 3) is the same as 3√16
|
root Eg. root(16, 3) is the same as 3√16
|
||||||
|
Loading…
Reference in New Issue
Block a user