Retrieves the full metadata object for a specific argument passed to a callback function.
Product:
Class:
Warning
uCalc API Preview Release Notice:The uCalc engine has successfully transitioned to modern cross-platform environments.The next phase envolves some structural changes, performance optimizations, and API refinements.The API is subject to breaking changes prior to the stable release. Please evaluate the preview version thoroughly before production use.
Returns the Item object for the specified argument, providing access to its metadata such as name, data type, and underlying value pointer. Returns an empty item if the index is out of bounds.
The ArgItem method is the primary tool for introspection within a callback. While other Arg* functions (Arg(), ArgStr(), etc.) return the value of an argument, ArgItem returns the argument's underlying Item object. This gives you access to a wealth of metadata, allowing you to build highly dynamic and context-aware functions.
Arg() vs. ArgItem()| Method | Returns | Use Case |
|---|---|---|
cb.Arg(1) | double (the value) | Simple numeric calculations. |
cb.ArgStr(1) | string (the value) | Simple string manipulation. |
cb.ArgItem(1) | Item (the object) | Accessing metadata: name, data type, original expression, value pointer. |
ByHandle and ByRef ArgumentsThis is the most common use case. When a parameter is defined with ByHandle, its Item object is passed instead of its value. ArgItem is the only way to retrieve this object.
...)For functions that accept a variable number of arguments, ArgItem allows you to loop through each argument and inspect its type and value, enabling you to create flexible functions like Sum() or Print().
By accessing an argument's metadata, you can change your function's behavior based on the caller's context. For example, you can check if an argument was a literal constant or a variable and process it differently.
vs. Reflection (C# ParameterInfo, Java Parameter):ArgItem provides functionality similar to reflection APIs in other languages but is more lightweight and integrated directly into the evaluation flow. Retrieving metadata is a simple method call, avoiding the complexity of navigating MethodInfo or Assembly objects.
vs. Dynamic Languages (Python *args, **kwargs):ArgItem brings the introspective power of dynamic languages into uCalc's strongly-typed (but flexible) environment. It provides a structured way to inspect arguments that is safer than simple type-checking in a fully dynamic context.
ID: 13
using uCalcSoftware;
var uc = new uCalc();
static void DisplayArgs(uCalc.Callback cb) {
for (int x = 1; x <= cb.ArgCount(); x++) {
Console.WriteLine(cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType.Name);
}
}
uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs);
uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))");
5 Type: double
3+2i Type: complex
Hello Type: string
true Type: bool
false Type: bool
9 Type: int16 using uCalcSoftware; var uc = new uCalc(); static void DisplayArgs(uCalc.Callback cb) { for (int x = 1; x <= cb.ArgCount(); x++) { Console.WriteLine(cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType.Name); } } uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs); uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))");
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
void ucalc_call DisplayArgs(uCalcBase::Callback cb) {
for (int x = 1; x <= cb.ArgCount(); x++) {
cout << cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType().Name() << endl;
}
}
int main() {
uCalc uc;
uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs);
uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))");
}
5 Type: double
3+2i Type: complex
Hello Type: string
true Type: bool
false Type: bool
9 Type: int16 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; void ucalc_call DisplayArgs(uCalcBase::Callback cb) { for (int x = 1; x <= cb.ArgCount(); x++) { cout << cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType().Name() << endl; } } int main() { uCalc uc; uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", DisplayArgs); uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))"); }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub DisplayArgs(ByVal cb As uCalc.Callback)
For x As Integer = 1 To cb.ArgCount()
Console.WriteLine(cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType.Name)
Next
End Sub
Public Sub Main()
Dim uc As New uCalc()
uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", AddressOf DisplayArgs)
uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))")
End Sub
End Module
5 Type: double
3+2i Type: complex
Hello Type: string
true Type: bool
false Type: bool
9 Type: int16 Imports System Imports uCalcSoftware Public Module Program Public Sub DisplayArgs(ByVal cb As uCalc.Callback) For x As Integer = 1 To cb.ArgCount() Console.WriteLine(cb.ArgItem(x).ValueStr() + " Type: " + cb.ArgItem(x).DataType.Name) Next End Sub Public Sub Main() Dim uc As New uCalc() uc.DefineFunction("DisplayArgs(ByHandle Arg As AnyType ...)", AddressOf DisplayArgs) uc.Eval("DisplayArgs(5, 3+2*#i, 'Hello', True, False, Int16(5+4.1))") End Sub End Module
ID: 14
using uCalcSoftware;
var uc = new uCalc();
static void MySum(uCalc.Callback cb) {
var Total = 0.0;
var Expr = cb.ArgExpr(1);
var Start = cb.Arg(2);
var Finish = cb.Arg(3);
var Variable = cb.ArgItem(4);
for (double x = Start; x <= Finish; x++) {
Variable.Value(x);
Total += Expr.Evaluate();
}
cb.Return(Total);
}
uc.DefineVariable("x");
uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum);
Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)"));
385 using uCalcSoftware; var uc = new uCalc(); static void MySum(uCalc.Callback cb) { var Total = 0.0; var Expr = cb.ArgExpr(1); var Start = cb.Arg(2); var Finish = cb.Arg(3); var Variable = cb.ArgItem(4); for (double x = Start; x <= Finish; x++) { Variable.Value(x); Total += Expr.Evaluate(); } cb.Return(Total); } uc.DefineVariable("x"); uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum); Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)"));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
void ucalc_call MySum(uCalcBase::Callback cb) {
auto Total = 0.0;
auto Expr = cb.ArgExpr(1);
auto Start = cb.Arg(2);
auto Finish = cb.Arg(3);
auto Variable = cb.ArgItem(4);
for (double x = Start; x <= Finish; x++) {
Variable.Value(x);
Total += Expr.Evaluate();
}
cb.Return(Total);
}
int main() {
uCalc uc;
uc.DefineVariable("x");
uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum);
cout << uc.Eval("Sum(x ^ 2, 1, 10, x)") << endl;
}
385 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; void ucalc_call MySum(uCalcBase::Callback cb) { auto Total = 0.0; auto Expr = cb.ArgExpr(1); auto Start = cb.Arg(2); auto Finish = cb.Arg(3); auto Variable = cb.ArgItem(4); for (double x = Start; x <= Finish; x++) { Variable.Value(x); Total += Expr.Evaluate(); } cb.Return(Total); } int main() { uCalc uc; uc.DefineVariable("x"); uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", MySum); cout << uc.Eval("Sum(x ^ 2, 1, 10, x)") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub MySum(ByVal cb As uCalc.Callback)
Dim Total = 0.0
Dim Expr = cb.ArgExpr(1)
Dim Start = cb.Arg(2)
Dim Finish = cb.Arg(3)
Dim Variable = cb.ArgItem(4)
For x As Double = Start To Finish
Variable.Value(x)
Total += Expr.Evaluate()
Next
cb.Return(Total)
End Sub
Public Sub Main()
Dim uc As New uCalc()
uc.DefineVariable("x")
uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", AddressOf MySum)
Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)"))
End Sub
End Module
385 Imports System Imports uCalcSoftware Public Module Program Public Sub MySum(ByVal cb As uCalc.Callback) Dim Total = 0.0 Dim Expr = cb.ArgExpr(1) Dim Start = cb.Arg(2) Dim Finish = cb.Arg(3) Dim Variable = cb.ArgItem(4) For x As Double = Start To Finish Variable.Value(x) Total += Expr.Evaluate() Next cb.Return(Total) End Sub Public Sub Main() Dim uc As New uCalc() uc.DefineVariable("x") uc.DefineFunction("Sum(ByExpr Expr, Start, Finish, ByHandle Var)", AddressOf MySum) Console.WriteLine(uc.Eval("Sum(x ^ 2, 1, 10, x)")) End Sub End Module
ID: 86
using uCalcSoftware;
var uc = new uCalc();
static void GetAddressOf(uCalc.Callback cb) {
cb.ReturnPtr(cb.ArgItem(1).ValueAddr());
}
// This example is for sake of illustration
// There is already a built-in AddressOf() function
uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", GetAddressOf);
uc.DefineVariable("MyVariable = 123.456");
uc.DefineVariable("MyStr = 'Hello world!'");
Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyVariable))"));
Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyStr))"));
123.456
Hello world! using uCalcSoftware; var uc = new uCalc(); static void GetAddressOf(uCalc.Callback cb) { cb.ReturnPtr(cb.ArgItem(1).ValueAddr()); } // This example is for sake of illustration // There is already a built-in AddressOf() function uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", GetAddressOf); uc.DefineVariable("MyVariable = 123.456"); uc.DefineVariable("MyStr = 'Hello world!'"); Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyVariable))")); Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyStr))"));
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
void ucalc_call GetAddressOf(uCalcBase::Callback cb) {
cb.ReturnPtr(cb.ArgItem(1).ValueAddr());
}
int main() {
uCalc uc;
// This example is for sake of illustration
// There is already a built-in AddressOf() function
uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", GetAddressOf);
uc.DefineVariable("MyVariable = 123.456");
uc.DefineVariable("MyStr = 'Hello world!'");
cout << uc.EvalStr("ValueAt(GetAddressOf(MyVariable))") << endl;
cout << uc.EvalStr("ValueAt(GetAddressOf(MyStr))") << endl;
}
123.456
Hello world! #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; void ucalc_call GetAddressOf(uCalcBase::Callback cb) { cb.ReturnPtr(cb.ArgItem(1).ValueAddr()); } int main() { uCalc uc; // This example is for sake of illustration // There is already a built-in AddressOf() function uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", GetAddressOf); uc.DefineVariable("MyVariable = 123.456"); uc.DefineVariable("MyStr = 'Hello world!'"); cout << uc.EvalStr("ValueAt(GetAddressOf(MyVariable))") << endl; cout << uc.EvalStr("ValueAt(GetAddressOf(MyStr))") << endl; }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub GetAddressOf(ByVal cb As uCalc.Callback)
cb.ReturnPtr(cb.ArgItem(1).ValueAddr())
End Sub
Public Sub Main()
Dim uc As New uCalc()
'// This example is for sake of illustration
'// There is already a built-in AddressOf() function
uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", AddressOf GetAddressOf)
uc.DefineVariable("MyVariable = 123.456")
uc.DefineVariable("MyStr = 'Hello world!'")
Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyVariable))"))
Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyStr))"))
End Sub
End Module
123.456
Hello world! Imports System Imports uCalcSoftware Public Module Program Public Sub GetAddressOf(ByVal cb As uCalc.Callback) cb.ReturnPtr(cb.ArgItem(1).ValueAddr()) End Sub Public Sub Main() Dim uc As New uCalc() '// This example is for sake of illustration '// There is already a built-in AddressOf() function uc.DefineFunction("GetAddressOf(ByHandle Variable As AnyType) As SameTypeAs:0 Ptr", AddressOf GetAddressOf) uc.DefineVariable("MyVariable = 123.456") uc.DefineVariable("MyStr = 'Hello world!'") Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyVariable))")) Console.WriteLine(uc.EvalStr("ValueAt(GetAddressOf(MyStr))")) End Sub End Module
ID: 1461
using uCalcSoftware;
var uc = new uCalc();
static void EqSolveCb(uCalc.Callback cb) { // Callback based on the Bisection Method
var expr = cb.ArgExpr(1); // ByExpr: Unevaluated Expression object (lazy evaluation)
var a = cb.Arg(2); // Argument 2: Range Minimum
var b = cb.Arg(3); // Argument 3: Range Maximum
var variable = cb.ArgItem(4); // ByHandle: The variable Item object
// Helper to update the variable in the uCalc engine and evaluate the expression
double EvaluateAt(double val) {
variable.Value(val); // Push the new test value to the variable
return expr.Evaluate(); // Evaluate the pre-parsed expression
}
// 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)) (a, b) = (b, a);
var midpoint = 0.0;
var fMidpoint = 0.0;
// Bisection loop
for (int i = 0; i <= 100; i++) {
midpoint = (a + b) / 2;
fMidpoint = EvaluateAt(midpoint);
if (Math.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 (Math.Abs(fMidpoint) > 1e-5) cb.Error.Raise("No solution found in the given range.");
cb.Return(Math.Round(midpoint, 7)); // Return the final solved value
}
// 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
var 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 ---
System.Collections.Generic.List eqList = new() {
"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'
};
foreach(var eq in eqList) {
Console.WriteLine(uc.ExpressionTransformer.Transform(eq)); // Displays transformed expression
Console.WriteLine($"Result: {uc.EvalStr(eq)}"); // Returns result
}
EqSolve(x + 5 - (125), -10000, 10000, x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000, 10000, x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100, x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0, x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000, 10000, x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000, 10000, MyVar)
Result: 8 using uCalcSoftware; var uc = new uCalc(); static void EqSolveCb(uCalc.Callback cb) { // Callback based on the Bisection Method var expr = cb.ArgExpr(1); // ByExpr: Unevaluated Expression object (lazy evaluation) var a = cb.Arg(2); // Argument 2: Range Minimum var b = cb.Arg(3); // Argument 3: Range Maximum var variable = cb.ArgItem(4); // ByHandle: The variable Item object // Helper to update the variable in the uCalc engine and evaluate the expression double EvaluateAt(double val) { variable.Value(val); // Push the new test value to the variable return expr.Evaluate(); // Evaluate the pre-parsed expression } // 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)) (a, b) = (b, a); var midpoint = 0.0; var fMidpoint = 0.0; // Bisection loop for (int i = 0; i <= 100; i++) { midpoint = (a + b) / 2; fMidpoint = EvaluateAt(midpoint); if (Math.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 (Math.Abs(fMidpoint) > 1e-5) cb.Error.Raise("No solution found in the given range."); cb.Return(Math.Round(midpoint, 7)); // Return the final solved value } // 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 var 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 --- System.Collections.Generic.List<string> eqList = new() { "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' }; foreach(var eq in eqList) { Console.WriteLine(uc.ExpressionTransformer.Transform(eq)); // Displays transformed expression Console.WriteLine($"Result: {uc.EvalStr(eq)}"); // Returns result }
#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
}
}
EqSolve(x + 5 - (125), -10000, 10000, x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000, 10000, x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100, x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0, x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000, 10000, x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000, 10000, MyVar)
Result: 8 #include <iostream> #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<string> 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 } }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub EqSolveCb(ByVal cb As uCalc.Callback)REM // Callback based on the Bisection Method
Dim expr = cb.ArgExpr(1) '// ByExpr: Unevaluated Expression object (lazy evaluation)
Dim a = cb.Arg(2) '// Argument 2: Range Minimum
Dim b = cb.Arg(3) '// Argument 3: Range Maximum
Dim variable = cb.ArgItem(4) '// ByHandle: The variable Item object
'// Helper to update the variable in the uCalc engine and evaluate the expression
Dim EvaluateAt = Function (val as Double) As Double
variable.Value(val) '// Push the new test value to the variable
return expr.Evaluate() '// Evaluate the pre-parsed expression
End Function
'// 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) Then Dim temp = a : a = b : b = temp
Dim midpoint = 0.0
Dim fMidpoint = 0.0
'// Bisection loop
For i As Integer = 0 To 100
midpoint = (a + b) / 2
fMidpoint = EvaluateAt(midpoint)
If Math.Abs(fMidpoint) < 1e-7 Then Exit For REM // Stop if close enough to 0
REM// Narrow the bounds (compact logic!)
If fMidpoint < 0 Then a = midpoint Else b = midpoint
Next
If Math.Abs(fMidpoint) > 1e-5 Then cb.Error.Raise("No solution found in the given range.")
cb.Return(Math.Round(midpoint, 7)) '// Return the final solved value
End Sub
Public Sub Main()
Dim uc As New uCalc()
'// 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
Dim 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)", AddressOf EqSolveCb)
'// --- Demo Executions ---
Dim eqList As New List(Of String) From {
"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 Each eq In eqList
Console.WriteLine(uc.ExpressionTransformer.Transform(eq)) '// Displays transformed expression
Console.WriteLine($"Result: {uc.EvalStr(eq)}") '// Returns result
Next
End Sub
End Module
EqSolve(x + 5 - (125), -10000, 10000, x)
Result: 120
EqSolve(x^2 + 5 - (105), -10000, 10000, x)
Result: 10
EqSolve(x^2 + 5 - (105), 0, 100, x)
Result: 10
EqSolve(x^2 + 5 - (105), -100, 0, x)
Result: -10
EqSolve(x^2 + 1000 - (5), -10000, 10000, x)
Result: No solution found in the given range.
EqSolve(40 + MyVar * 6 - (88), -10000, 10000, MyVar)
Result: 8 Imports System Imports uCalcSoftware Public Module Program Public Sub EqSolveCb(ByVal cb As uCalc.Callback)REM // Callback based on the Bisection Method Dim expr = cb.ArgExpr(1) '// ByExpr: Unevaluated Expression object (lazy evaluation) Dim a = cb.Arg(2) '// Argument 2: Range Minimum Dim b = cb.Arg(3) '// Argument 3: Range Maximum Dim variable = cb.ArgItem(4) '// ByHandle: The variable Item object '// Helper to update the variable in the uCalc engine and evaluate the expression Dim EvaluateAt = Function (val as Double) As Double variable.Value(val) '// Push the new test value to the variable return expr.Evaluate() '// Evaluate the pre-parsed expression End Function '// 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) Then Dim temp = a : a = b : b = temp Dim midpoint = 0.0 Dim fMidpoint = 0.0 '// Bisection loop For i As Integer = 0 To 100 midpoint = (a + b) / 2 fMidpoint = EvaluateAt(midpoint) If Math.Abs(fMidpoint) < 1e-7 Then Exit For REM // Stop if close enough to 0 REM// Narrow the bounds (compact logic!) If fMidpoint < 0 Then a = midpoint Else b = midpoint Next If Math.Abs(fMidpoint) > 1e-5 Then cb.Error.Raise("No solution found in the given range.") cb.Return(Math.Round(midpoint, 7)) '// Return the final solved value End Sub Public Sub Main() Dim uc As New uCalc() '// 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 Dim 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)", AddressOf EqSolveCb) '// --- Demo Executions --- Dim eqList As New List(Of String) From { "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 Each eq In eqList Console.WriteLine(uc.ExpressionTransformer.Transform(eq)) '// Displays transformed expression Console.WriteLine($"Result: {uc.EvalStr(eq)}") '// Returns result Next End Sub End Module
This page last modified on: