mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-31 08:59:15 +01:00
Integration estimation
Needs more a bit more accuracy though. Currently the n value in the trapezoidal rule is fixed.
This commit is contained in:
parent
439f732013
commit
651b289f4b
@ -302,6 +302,79 @@ fn eval_fn_call_expr(
|
||||
|
||||
return Ok(sum);
|
||||
}
|
||||
"integrate" | "∫" => {
|
||||
// Make sure exactly 3 arguments were supplied.
|
||||
if expressions.len() != 3 {
|
||||
return Err(CalcError::IncorrectAmountOfArguments(
|
||||
3,
|
||||
"integrate".into(),
|
||||
expressions.len(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut result = KalkNum::default();
|
||||
let mut integration_variable: Option<&str> = None;
|
||||
|
||||
// integral(a, b, expr dx)
|
||||
if let Expr::Binary(_, TokenKind::Star, right) = &expressions[2] {
|
||||
if let Expr::Var(right_name) = &**right {
|
||||
if right_name.starts_with("d") {
|
||||
// Take the value, but remove the d, so that only eg. x is left from dx
|
||||
integration_variable = Some(&right_name[1..]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if integration_variable.is_none() {
|
||||
unimplemented!(); // TODO: Error message
|
||||
}
|
||||
|
||||
// delta_x/2[f(a) + 2f(x_1) + 2f(x_2) + ...2f(x_n) + f(b)]
|
||||
// where delta_x = (b - a) / n
|
||||
// and x_n = a + i * delta_x
|
||||
|
||||
// f(a)
|
||||
context.symbol_table.set(Stmt::VarDecl(
|
||||
integration_variable.unwrap().into(),
|
||||
Box::new(expressions[0].clone()),
|
||||
));
|
||||
|
||||
// "dx" is still in the expression. Set dx = 1, so that it doesn't affect the expression value.
|
||||
context.symbol_table.set(Stmt::VarDecl(
|
||||
String::from("dx"),
|
||||
Box::new(Expr::Literal(1f64)),
|
||||
));
|
||||
|
||||
result.value += eval_expr(context, &expressions[2], "")?.value;
|
||||
|
||||
// 2f(x_n)
|
||||
// where x_n = a + i * delta_x
|
||||
const N: i32 = 100;
|
||||
let a = eval_expr(context, &expressions[0], "")?.value.to_f64();
|
||||
let b = eval_expr(context, &expressions[1], "")?.value.to_f64();
|
||||
let delta_x = (b - a) / N as f64;
|
||||
for i in 1..N {
|
||||
context.symbol_table.set(Stmt::VarDecl(
|
||||
integration_variable.unwrap().into(),
|
||||
Box::new(Expr::Literal(a + i as f64 * delta_x)),
|
||||
));
|
||||
|
||||
// 2f(x_n)
|
||||
result.value += 2 * eval_expr(context, &expressions[2], "")?.value;
|
||||
}
|
||||
|
||||
// f(b)
|
||||
context.symbol_table.set(Stmt::VarDecl(
|
||||
integration_variable.unwrap().into(),
|
||||
Box::new(expressions[1].clone()),
|
||||
));
|
||||
result.value += eval_expr(context, &expressions[2], "")?.value;
|
||||
|
||||
// Finally, delta_x/2 for all of it
|
||||
result.value *= delta_x / 2f64;
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@ -550,4 +623,22 @@ mod tests {
|
||||
|
||||
assert_eq!(interpret(stmt).unwrap().unwrap().to_f64(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integrate_fn() {
|
||||
let stmt = Stmt::Expr(fn_call(
|
||||
"integrate",
|
||||
vec![
|
||||
*literal(2f64),
|
||||
*literal(4f64),
|
||||
*binary(
|
||||
binary(var("x"), TokenKind::Power, literal(3f64)),
|
||||
TokenKind::Star,
|
||||
binary(var("d"), TokenKind::Star, var("x")),
|
||||
),
|
||||
],
|
||||
));
|
||||
|
||||
assert!((interpret(stmt).unwrap().unwrap().to_f64() - 60f64).abs() < 1f64);
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ pub struct Context {
|
||||
parsing_identifier_stmt: bool,
|
||||
equation_variable: Option<String>,
|
||||
contains_equal_sign: bool,
|
||||
is_in_integral: bool,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@ -46,6 +47,7 @@ impl Context {
|
||||
parsing_identifier_stmt: false,
|
||||
equation_variable: None,
|
||||
contains_equal_sign: false,
|
||||
is_in_integral: false,
|
||||
};
|
||||
|
||||
parse(&mut context, crate::prelude::INIT).unwrap();
|
||||
@ -491,6 +493,10 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
if !parse_as_var_instead && match_token(context, TokenKind::OpenParenthesis) {
|
||||
advance(context);
|
||||
|
||||
if identifier.value == "integrate" || identifier.value == "∫" {
|
||||
context.is_in_integral = true;
|
||||
}
|
||||
|
||||
let mut parameters = Vec::new();
|
||||
parameters.push(parse_expr(context)?);
|
||||
|
||||
@ -500,10 +506,16 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
}
|
||||
|
||||
consume(context, TokenKind::ClosedParenthesis)?;
|
||||
context.is_in_integral = false;
|
||||
|
||||
return Ok(Expr::FnCall(identifier.value, parameters));
|
||||
}
|
||||
|
||||
// Eg. dx inside an integral, should be parsed as *one* identifier
|
||||
if context.is_in_integral && identifier.value.starts_with("d") {
|
||||
return Ok(Expr::Var(identifier.value));
|
||||
}
|
||||
|
||||
// Eg. x
|
||||
if parse_as_var_instead || context.symbol_table.contains_var(&identifier.value) {
|
||||
Ok(Expr::Var(identifier.value))
|
||||
|
@ -35,6 +35,8 @@ impl BinaryFuncInfo {
|
||||
pub fn is_prelude_func(identifier: &str) -> bool {
|
||||
identifier == "sum"
|
||||
|| identifier == "Σ"
|
||||
|| identifier == "integrate"
|
||||
|| identifier == "∫"
|
||||
|| UNARY_FUNCS.contains_key(identifier)
|
||||
|| BINARY_FUNCS.contains_key(identifier)
|
||||
}
|
||||
|
@ -42,6 +42,8 @@ impl BinaryFuncInfo {
|
||||
pub fn is_prelude_func(identifier: &str) -> bool {
|
||||
identifier == "sum"
|
||||
|| identifier == "Σ"
|
||||
|| identifier == "integrate"
|
||||
|| identifier == "∫"
|
||||
|| UNARY_FUNCS.contains_key(identifier)
|
||||
|| BINARY_FUNCS.contains_key(identifier)
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ lazy_static! {
|
||||
m.insert("floor", "⌊⌋");
|
||||
m.insert("gamma", "Γ");
|
||||
m.insert("sum", "Σ()");
|
||||
m.insert("integrate", "∫()");
|
||||
m.insert("phi", "ϕ");
|
||||
m.insert("pi", "π");
|
||||
m.insert("sqrt", "√");
|
||||
@ -143,6 +144,7 @@ impl Completer for RLHelper {
|
||||
line.insert_str(line.pos(), elected);
|
||||
line.move_forward(match elected {
|
||||
"Σ()" => 2,
|
||||
"∫()" => 2,
|
||||
_ => 1,
|
||||
});
|
||||
}
|
||||
|
@ -177,6 +177,9 @@
|
||||
} else if (input == "Σ") {
|
||||
input += "()";
|
||||
movementOffset = 2;
|
||||
} else if (input == "∫") {
|
||||
input += "()";
|
||||
movementOffset = 2;
|
||||
} else if (input == "⌊") {
|
||||
input += "⌋";
|
||||
} else if (input == "⌈") {
|
||||
@ -283,6 +286,10 @@
|
||||
newSubstring = "Σ";
|
||||
break;
|
||||
}
|
||||
case "integrate": {
|
||||
newSubstring = "∫";
|
||||
break;
|
||||
}
|
||||
case "pi": {
|
||||
newSubstring = "π";
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user