Speed
Issues
uCalc Fast Math Parser is designed to run rapidly
as-is. However, an understanding of the
following topics can help you make the right decisions in order to achieve
optimal speeds.
- If speed
is of concern, then use version 2.96 or above instead of any of the
previous versions.
- Use
default numeric and string types.
uCalc supports many data types. However, it is designed to run at
optimal speeds when the default numeric or string types are used. Note that the default numeric type is
not the same for all supported compilers.
Some are configured for double precision, while others are
configured for extended precision.
It is generally better to avoid specifying a numeric type when
defining things, and let uCalc select the appropriate default numeric
type, unless you need the specific properties of a given type. It is possible to optimize uCalc for
data types other than the current defaults. However, details for this are beyond the scope of this
documentation.
- Use
a centralized error handler instead of ucError. In version 2.0, error checking required
a call to ucError after each call to a uCalc routine for which you wanted
to check for an error. This technique
is still supported. However, it
generally takes more lines of code, is less foolproof, and the extra
overhead can slow your program down.
Centralized error handlers,
which are supported in the current version, are recommended for
efficiency.
- ucParse
/ ucEvaluate vs ucEval. When
evaluating the same expression a large number of times in a loop, the
evaluation is much quicker if you use ucParse
prior to the loop, and ucEvaluate within the
loop, instead of using ucEval within the loop.
- Native
callbacks are significantly faster than non-native callbacks. "Built-in" operators and
functions are defined using native callbacks. You can define your own callback routines that are just as
fast. Methods for defining native
callbacks were available since version 2.9. However, it wasn't documented in the uCalc FMP help file until
version 2.96. Furthermore the
actual method was simplified in version 2.96 so that the use of pointers
is not required. Prior to version
2.96 the use of ucParam was discouraged as a leftover from version
2.0. However, ucParam was
re-designed for optimal speed and is now recommended. Using pointers in native callback
routines is more complicated and provides only a relatively small speed
advantage over ucParam.
- Some
self-contained function definitions are slower than others. A self-contained function or operator
(one that can be defined by the end-user) will be slower if the body of
the definition contains a function or operator that is non-native,
recursive, overloaded (except for the last definition), or bootstrapped,
or if it performs implicit data type conversions, or includes a pointer
reference (with ValueAtAddr), or if it contains a routine with an
argument of type AnyType, or if it is explicitly defined using the overhead
directive. The presence of a
routine with extra overhead like this in an expression will slow the
expression down.
- uCalc's
FPU setting should be the same as that of the host program. uCalc lets you have separate FPU settings for uCalc and the host program. ucEvaluate may run a little slower if
they are different, because the setting ends up being switched and
restored with each call to ucEvaluate.
So unless you specifically require the effects of uCalc having a
different FPU setting than the host program, it is best to insure that
they are the same.
- The
^ operator is faster when the right-hand operand is an integer.
- Minimize
the use of expressions that perform automatic conversions. If an expression contains a mix of data
types (such as Single, Double, Long integer, etc), uCalc generally
performs the necessary conversions automatically. However, this may incur a speed
penalty.
- Avoid
expressions that perform generic conversions. As mentioned above, automatic
conversions may incur a speed penalty.
However, there is an even greater penalty if uCalc does not have a
built-in conversion routine for the given types. As of version 2.96, uCalc has automatic converters for
things like Long integer to Double (or Extended), but not for Dword to
Long. If you browse through the
Include file, you will see which data types have automatic conversions
routines between them. If two
types are defined as compatible, but do not have a routine to perform the
conversion, uCalc converts the item to a string first, and then to the
target data type, which is a slow process.
- uCalc
runs faster for some compilers than for others. Version 2.96 largely closes the speed
gap that existed between .NET compilers and non-.NET compilers. One area in which there is a speed
penalty is when ucSetVariableValue is used under .NET in a tight loop that
contains ucEvaluate, whereas in other compilers you can attach a uCalc
variable to a variable in your host program once and for all prior to the
loop. The VB.NET demo shows a
technique using a uc_For loop without the need for ucSetVariableValue as
an alternative for ucEvaluate, for faster speed in .NET. This speed-boosting technique is not
necessary in other compilers. And
even in .NET compilers, the speed advantage of using uc_For may not be consistent. C# lets you attach a uCalc variable to
one in your host C# program if you use the unsafe directive (as
you'll find in the Summation example of the C# demo).
- Pass
a handle to uCalc() instead of an item name. In many cases, the uCalc() function gives you the option of
specifying an item by name, or by handle.
Specifying an item by handle is faster.
- Batch
mode evaluation is not documented in this help file. However, if this is of importance to
you, please ask about it. Speed
gains for batch evaluation may appear dramatic in very specific
circumstances, but the advantage is not consistent overall.
- When
defining multiple versions of a function or operator, the version that is
most likely to appear more often in expressions should usually be defined
last so that these expressions are parsed more rapidly. (This has no effect on evaluation
speed).
- Keep
new pattern definitions to a minimum.
Patterns that are most likely to appear in an expression should be
defined last for faster parsing. (This
has no effect on evaluation speed).
- Syntax
constructs that start with a regular expression may affect the parsing
speed of all expressions. If you
define a syntax construct, when possible the first non-argument part of
the construct should be a name or symbol instead of a regular
expression. (This has no effect on
evaluation speed).