#include #include "uCalc.h" using namespace std; using namespace uCalcSoftware; void ucalc_call EqSolveCb(uCalcBase::Callback cb) { // Callback based on the Bisection Method auto expr = cb.ArgExpr(1); // ByExpr: Unevaluated Expression object (lazy evaluation) auto a = cb.Arg(2); // Argument 2: Range Minimum auto b = cb.Arg(3); // Argument 3: Range Maximum auto variable = cb.ArgItem(4); // ByHandle: The variable Item object // Helper to update the variable in the uCalc engine and evaluate the expression auto EvaluateAt = [&](double val) -> double { variable.Value(val); return expr.Evaluate(); }; // Ensure f(a) < f(b) so we always know which direction to slide the bounds; swap a & b if necessary if (EvaluateAt(b) < EvaluateAt(a)) swap(a, b); auto midpoint = 0.0; auto fMidpoint = 0.0; // Bisection loop for (int i = 0; i <= 100; i++) { midpoint = (a + b) / 2; fMidpoint = EvaluateAt(midpoint); if (abs(fMidpoint) < 1e-7) break; // Stop if close enough to 0 // Narrow the bounds (compact logic!) if (fMidpoint < 0) a = midpoint; else b = midpoint; } if (abs(fMidpoint) > 1e-5) cb.Error().Raise("No solution found in the given range."); cb.Return(round(midpoint * 10000000.0) / 10000000.0); // Return the final solved value } int main() { uCalc uc; // 1. Define variables that might be used by the end-user uc.DefineVariable("x"); uc.DefineVariable("MyVar"); // 2. Transformer converts `EqSolve(L = R)` into `EqSolve(L - (R))` & sets defaults before it hits the parser auto t = uc.ExpressionTransformer(); t.FromTo("EqSolve({L} = {R} [[,]for {var}][, {min}, {max}])", "EqSolve({L} - ({R}), {min}{!min:-10000}, {max}{!max: 10000}, {var}{!var: x})"); // 3. Define the custom function signature uc.DefineFunction("EqSolve(ByExpr eq, min, max, ByHandle variable)", EqSolveCb); // --- Demo Executions --- vector eqList = { "EqSolve(x + 5 = 125)", // Using default range [-10000,10000] "EqSolve(x^2 + 5 = 105)", // Picks one result from the default range "EqSolve(x^2 + 5 = 105, 0, 100)", // Restricts to positive root "EqSolve(x^2 + 5 = 105, -100, 0)", // Restricts to negative root "EqSolve(x^2 + 1000 = 5)", // No existing solution "EqSolve(40 + MyVar * 6 = 88, for MyVar)" // Uses custom variable 'MyVar' instead of 'x' }; for(auto eq : eqList) { cout << uc.ExpressionTransformer().Transform(eq) << endl; // Displays transformed expression cout << "Result: " << uc.EvalStr(eq) << endl; // Returns result } }