mirror of
https://github.com/c3d/DB48X-on-DM42.git
synced 2024-09-28 03:20:53 +02:00
expressions: Accept algebraic forms for integrate
and root
Acceptable syntaxes: - `‘integrate(1;2;sin(X);X)’` or `‘∫(1;2;sin(X);X)’` - `‘root(sin(X)-0.5;X;1)’` Fixes: #1172 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
parent
8330601303
commit
b8d2be1425
7 changed files with 91 additions and 63 deletions
|
@ -1235,7 +1235,7 @@ static algebraic_p sum_product(object::id op,
|
|||
|
||||
if (!expr->is_program())
|
||||
{
|
||||
rt.type_error();
|
||||
rt.invalid_equation_error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -369,6 +369,8 @@ NAMED(comb, "Combinations")
|
|||
NAMED(perm, "Permutations")
|
||||
NAMED(Sum, "Σ")
|
||||
NAMED(Product, "∏")
|
||||
CMD(Root)
|
||||
NAMED(Integrate, "∫")
|
||||
|
||||
NAMED(cbrt, "∛") ALIAS(cbrt, "CubeRoot")
|
||||
OP(hypot, "⊿") ALIAS(hypot, "Hypothenuse")
|
||||
|
@ -583,10 +585,6 @@ CMD(TypeName)
|
|||
CMD(Version)
|
||||
CMD(ScreenCapture)
|
||||
|
||||
// High-level applications
|
||||
CMD(Root)
|
||||
NAMED(Integrate, "∫")
|
||||
|
||||
// Special arithmetic
|
||||
NAMED(Div2, "QuoRem") ALIAS(Div2, "IDiv2")
|
||||
ALIAS(Div2, "QuotientRemainder")
|
||||
|
|
|
@ -45,24 +45,29 @@ RECORDER(integrate, 16, "Numerical integration");
|
|||
RECORDER(integrate_error, 16, "Numerical integrationsol");
|
||||
|
||||
|
||||
COMMAND_BODY(Integrate)
|
||||
NFUNCTION_BODY(Integrate)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Numerical integration
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
object_g variable = rt.stack(0);
|
||||
object_g eqobj = rt.stack(1);
|
||||
object_g high = rt.stack(2);
|
||||
object_g low = rt.stack(3);
|
||||
if (!eqobj || !variable || !high || !low)
|
||||
return ERROR;
|
||||
if (arity != 4)
|
||||
{
|
||||
rt.internal_error();
|
||||
return nullptr;
|
||||
}
|
||||
algebraic_g &variable = args[0];
|
||||
algebraic_g &eqobj = args[1];
|
||||
algebraic_g &high = args[2];
|
||||
algebraic_g &low = args[3];
|
||||
|
||||
record(integrate,
|
||||
"Integrating %t for variable %t in range %t-%t",
|
||||
+eqobj,
|
||||
+variable,
|
||||
+low,
|
||||
+high);
|
||||
if (!eqobj->is_program())
|
||||
{
|
||||
rt.invalid_equation_error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
record(integrate, "Integrating %t for variable %t in range %t-%t",
|
||||
+eqobj, +variable, +low, +high);
|
||||
|
||||
// Check that we have a variable name on stack level 1 and
|
||||
// a proram or equation on level 2
|
||||
|
@ -70,30 +75,22 @@ COMMAND_BODY(Integrate)
|
|||
id eqty = eqobj->type();
|
||||
if (eqty == ID_equation)
|
||||
{
|
||||
eqobj = equation_p(+eqobj)->value();
|
||||
if (!eqobj)
|
||||
return ERROR;
|
||||
eqobj = algebraic_p(equation_p(+eqobj)->value());
|
||||
if (!eqobj || !eqobj->is_algebraic())
|
||||
return nullptr;
|
||||
eqty = eqobj->type();
|
||||
}
|
||||
if (eqty != ID_program && eqty != ID_expression)
|
||||
name = nullptr;
|
||||
if (!name || !low->is_algebraic() || !high->is_algebraic())
|
||||
if ((eqty != ID_program && eqty != ID_expression) ||
|
||||
!name || !low->is_algebraic() || !high->is_algebraic())
|
||||
{
|
||||
rt.type_error();
|
||||
return ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Drop input parameters
|
||||
rt.drop(4);
|
||||
|
||||
// Actual integration
|
||||
program_g eq = program_p(+eqobj);
|
||||
algebraic_g intg =
|
||||
integrate(eq, name, algebraic_p(+low), algebraic_p(+high));
|
||||
if (intg&& rt.push(+intg))
|
||||
return OK;
|
||||
|
||||
return ERROR;
|
||||
algebraic_g i = integrate(eq, name, algebraic_p(+low), algebraic_p(+high));
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
// ****************************************************************************
|
||||
|
||||
#include "algebraic.h"
|
||||
#include "command.h"
|
||||
#include "functions.h"
|
||||
#include "symbol.h"
|
||||
|
||||
algebraic_p integrate(program_g eq,
|
||||
|
@ -38,6 +38,11 @@ algebraic_p integrate(program_g eq,
|
|||
algebraic_g low,
|
||||
algebraic_g high);
|
||||
|
||||
COMMAND_DECLARE(Integrate,4);
|
||||
NFUNCTION(Integrate, 4,
|
||||
static bool can_be_symbolic(uint a)
|
||||
{
|
||||
return a == 0 || a == 1;
|
||||
}
|
||||
);
|
||||
|
||||
#endif // INTEGRATE_H
|
||||
|
|
47
src/solve.cc
47
src/solve.cc
|
@ -49,22 +49,24 @@ RECORDER(solve, 16, "Numerical solver");
|
|||
RECORDER(solve_error, 16, "Numerical solver errors");
|
||||
|
||||
|
||||
COMMAND_BODY(Root)
|
||||
NFUNCTION_BODY(Root)
|
||||
// ----------------------------------------------------------------------------
|
||||
// Numerical solver
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
object_g eqobj = rt.stack(2);
|
||||
object_g variable = rt.stack(1);
|
||||
object_g guess = rt.stack(0);
|
||||
if (arity != 3)
|
||||
{
|
||||
rt.internal_error();
|
||||
return nullptr;
|
||||
}
|
||||
algebraic_g &eqobj = args[2];
|
||||
algebraic_g &variable = args[1];
|
||||
algebraic_g &guess = args[0];
|
||||
if (!eqobj || !variable || !guess)
|
||||
return ERROR;
|
||||
return nullptr;
|
||||
|
||||
record(solve,
|
||||
"Solving %t for variable %t with guess %t",
|
||||
+eqobj,
|
||||
+variable,
|
||||
+guess);
|
||||
record(solve, "Solving %t for variable %t with guess %t",
|
||||
+eqobj, +variable, +guess);
|
||||
|
||||
// Check that we have a variable name on stack level 1 and
|
||||
// a proram or equation on level 2
|
||||
|
@ -72,40 +74,35 @@ COMMAND_BODY(Root)
|
|||
id eqty = eqobj->type();
|
||||
if (eqty == ID_equation)
|
||||
{
|
||||
eqobj = equation_p(+eqobj)->value();
|
||||
if (!eqobj)
|
||||
return ERROR;
|
||||
eqobj = algebraic_p(equation_p(+eqobj)->value());
|
||||
if (!eqobj || !eqobj->is_algebraic())
|
||||
return nullptr;
|
||||
eqty = eqobj->type();
|
||||
}
|
||||
if (eqty != ID_program && eqty != ID_expression)
|
||||
name = nullptr;
|
||||
if (!name)
|
||||
if ((eqty != ID_program && eqty != ID_expression) || !name)
|
||||
{
|
||||
rt.type_error();
|
||||
return ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Drop input parameters
|
||||
rt.drop(3);
|
||||
|
||||
if (!eqobj->is_program())
|
||||
{
|
||||
rt.invalid_equation_error();
|
||||
return ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Actual solving
|
||||
program_g eq = program_p(+eqobj);
|
||||
if (algebraic_g x = solve(eq, +name, guess))
|
||||
if (algebraic_g x = solve(eq, +name, +guess))
|
||||
{
|
||||
size_t nlen = 0;
|
||||
gcutf8 ntxt = name->value(&nlen);
|
||||
object_g top = tag::make(ntxt, nlen, +x);
|
||||
if (rt.push(top))
|
||||
return rt.error() ? ERROR : OK;
|
||||
if (top && !rt.error())
|
||||
return algebraic_p(+top);
|
||||
}
|
||||
|
||||
return ERROR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,13 +30,18 @@
|
|||
// ****************************************************************************
|
||||
|
||||
#include "algebraic.h"
|
||||
#include "command.h"
|
||||
#include "functions.h"
|
||||
#include "menu.h"
|
||||
#include "symbol.h"
|
||||
|
||||
algebraic_p solve(program_g eq, algebraic_g name, object_g guess);
|
||||
|
||||
COMMAND_DECLARE(Root,3);
|
||||
NFUNCTION(Root,3,
|
||||
static bool can_be_symbolic(uint a)
|
||||
{
|
||||
return a == 1 || a == 2;
|
||||
}
|
||||
);
|
||||
|
||||
COMMAND_DECLARE(StEq, 1);
|
||||
COMMAND_DECLARE(RcEq, 0);
|
||||
|
|
26
src/tests.cc
26
src/tests.cc
|
@ -5687,6 +5687,11 @@ void tests::solver_testing()
|
|||
step("Solver with expression")
|
||||
.test(CLEAR, "'X+3' 'X' 0 ROOT", ENTER)
|
||||
.noerror().expect("X:-3.");
|
||||
step("Solver with arithmetic syntax")
|
||||
.test(CLEAR, "'ROOT(X+3;X;0)'", ENTER)
|
||||
.expect("'Root(X+3;X;0)'")
|
||||
.test(RUNSTOP)
|
||||
.expect("X:-3.");
|
||||
step("Solver with equation")
|
||||
.test(CLEAR, "'sq(x)=3' 'X' 0 ROOT", ENTER)
|
||||
.noerror().expect("X:1.73205 08075 7");
|
||||
|
@ -5949,6 +5954,27 @@ void tests::numerical_integration_testing()
|
|||
.test("'sq(Z)+Z'", ENTER).expect("'Z²+Z'")
|
||||
.test(F, ALPHA, Z, ENTER).expect("'Z'")
|
||||
.test(SHIFT, KEY8, F2).expect("8.83333 33333 3", 350);
|
||||
step("Integrate with symbols")
|
||||
.test(CLEAR, "A B '1/X' 'X' INTEGRATE", ENTER)
|
||||
.expect("'∫(A;B;1÷X;X)'")
|
||||
.test(DOWN)
|
||||
.editor("'∫(A;B;1÷X;X)'")
|
||||
.test(ENTER)
|
||||
.expect("'∫(A;B;1÷X;X)'");
|
||||
step("Integrate with one symbol")
|
||||
.test(CLEAR, "1 B '1/X' 'X' INTEGRATE", ENTER)
|
||||
.expect("'∫(1;B;1÷X;X)'")
|
||||
.test(DOWN)
|
||||
.editor("'∫(1;B;1÷X;X)'")
|
||||
.test(ENTER)
|
||||
.expect("'∫(1;B;1÷X;X)'");
|
||||
step("Integrate with second symbol")
|
||||
.test(CLEAR, "A 1 '1/X' 'X' INTEGRATE", ENTER)
|
||||
.expect("'∫(A;1;1÷X;X)'")
|
||||
.test(DOWN)
|
||||
.editor("'∫(A;1;1÷X;X)'")
|
||||
.test(ENTER)
|
||||
.expect("'∫(A;1;1÷X;X)'");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue