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 the latest version of uCalc
FMP.
- 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. 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 [now called ucArg in
version 3.0] 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. Note: uCalc() is no longer supported in FMP, but the tip
is still valid for parsing beyond FMP.
- 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 token definitions to a minimum.
Tokens 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).
What’s new in version
3.0
·
Min() and Max() are
very significantly faster than before.
Note: Batch mode evaluation, and uCalc() are no longer
supported in this version. However, the
tip for uCalc() is still applicable beyond FMP.