Remove trig functions from prelude and change their unit handling Signed-off-by: Nick Cameron <nrc@ncameron.org>
716 lines
21 KiB
Rust
716 lines
21 KiB
Rust
//! Functions related to mathematics.
|
|
|
|
use anyhow::Result;
|
|
use kcl_derive_docs::stdlib;
|
|
|
|
use crate::{
|
|
errors::KclError,
|
|
execution::{
|
|
types::{ArrayLen, NumericType, RuntimeType},
|
|
ExecState, KclValue,
|
|
},
|
|
std::args::{Args, TyF64},
|
|
CompilationError,
|
|
};
|
|
|
|
/// Compute the remainder after dividing `num` by `div`.
|
|
/// If `num` is negative, the result will be too.
|
|
pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let n: TyF64 = args.get_unlabeled_kw_arg_typed("number to divide", &RuntimeType::num_any(), exec_state)?;
|
|
let d: TyF64 = args.get_kw_arg_typed("divisor", &RuntimeType::num_any(), exec_state)?;
|
|
|
|
let (n, d, ty) = NumericType::combine_div(n, d);
|
|
if ty == NumericType::Unknown {
|
|
exec_state.err(CompilationError::err(
|
|
args.source_range,
|
|
"Calling `rem` on numbers which have unknown or incompatible units.\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`"
|
|
));
|
|
}
|
|
let remainder = inner_rem(n, d);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(remainder, ty)))
|
|
}
|
|
|
|
/// Compute the remainder after dividing `num` by `div`.
|
|
/// If `num` is negative, the result will be too.
|
|
///
|
|
/// ```no_run
|
|
/// assert(rem( 7, divisor = 4), isEqualTo = 3, error = "remainder is 3")
|
|
/// assert(rem(-7, divisor = 4), isEqualTo = -3, error = "remainder is -3")
|
|
/// assert(rem( 7, divisor = -4), isEqualTo = 3, error = "remainder is 3")
|
|
/// assert(rem( 6, divisor = 2.5), isEqualTo = 1, error = "remainder is 1")
|
|
/// assert(rem( 6.5, divisor = 2.5), isEqualTo = 1.5, error = "remainder is 1.5")
|
|
/// assert(rem( 6.5, divisor = 2), isEqualTo = 0.5, error = "remainder is 0.5")
|
|
/// ```
|
|
#[stdlib {
|
|
name = "rem",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
num = {docs = "The number which will be divided by `divisor`."},
|
|
divisor = {docs = "The number which will divide `num`."},
|
|
}
|
|
}]
|
|
fn inner_rem(num: f64, divisor: f64) -> f64 {
|
|
num % divisor
|
|
}
|
|
|
|
/// Compute the cosine of a number (in radians).
|
|
pub async fn cos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
|
|
let num = num.to_radians();
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.cos())))
|
|
}
|
|
|
|
/// Compute the sine of a number (in radians).
|
|
pub async fn sin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
|
|
let num = num.to_radians();
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.sin())))
|
|
}
|
|
|
|
/// Compute the tangent of a number (in radians).
|
|
pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
|
|
let num = num.to_radians();
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.tan())))
|
|
}
|
|
|
|
/// Compute the square root of a number.
|
|
pub async fn sqrt(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_sqrt(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the square root of a number.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = 50,
|
|
/// length = sqrt(2500),
|
|
/// )
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "sqrt",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute the square root of."},
|
|
}
|
|
}]
|
|
fn inner_sqrt(input: f64) -> f64 {
|
|
input.sqrt()
|
|
}
|
|
|
|
/// Compute the absolute value of a number.
|
|
pub async fn abs(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_abs(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
|
|
}
|
|
|
|
/// Compute the absolute value of a number.
|
|
///
|
|
/// ```no_run
|
|
/// myAngle = -120
|
|
///
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(end = [8, 0])
|
|
/// |> angledLine(
|
|
/// angle = abs(myAngle),
|
|
/// length = 5,
|
|
/// )
|
|
/// |> line(end = [-5, 0])
|
|
/// |> angledLine(
|
|
/// angle = myAngle,
|
|
/// length = 5,
|
|
/// )
|
|
/// |> close()
|
|
///
|
|
/// baseExtrusion = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "abs",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute the absolute value of."},
|
|
}
|
|
}]
|
|
fn inner_abs(input: f64) -> f64 {
|
|
input.abs()
|
|
}
|
|
|
|
/// Round a number to the nearest integer.
|
|
pub async fn round(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_round(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
|
|
}
|
|
|
|
/// Round a number to the nearest integer.
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(endAbsolute = [12, 10])
|
|
/// |> line(end = [round(7.02986), 0])
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "round",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to round."},
|
|
}
|
|
}]
|
|
fn inner_round(input: f64) -> f64 {
|
|
input.round()
|
|
}
|
|
|
|
/// Compute the largest integer less than or equal to a number.
|
|
pub async fn floor(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_floor(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
|
|
}
|
|
|
|
/// Compute the largest integer less than or equal to a number.
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(endAbsolute = [12, 10])
|
|
/// |> line(end = [floor(7.02986), 0])
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "floor",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to round."},
|
|
}
|
|
}]
|
|
fn inner_floor(input: f64) -> f64 {
|
|
input.floor()
|
|
}
|
|
|
|
/// Compute the smallest integer greater than or equal to a number.
|
|
pub async fn ceil(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_ceil(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(input.map_value(result)))
|
|
}
|
|
|
|
/// Compute the smallest integer greater than or equal to a number.
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(endAbsolute = [12, 10])
|
|
/// |> line(end = [ceil(7.02986), 0])
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "ceil",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to round."},
|
|
}
|
|
}]
|
|
fn inner_ceil(input: f64) -> f64 {
|
|
input.ceil()
|
|
}
|
|
|
|
/// Compute the minimum of the given arguments.
|
|
pub async fn min(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg_typed(
|
|
"input",
|
|
&RuntimeType::Array(Box::new(RuntimeType::num_any()), ArrayLen::None),
|
|
exec_state,
|
|
)?;
|
|
let (nums, ty) = NumericType::combine_eq_array(&nums);
|
|
if ty == NumericType::Unknown {
|
|
exec_state.warn(CompilationError::err(
|
|
args.source_range,
|
|
"Calling `min` on numbers which have unknown or incompatible units.\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`",
|
|
));
|
|
}
|
|
let result = inner_min(nums);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, ty)))
|
|
}
|
|
|
|
/// Compute the minimum of the given arguments.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = 70,
|
|
/// length = min([15, 31, 4, 13, 22])
|
|
/// )
|
|
/// |> line(end = [20, 0])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "min",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "An array of numbers to compute the minimum of."},
|
|
}
|
|
}]
|
|
fn inner_min(input: Vec<f64>) -> f64 {
|
|
let mut min = f64::MAX;
|
|
for num in input.iter() {
|
|
if *num < min {
|
|
min = *num;
|
|
}
|
|
}
|
|
|
|
min
|
|
}
|
|
|
|
/// Compute the maximum of the given arguments.
|
|
pub async fn max(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let nums: Vec<TyF64> = args.get_unlabeled_kw_arg_typed(
|
|
"input",
|
|
&RuntimeType::Array(Box::new(RuntimeType::num_any()), ArrayLen::None),
|
|
exec_state,
|
|
)?;
|
|
let (nums, ty) = NumericType::combine_eq_array(&nums);
|
|
if ty == NumericType::Unknown {
|
|
exec_state.warn(CompilationError::err(
|
|
args.source_range,
|
|
"Calling `max` on numbers which have unknown or incompatible units.\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`",
|
|
));
|
|
}
|
|
let result = inner_max(nums);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, ty)))
|
|
}
|
|
|
|
/// Compute the maximum of the given arguments.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = 70,
|
|
/// length = max([15, 31, 4, 13, 22])
|
|
/// )
|
|
/// |> line(end = [20, 0])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "max",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "An array of numbers to compute the maximum of."},
|
|
}
|
|
}]
|
|
fn inner_max(input: Vec<f64>) -> f64 {
|
|
let mut max = f64::MIN;
|
|
for num in input.iter() {
|
|
if *num > max {
|
|
max = *num;
|
|
}
|
|
}
|
|
|
|
max
|
|
}
|
|
|
|
/// Compute the number to a power.
|
|
pub async fn pow(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let exp: TyF64 = args.get_kw_arg_typed("exp", &RuntimeType::count(), exec_state)?;
|
|
let result = inner_pow(input.n, exp.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the number to a power.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = 50,
|
|
/// length = pow(5, exp = 2),
|
|
/// )
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "pow",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to raise."},
|
|
exp = {docs = "The power to raise to."},
|
|
}
|
|
}]
|
|
fn inner_pow(input: f64, exp: f64) -> f64 {
|
|
input.powf(exp)
|
|
}
|
|
|
|
/// Compute the arccosine of a number (in radians).
|
|
pub async fn acos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
|
|
let result = inner_acos(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
|
|
}
|
|
|
|
/// Compute the arccosine of a number (in radians).
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = units::toDegrees(acos(0.5)),
|
|
/// length = 10,
|
|
/// )
|
|
/// |> line(end = [5, 0])
|
|
/// |> line(endAbsolute = [12, 0])
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "acos",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute arccosine of."},
|
|
}
|
|
}]
|
|
fn inner_acos(input: f64) -> f64 {
|
|
input.acos()
|
|
}
|
|
|
|
/// Compute the arcsine of a number (in radians).
|
|
pub async fn asin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
|
|
let result = inner_asin(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
|
|
}
|
|
|
|
/// Compute the arcsine of a number (in radians).
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = units::toDegrees(asin(0.5)),
|
|
/// length = 20,
|
|
/// )
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "asin",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute arcsine of."},
|
|
}
|
|
}]
|
|
fn inner_asin(input: f64) -> f64 {
|
|
input.asin()
|
|
}
|
|
|
|
/// Compute the arctangent of a number (in radians).
|
|
pub async fn atan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::count(), exec_state)?;
|
|
let result = inner_atan(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
|
|
}
|
|
|
|
/// Compute the arctangent of a number (in radians).
|
|
///
|
|
/// Consider using `atan2()` instead for the true inverse of tangent.
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn('XZ')
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = units::toDegrees(atan(1.25)),
|
|
/// length = 20,
|
|
/// )
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "atan",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute arctangent of."},
|
|
}
|
|
}]
|
|
fn inner_atan(input: f64) -> f64 {
|
|
input.atan()
|
|
}
|
|
|
|
/// Compute the four quadrant arctangent of Y and X (in radians).
|
|
pub async fn atan2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let y = args.get_kw_arg_typed("y", &RuntimeType::length(), exec_state)?;
|
|
let x = args.get_kw_arg_typed("x", &RuntimeType::length(), exec_state)?;
|
|
let (y, x, _) = NumericType::combine_eq_coerce(y, x);
|
|
let result = inner_atan2(y, x);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
|
|
}
|
|
|
|
/// Compute the four quadrant arctangent of Y and X (in radians).
|
|
///
|
|
/// ```no_run
|
|
/// sketch001 = startSketchOn(XZ)
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> angledLine(
|
|
/// angle = units::toDegrees(atan2(y = 1.25, x = 2)),
|
|
/// length = 20,
|
|
/// )
|
|
/// |> yLine(endAbsolute = 0)
|
|
/// |> close()
|
|
///
|
|
/// extrude001 = extrude(sketch001, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "atan2",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = false,
|
|
args = {
|
|
y = { docs = "Y"},
|
|
x = { docs = "X"},
|
|
}
|
|
}]
|
|
fn inner_atan2(y: f64, x: f64) -> f64 {
|
|
y.atan2(x)
|
|
}
|
|
|
|
/// Compute the logarithm of the number with respect to an arbitrary base.
|
|
///
|
|
/// The result might not be correctly rounded owing to implementation
|
|
/// details; `log2()` can produce more accurate results for base 2,
|
|
/// and `log10()` can produce more accurate results for base 10.
|
|
pub async fn log(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let base: TyF64 = args.get_kw_arg_typed("base", &RuntimeType::count(), exec_state)?;
|
|
let result = inner_log(input.n, base.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the logarithm of the number with respect to an arbitrary base.
|
|
///
|
|
/// The result might not be correctly rounded owing to implementation
|
|
/// details; `log2()` can produce more accurate results for base 2,
|
|
/// and `log10()` can produce more accurate results for base 10.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(end = [log(100, base = 5), 0])
|
|
/// |> line(end = [5, 8])
|
|
/// |> line(end = [-10, 0])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "log",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute the logarithm of."},
|
|
base = {docs = "The base of the logarithm."},
|
|
}
|
|
}]
|
|
fn inner_log(input: f64, base: f64) -> f64 {
|
|
input.log(base)
|
|
}
|
|
|
|
/// Compute the base 2 logarithm of the number.
|
|
pub async fn log2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_log2(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the base 2 logarithm of the number.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(end = [log2(100), 0])
|
|
/// |> line(end = [5, 8])
|
|
/// |> line(end = [-10, 0])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "log2",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute the logarithm of."},
|
|
}
|
|
}]
|
|
fn inner_log2(input: f64) -> f64 {
|
|
input.log2()
|
|
}
|
|
|
|
/// Compute the base 10 logarithm of the number.
|
|
pub async fn log10(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_log10(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the base 10 logarithm of the number.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(end = [log10(100), 0])
|
|
/// |> line(end = [5, 8])
|
|
/// |> line(end = [-10, 0])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "log10",
|
|
tags = ["math"],
|
|
}]
|
|
fn inner_log10(num: f64) -> f64 {
|
|
num.log10()
|
|
}
|
|
|
|
/// Compute the natural logarithm of the number.
|
|
pub async fn ln(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
let input: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::num_any(), exec_state)?;
|
|
let result = inner_ln(input.n);
|
|
|
|
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, exec_state.current_default_units())))
|
|
}
|
|
|
|
/// Compute the natural logarithm of the number.
|
|
///
|
|
/// ```no_run
|
|
/// exampleSketch = startSketchOn("XZ")
|
|
/// |> startProfile(at = [0, 0])
|
|
/// |> line(end = [ln(100), 15])
|
|
/// |> line(end = [5, -6])
|
|
/// |> line(end = [-10, -10])
|
|
/// |> close()
|
|
///
|
|
/// example = extrude(exampleSketch, length = 5)
|
|
/// ```
|
|
#[stdlib {
|
|
name = "ln",
|
|
tags = ["math"],
|
|
keywords = true,
|
|
unlabeled_first = true,
|
|
args = {
|
|
input = {docs = "The number to compute the logarithm of."},
|
|
}
|
|
}]
|
|
fn inner_ln(input: f64) -> f64 {
|
|
input.ln()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_inner_max() {
|
|
let nums = vec![4.0, 5.0, 6.0];
|
|
let result = inner_max(nums);
|
|
assert_eq!(result, 6.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inner_max_with_neg() {
|
|
let nums = vec![4.0, -5.0];
|
|
let result = inner_max(nums);
|
|
assert_eq!(result, 4.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inner_min() {
|
|
let nums = vec![4.0, 5.0, 6.0];
|
|
let result = inner_min(nums);
|
|
assert_eq!(result, 4.0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inner_min_with_neg() {
|
|
let nums = vec![4.0, -5.0];
|
|
let result = inner_min(nums);
|
|
assert_eq!(result, -5.0);
|
|
}
|
|
}
|