summaryrefslogtreecommitdiff
path: root/library/src
diff options
context:
space:
mode:
authorJett Chen <jettchen12345@gmail.com>2023-06-07 20:44:07 +0800
committerGitHub <noreply@github.com>2023-06-07 14:44:07 +0200
commitc87f802cf60b7ae5dfdca9ccfa011c5105d9947b (patch)
treec9ea6af8be3aa7edd14b641251eafe874bdeaba5 /library/src
parent0dc1776202149bb59c21d1db8efe2a10c409b6e6 (diff)
add calc.exp, calc.ln (#1299)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'library/src')
-rw-r--r--library/src/compute/calc.rs82
1 files changed, 78 insertions, 4 deletions
diff --git a/library/src/compute/calc.rs b/library/src/compute/calc.rs
index 071cf164..c1ae683e 100644
--- a/library/src/compute/calc.rs
+++ b/library/src/compute/calc.rs
@@ -13,6 +13,7 @@ pub fn module() -> Module {
let mut scope = Scope::new();
scope.define("abs", abs_func());
scope.define("pow", pow_func());
+ scope.define("exp", exp_func());
scope.define("sqrt", sqrt_func());
scope.define("sin", sin_func());
scope.define("cos", cos_func());
@@ -25,6 +26,7 @@ pub fn module() -> Module {
scope.define("cosh", cosh_func());
scope.define("tanh", tanh_func());
scope.define("log", log_func());
+ scope.define("ln", ln_func());
scope.define("fact", fact_func());
scope.define("perm", perm_func());
scope.define("binom", binom_func());
@@ -96,7 +98,7 @@ cast! {
pub fn pow(
/// The base of the power.
base: Num,
- /// The exponent of the power. Must be non-negative.
+ /// The exponent of the power.
exponent: Spanned<Num>,
/// The callsite span.
span: Span,
@@ -120,8 +122,15 @@ pub fn pow(
.map(Num::Int)
.ok_or("the result is too large")
.at(span)?,
- (a, Num::Int(b)) => Num::Float(a.float().powi(b as i32)),
- (a, b) => Num::Float(a.float().powf(b.float())),
+ (a, b) => Num::Float(if a.float() == std::f64::consts::E {
+ b.float().exp()
+ } else if a.float() == 2.0 {
+ b.float().exp2()
+ } else if let Num::Int(b) = b {
+ a.float().powi(b as i32)
+ } else {
+ a.float().powf(b.float())
+ }),
};
if result.float().is_nan() {
@@ -131,6 +140,40 @@ pub fn pow(
Ok(result)
}
+/// Raise a value to some exponent of e.
+///
+/// ## Example { #example }
+/// ```example
+/// #calc.exp(3)
+/// ```
+///
+/// Display: Exponential
+/// Category: calculate
+#[func]
+pub fn exp(
+ /// The exponent of the power.
+ exponent: Spanned<Num>,
+ /// The callsite span.
+ span: Span,
+) -> SourceResult<f64> {
+ match exponent.v {
+ Num::Int(i) if i32::try_from(i).is_err() => {
+ bail!(exponent.span, "exponent is too large")
+ }
+ Num::Float(f) if !f.is_normal() && f != 0.0 => {
+ bail!(exponent.span, "exponent may not be infinite, subnormal, or NaN")
+ }
+ _ => {}
+ };
+
+ let result = exponent.v.float().exp();
+ if result.is_nan() {
+ bail!(span, "the result is not a real number")
+ }
+
+ Ok(result)
+}
+
/// Calculate the square root of a number.
///
/// ## Example { #example }
@@ -416,7 +459,9 @@ pub fn log(
bail!(base.span, "base may not be zero, NaN, infinite, or subnormal")
}
- let result = if base.v == 2.0 {
+ let result = if base.v == std::f64::consts::E {
+ number.ln()
+ } else if base.v == 2.0 {
number.log2()
} else if base.v == 10.0 {
number.log10()
@@ -431,6 +476,35 @@ pub fn log(
Ok(result)
}
+/// Calculate the natural logarithm of a number.
+///
+/// ## Example { #example }
+/// ```example
+/// #calc.ln(100)
+/// ```
+///
+/// Display: Natural Logarithm
+/// Category: calculate
+#[func]
+pub fn ln(
+ /// The number whose logarithm to calculate. Must be strictly positive.
+ value: Spanned<Num>,
+ /// The callsite span.
+ span: Span,
+) -> SourceResult<f64> {
+ let number = value.v.float();
+ if number <= 0.0 {
+ bail!(value.span, "value must be strictly positive")
+ }
+
+ let result = number.ln();
+ if result.is_infinite() {
+ bail!(span, "result close to -inf")
+ }
+
+ Ok(result)
+}
+
/// Calculate the factorial of a number.
///
/// ## Example { #example }