Implemented complex variants of prelude functions

This commit is contained in:
bakk 2021-05-22 20:47:10 +02:00
parent 1c914bc77f
commit fa4e853982
9 changed files with 717 additions and 610 deletions

View File

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

View File

@ -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");

View File

@ -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(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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