Reference
Everything on this page is a thing the library does not do, does imperfectly, or does in a way that will surprise you. It is here so you find out now rather than at two in the morning.
Where a limit has a workaround, the workaround is given. Where it does not, that is said plainly.
Extended is 10 bytes on 32-bit Delphi and on FPC for Linux, and 8
bytes - the same as Double - on 64-bit Windows. The parser keeps
intermediates in Extended, so a long chain can end on a different
last bit depending on the target.
Concretely: 0.1 + 0.2 ends in ...3333 on the first pair
and ...3334 on the second. Both are correct roundings of different
intermediate precision. If you need one answer everywhere, round explicitly at
the end.
2 ** 0.5 should equal sqrt(2) to the last bit. Under
Delphi and under FPC on Linux it does. Under FPC on 64-bit Windows it misses by
337 units in the last place, because Power there computes
exp(y × ln x) without the extra precision the other targets have.
Use sqrt for square roots and intpower for whole
exponents, both of which are exact.
Names and string parameters live in a fixed buffer of 4 096 characters. Anything longer is truncated silently - no exception, no warning. In practice a formula never comes close, but a generated one might. The registry also weighs more than it should because of this: roughly 900 KB per parser instance with the full function set registered.
Changing this means moving the registry to dynamic strings and a new serialisation format. It is planned, not done.
| Does not | Consequence |
|---|---|
| Run anywhere but x86-64 | on ARM or 32-bit targets the machine-code stage is skipped; the portable IR is tried next, with the ordinary interpreter as the final fallback. The measured IR figures are in jit/README.md |
| Compile functions that take parameters | mean, poly and friends fall back |
| Key its cache by shape | two formulas differing only in a constant compile twice |
TMathParser. Evaluation is thread-safe once everything is registered. Registration itself is not: adding a function or a variable while another thread is evaluating is undefined. The contract is simple and worth stating - register everything before the first evaluation, then evaluate from as many threads as you like.
TJitParser is different, and the difference matters. The accelerator keeps a cache: the text of the last formula, a list of compiled entries and the counters beside it, all written on the first sight of a formula and none of it under a lock. Two threads meeting a formula the cache has not seen will both compile it and both write the list. One accelerating parser therefore belongs to one thread.
To evaluate in parallel, compile the scripts up front on a single thread
with CompileScript, then execute them. Executing a prepared
TJitScript does not modify it, so one script may run on several
threads at once - but only as far as everything it reaches allows that: the
variables it reads have to be safe to read concurrently, and so does every
function it calls. Both are yours, not the library's.
The addresses are baked in when the script is built: the redirect chain is
resolved once, at compile time. So a thread that needs its own variables
needs its own script, with its own category, compiled separately -
Copy the script, redirect the copy, compile that.
| Limit | Detail |
|---|---|
| Antialiasing | smooth curves use GDI+, which exists only in the Delphi build; FPC draws a plain polyline |
| Report | roots and areas are found numerically on the sampled points, so their accuracy follows the sampling density |
| Polar poles | a curve through infinity is broken rather than joined - correct, but it means one curve may arrive as several pieces |
| Loop budget in the browser | one budget covers a whole sweep, not each point, so an endless loop cannot hold the tab for as many turns as there are points. A formula with an honest loop can spend it partway along, and the remaining points come back as "not a number". The demo says so rather than leaving a silent gap; the plugin has no such limit |
There is no complex arithmetic, no matrices, no units of measurement, and no
symbolic algebra beyond deriv. Adding any of them is possible
through the function registry; none is built in.